From 30a12a0dee5c61088e8cc18f344dfd6019698241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Sun, 7 Jun 2026 16:14:17 +0200 Subject: [PATCH 1/9] fix(ci): repair URL extraction in link-check workflow Fixes #3. Three buckets of false-positive errors: - grep regex truncated URLs at `)`, mangling Wikipedia disambiguation titles. Allow `)` in URLs and strip only unbalanced trailing `)`. - resolver templates with `{placeholder}` reached lychee verbatim. Filter them out. - `data/package-lock.json` contributed bot-blocked opencollective URLs. Restrict grep to YAML/MD and add opencollective to lychee excludes. Also bump the registry submodule for the Perseus license_url fix, and mirror that URL change in the how-it-works example. Co-Authored-By: Claude Opus 4.7 --- .github/workflows/links.yml | 9 ++++++++- data | 2 +- lychee.toml | 1 + src/content/docs/get-started/how-it-works.md | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml index 5217e88..cec2fad 100644 --- a/.github/workflows/links.yml +++ b/.github/workflows/links.yml @@ -28,7 +28,14 @@ jobs: - name: Collect external URLs from sources run: | mkdir -p lychee - grep -rhoE 'https?://[^"'\''<>) ]+' data/ src/content/docs/ \ + # Allow `)` inside URLs (Wikipedia disambiguation titles), then strip + # a single trailing `)` only when unbalanced (handles markdown + # `[text](url)`). Drop resolver templates containing `{placeholder}`. + # Restrict to YAML/MD so lockfiles inside data/ are not scanned. + grep -rhoE --include='*.yaml' --include='*.yml' --include='*.md' --include='*.mdx' \ + 'https?://[^]["'\''<>[:space:]]+' data/ src/content/docs/ \ + | awk '{ n=gsub(/\(/,"&"); m=gsub(/\)/,"&"); if (m>n) sub(/\)$/,""); print }' \ + | grep -v '[{}]' \ | sed -E 's/[.,;:]+$//' \ | sort -u > lychee/urls.txt echo "Collected $(wc -l < lychee/urls.txt) unique URLs" diff --git a/data b/data index 6d04b70..014bc81 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 6d04b70c61fce0c3402ea2f8eac7a5a9ea886e79 +Subproject commit 014bc81893007baee0f74b0a84b279981b627ec3 diff --git a/lychee.toml b/lychee.toml index d309414..f2f8688 100644 --- a/lychee.toml +++ b/lychee.toml @@ -33,6 +33,7 @@ exclude = [ "^https?://([a-z0-9-]+\\.)*linkedin\\.com", "^https?://([a-z0-9-]+\\.)*twitter\\.com", "^https?://([a-z0-9-]+\\.)*x\\.com", + "^https?://([a-z0-9-]+\\.)*opencollective\\.com", "^https?://localhost(:\\d+)?(/|$)", ] diff --git a/src/content/docs/get-started/how-it-works.md b/src/content/docs/get-started/how-it-works.md index 68d429f..e1ff860 100644 --- a/src/content/docs/get-started/how-it-works.md +++ b/src/content/docs/get-started/how-it-works.md @@ -53,7 +53,7 @@ The identity is the Stephanus reference, not any one Greek text, translation, or "provider": "Perseus Digital Library", "access": "open", "license": "CC-BY-SA-3.0", - "license_url": "https://www.perseus.tufts.edu/hopper/about/copyright", + "license_url": "https://www.perseus.tufts.edu/hopper/opensource", "last_checked": "2026-06-03" } ], From 6dd6e0d351fdff3e65e01ad7c17efb32779fc8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Sun, 7 Jun 2026 16:29:49 +0200 Subject: [PATCH 2/9] chore(deps): bump astro 6.4.4 and migrate to zod 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - npm update: astro 6.4.3 → 6.4.4 (patch) - zod 3.25.76 → 4.4.3 (was already pulled in by astro/starlight as transitive at v4; align top-level so there's one resolved copy) Zod 4 migration in schema + validator: - z.string().url() → z.url() (Iri) - z.ZodIssueCode.custom → 'custom' string literal (superRefine calls) - validate-data reportIssue path type widened to PropertyKey[] to match zod 4's $ZodIssue['path'] GH Actions are already on current majors; no bumps needed. Co-Authored-By: Claude Opus 4.7 --- package-lock.json | 447 +++++++++++++++-------------- package.json | 2 +- scripts/validate-data.ts | 5 +- standard/schema/citation-system.ts | 8 +- standard/schema/common.ts | 2 +- standard/schema/work.ts | 2 +- 6 files changed, 239 insertions(+), 227 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e1994f..1076de6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "starlight-blog": "^0.26.1", "uuid": "^14.0.0", "yaml": "^2.9.0", - "zod": "^3.23.8" + "zod": "^4.4.3" }, "devDependencies": { "@astrojs/check": "^0.9.9", @@ -263,15 +263,6 @@ "zod": "^4.3.6" } }, - "node_modules/@astrojs/rss/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/@astrojs/sitemap": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.3.tgz", @@ -283,15 +274,6 @@ "zod": "^4.3.6" } }, - "node_modules/@astrojs/sitemap/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/@astrojs/starlight": { "version": "0.39.3", "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.39.3.tgz", @@ -453,9 +435,9 @@ "license": "Apache-2.0" }, "node_modules/@clack/core": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.0.tgz", - "integrity": "sha512-7Wctjq6f7c1CPz8sPpkwUnz8yRgVANkpNupb81q432FjcJg4l+Sw7XANdNSdWfAKq0IHI0JTcUeK5dxs/HrGPw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.1.tgz", + "integrity": "sha512-FILJa1gGKEFTGZAJE9RpVhrjKz3c3h4ar60dSv6cGuDqufQ84YEIS3GAGvZiN+H6yaLbbvTFNejjCC4tXpZEuw==", "license": "MIT", "dependencies": { "fast-wrap-ansi": "^0.2.0", @@ -466,12 +448,12 @@ } }, "node_modules/@clack/prompts": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.5.0.tgz", - "integrity": "sha512-wKh+wTjmrUoUdkZg8KpJO5X+p9PWV+KE9mePseq9UYWkukgTKsGS47RRL2HstwVcvDQH+PenrPJWII8+MfiiyA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.5.1.tgz", + "integrity": "sha512-zccHj2z2oCCO4yrDiRSlFOxWerGqRiysP7a5jPK6uoI9URKAquwY42Dd/iUP8JWHxEzdRe4TlbvZCo8z1/mhrw==", "license": "MIT", "dependencies": { - "@clack/core": "1.4.0", + "@clack/core": "1.4.1", "fast-string-width": "^3.0.2", "fast-wrap-ansi": "^0.2.0", "sisteransi": "^1.0.5" @@ -2156,9 +2138,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.0.tgz", - "integrity": "sha512-dnxczajOqt0gesZlN5pGQ1s1imQVrsmCw5G2Ci4oM+0WvNz3pyRnlWrT7McoZIb8VlFwCawdmbWRmxRn7HI+VQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", + "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", "cpu": [ "arm" ], @@ -2169,9 +2151,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.0.tgz", - "integrity": "sha512-Bp3JpGP00Vu3f238ivRrjf7z3xSzVPXqCmaJYA9t2c+c8vKYvOzmXF7LkkeUalTEGd6cZcSWe+PFIP3Vy48fRg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", + "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", "cpu": [ "arm64" ], @@ -2182,9 +2164,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.0.tgz", - "integrity": "sha512-zaYIpr670mUmmZ1tVzUFplbQbG7h3Gugx3L5FoqhsC2m/YnLlR1a7zVLmXNPy+iY1tFPEbNG+HHBXZGyId0G5w==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", + "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", "cpu": [ "arm64" ], @@ -2195,9 +2177,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.0.tgz", - "integrity": "sha512-+P49fvkv2dSoeevUW+lgZ/I2JHSsJCK1Lyjj7Cu6E4UHG4tS9XIefzIjo5qhgELjAclnen1rLzK2PMKJdo+Dyg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", + "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", "cpu": [ "x64" ], @@ -2208,9 +2190,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.0.tgz", - "integrity": "sha512-l3FAAOyKJXH2ea6KNFN+MMgC/rnE94YGLXs2ehYqDcCoHt1DpvgWX75BhUJxN38XojP7Ul+4H8PRn7EdyqSDrw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", + "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", "cpu": [ "arm64" ], @@ -2221,9 +2203,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.0.tgz", - "integrity": "sha512-VokPN3TSctKj65cyCNPaUh4vMFA8awxOot/0sp+4J7ZlNRKQEhXhawqPwajoi8H5ZFt61i0ugZJuTKXBjGJ17Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", + "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", "cpu": [ "x64" ], @@ -2234,9 +2216,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.0.tgz", - "integrity": "sha512-DxH0P3wxm+Yzs/p3zrk9dw1rURu8p0Nv5+MRK/L7OtnLNg5rLZraSBFZ8iUXOd9f2BlhJyEpIZUH/emjq4UJ4g==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", + "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", "cpu": [ "arm" ], @@ -2250,9 +2232,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.0.tgz", - "integrity": "sha512-T6ZvMNe84kAz6TBWHC7hGAoEtzP1LWYw/AqayGWEF6uISt3Abk/st06LqRD9THd7Xz3NxzurUpzAuEAUbZf+nw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", + "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", "cpu": [ "arm" ], @@ -2266,9 +2248,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.0.tgz", - "integrity": "sha512-q/4hzvQkDs8b4jIBab1pnLiiM0ayTZsN2amBFPDzuyZxjEd4wDwx0UJFYM3cOZzSf5Kw8fnWSprJzIBMkcR44Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", + "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", "cpu": [ "arm64" ], @@ -2282,9 +2264,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.0.tgz", - "integrity": "sha512-vvYWX3akdEAY6km+9wAqFDnk6pQsbJKVnj7xawcvs/+fdlYBGp+U+Qq/lLfpIxYIZvZLHMAKD9HLdacSx/r3dw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", + "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", "cpu": [ "arm64" ], @@ -2298,9 +2280,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.0.tgz", - "integrity": "sha512-DePa5cqOxDP/Zp0VOXpeWaGew5iIv5DXp9NYbzkX5PFQyWVX9184WCTh3hvr/7lhXo8ZVlbFLkz8+o/q1dU6gA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", + "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", "cpu": [ "loong64" ], @@ -2314,9 +2296,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.0.tgz", - "integrity": "sha512-LV8aWMB8UChglMCEzs7RkN0GsH29RJaLLqwm9fCIjlqwxQTiWAqNcc7wjBkH31hV0PU/yVxGYvrYsgfea2qw6g==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", + "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", "cpu": [ "loong64" ], @@ -2330,9 +2312,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.0.tgz", - "integrity": "sha512-QoNSnwQtaeNu5grdBbsL0tt1uyl5EnS8DA8Mr3nluMXbhdQNyhN+G4tBax7VCdxLKj8YJ0/4OO9Ho84jMnJtKA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", + "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", "cpu": [ "ppc64" ], @@ -2346,9 +2328,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.0.tgz", - "integrity": "sha512-/zZp5MKapIIApE8trN8qLGNSiRN9TUoaUZ1cmVu4XnVdd5LQLOXTtyi+vtfUbNnT3iyjzpPqYeKXmvJ+gJGYWw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", + "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", "cpu": [ "ppc64" ], @@ -2362,9 +2344,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.0.tgz", - "integrity": "sha512-RbrzcD3aJ1k3UbtMRRBNwojdVVyXjuVAFTfn/xPa6EEl6GE9Sm/akPgFTb9aAC9pMKGJ6CtWxaGrqWcabH+ySg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", + "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", "cpu": [ "riscv64" ], @@ -2378,9 +2360,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.0.tgz", - "integrity": "sha512-ZF+onDsBso8PJf1XaG9lB+O9RnBpKGnY6OrzC4CSHrtC1jb6jWLTKK4bRqdoCXHd22gyr2hiYmEAm8Wns/BOCw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", + "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", "cpu": [ "riscv64" ], @@ -2394,9 +2376,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.0.tgz", - "integrity": "sha512-Atk0aSIk5Zx2Wuh9dgRQgLP0Koc8hOeYpbWryMXyk8G8/HmPkwPPkMqIIDhrXHHYqfUzSJA/I7IWSBv8xSmRBA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", + "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", "cpu": [ "s390x" ], @@ -2410,9 +2392,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.0.tgz", - "integrity": "sha512-0uMOcf3eZ5K+K4cYHkdxShFMPlPXCOdfDFEFn9dNYAEEd2cVvmOfH7zFgRVoDgmtQ1m9k5q7qfrHzyMAubKYUA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", + "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", "cpu": [ "x64" ], @@ -2426,9 +2408,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.0.tgz", - "integrity": "sha512-mvFtE4A/t/7hRJ7X8Ozmu8FsIkAUat2nzl12pgU337BRmq87AQUJztwHz2Zv5/tjo9/C95E66CK03SI/ToEDJw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", + "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", "cpu": [ "x64" ], @@ -2442,9 +2424,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.0.tgz", - "integrity": "sha512-z9b9+aTxvt8n2rNltMPvyaUfB8NJ+CVyOrGK/MdIKHx7B+lXmZpm/XbRsU7Rpf3fRqJ2uS6mBJiJveCtq8LHDg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", + "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", "cpu": [ "x64" ], @@ -2455,9 +2437,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.0.tgz", - "integrity": "sha512-jXaXFqKMehsOc+g8R6oo33RRC6w07G9jDBxAE5eAKX7mOcCbZloYIPNhfG9Wl+P9O9IWHFO4OJgPi1Ml2qkt7w==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", + "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", "cpu": [ "arm64" ], @@ -2468,9 +2450,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.0.tgz", - "integrity": "sha512-OXNWVFocS2IA4+QplhTZZ2a+8hPZR7T8KuozsNmJKK8y7cp83StHvGksfHzPG3wczWTczyWHVQuqeiTUbjiyBg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", + "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", "cpu": [ "arm64" ], @@ -2481,9 +2463,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.0.tgz", - "integrity": "sha512-AlAbNtBO637LxSldqV43z0FfXoGfl2TW1DgAg/bs7aQswFbDewz2SJm3BUhiGfbOVtW571xbc9p+REdxhyN/Eg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", + "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", "cpu": [ "ia32" ], @@ -2494,9 +2476,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.0.tgz", - "integrity": "sha512-QRSrQXyJ1M4tjNXdR0/G/IgV6lzfQQJYBjlWIEYkY2Xs86DRl/iEpQ4blMDjJxSl7n19eDKKXMg0AmuBVYy8pQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", + "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", "cpu": [ "x64" ], @@ -2507,9 +2489,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.0.tgz", - "integrity": "sha512-tkuFxhvKO/HlGd0VsINF6vHSYH8AF8W0TcNxKDK6JZmrehngFj78pToc8iemtnvwilDjs2G/qSzYFhe9U8q+fw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", "cpu": [ "x64" ], @@ -2527,13 +2509,13 @@ "license": "MIT" }, "node_modules/@shikijs/core": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.1.0.tgz", - "integrity": "sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.2.0.tgz", + "integrity": "sha512-Hc87Ab1Ld/vEbZRCbwx344I5v+4RU8CVToUTRkqXL1+TjbuOp9U5Xa0M23V4GEWHxVn+yO5otb+HkQVm3ptWQQ==", "license": "MIT", "dependencies": { - "@shikijs/primitive": "4.1.0", - "@shikijs/types": "4.1.0", + "@shikijs/primitive": "4.2.0", + "@shikijs/types": "4.2.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" @@ -2543,12 +2525,12 @@ } }, "node_modules/@shikijs/engine-javascript": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.1.0.tgz", - "integrity": "sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.2.0.tgz", + "integrity": "sha512-fjETeq1k5ffyXqRgS6+3hpvqseLalp1kjNfRbXpUgWR8FpZ1CmQfiNHovc5lncYjt/Vg5JK/WJEmLahjwMa0og==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.1.0", + "@shikijs/types": "4.2.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" }, @@ -2557,12 +2539,12 @@ } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.1.0.tgz", - "integrity": "sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.2.0.tgz", + "integrity": "sha512-hTorK1dffPkpbMUk6Z+828PgRo7d07HbnizoP0hNPFjhxMHctj0Px/qoHeGMYafc6ju+u9iMldN4JbVzNQM++g==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.1.0", + "@shikijs/types": "4.2.0", "@shikijs/vscode-textmate": "^10.0.2" }, "engines": { @@ -2570,24 +2552,24 @@ } }, "node_modules/@shikijs/langs": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.1.0.tgz", - "integrity": "sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.2.0.tgz", + "integrity": "sha512-bwrVRlJ0wUhZxAbVdvBbv2TTC9yLsh4C/IO5Ofz0T8MQntgDvyVnkbjw9vi50r1kx7RCIJdnJnjZAwmAsXFLZQ==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.1.0" + "@shikijs/types": "4.2.0" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/primitive": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.1.0.tgz", - "integrity": "sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.2.0.tgz", + "integrity": "sha512-NOq+DtUkVBJtZMVXL5A0vI0Xk8nvDYaXetFHSJFlOqjDZIVhIPRYFdGkSoElDqNuegikcc3A76SNUa8dTqtAYA==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.1.0", + "@shikijs/types": "4.2.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" }, @@ -2596,21 +2578,21 @@ } }, "node_modules/@shikijs/themes": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.1.0.tgz", - "integrity": "sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.2.0.tgz", + "integrity": "sha512-RX8IHYeLv8Cu2W6ruc3RxUqWn0IYCqSrMBzi/uRGAmfyDNOnNO5BF/Px7o97n4XTpmFTo5GbRaazuOWj+2ak2w==", "license": "MIT", "dependencies": { - "@shikijs/types": "4.1.0" + "@shikijs/types": "4.2.0" }, "engines": { "node": ">=20" } }, "node_modules/@shikijs/types": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.1.0.tgz", - "integrity": "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.2.0.tgz", + "integrity": "sha512-VT/MKtlpOhEPZloSH3Pb9WCZEBDoQVMa9jedp5UAwmJOar1DVc9DRODAxmYPW9M93IK4ryuqRejFfmlvlVDemw==", "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", @@ -2990,9 +2972,9 @@ } }, "node_modules/@types/mdx": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.13.tgz", - "integrity": "sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.14.tgz", + "integrity": "sha512-T48PeuJtvLosNTPVhfnIp3i/n3a4g4Bad7YCq5k64D4u7NwDrAotikQ+5+sjtUvBmxCMlbo3dVL+C2dP0rWHzg==", "license": "MIT" }, "node_modules/@types/micromatch": { @@ -3021,9 +3003,9 @@ } }, "node_modules/@types/node": { - "version": "25.9.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz", - "integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==", + "version": "25.9.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.2.tgz", + "integrity": "sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==", "license": "MIT", "dependencies": { "undici-types": ">=7.24.0 <7.24.7" @@ -3347,9 +3329,9 @@ } }, "node_modules/astro": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/astro/-/astro-6.4.3.tgz", - "integrity": "sha512-heArIk8zLcxuoj1WgBH2zGdAD8zKSU1mEcBvS6hYMEHRPlbtvB+4Y8ri9Z27hzeryvGaFgrH32zjghEfV2y07g==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/astro/-/astro-6.4.4.tgz", + "integrity": "sha512-hVe8tq3lqt/Dr0UyB//yUmQSlHMTU8scTiF/vQddQVahLE4TTaSdH5H0nb7OvRcwo0UmlAO8DWYar4jNaS7H+A==", "license": "MIT", "dependencies": { "@astrojs/compiler": "^4.0.0", @@ -3503,15 +3485,6 @@ "integrity": "sha512-eouss7G8ygdZqHuke033VMcVw5HTZUu+PXd/h06DGDUg/jt5btPYPqh66ENWw/mU78rBrf/oeC4oqoBwMtDMNA==", "license": "MIT" }, - "node_modules/astro/node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4869,9 +4842,9 @@ } }, "node_modules/dompurify": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz", - "integrity": "sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==", + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.8.tgz", + "integrity": "sha512-yb1cEmaOum7wFvOCSQxyfgVlv5D47Rc30iZWoMpbDIWTnJ6grDDQyu2KFJzB2k7u0pMuJcQ1zphH//fFnw2tjQ==", "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" @@ -6347,9 +6320,9 @@ } }, "node_modules/i18next": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.0.tgz", - "integrity": "sha512-gHSgGpUXVmuqE2El1W61DmxeyeTlFfZgdJRWMo9jScAn5pu7TuTuiccb1zh3E2J9hEBVGJ23+96x0ieBhfuIHA==", + "version": "26.3.1", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.3.1.tgz", + "integrity": "sha512-txQqd5EULsqEh9OJqRH15aCaOuy/nLJyhw5EHCSKLKJE1aBbb3Zve2+uQIxgWhPm1QqUQoWyQBm2kfmmIrzkcQ==", "funding": [ { "type": "individual", @@ -8353,14 +8326,17 @@ } }, "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.2.tgz", + "integrity": "sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==", "funding": [ "https://github.com/sponsors/sxzz", "https://opencollective.com/debug" ], - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } }, "node_modules/ofetch": { "version": "1.5.1", @@ -9302,9 +9278,9 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "4.61.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.0.tgz", - "integrity": "sha512-T9mWdbWfQtp0B5lv/HX+wrhYsmXRlcWnXXmJbXqKJhlRaoS6KMhq0gpyzW4UJfclcxrEdLnTgjT2NjruLONu0g==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", + "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", "license": "MIT", "dependencies": { "@types/estree": "1.0.9" @@ -9317,31 +9293,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.61.0", - "@rollup/rollup-android-arm64": "4.61.0", - "@rollup/rollup-darwin-arm64": "4.61.0", - "@rollup/rollup-darwin-x64": "4.61.0", - "@rollup/rollup-freebsd-arm64": "4.61.0", - "@rollup/rollup-freebsd-x64": "4.61.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.61.0", - "@rollup/rollup-linux-arm-musleabihf": "4.61.0", - "@rollup/rollup-linux-arm64-gnu": "4.61.0", - "@rollup/rollup-linux-arm64-musl": "4.61.0", - "@rollup/rollup-linux-loong64-gnu": "4.61.0", - "@rollup/rollup-linux-loong64-musl": "4.61.0", - "@rollup/rollup-linux-ppc64-gnu": "4.61.0", - "@rollup/rollup-linux-ppc64-musl": "4.61.0", - "@rollup/rollup-linux-riscv64-gnu": "4.61.0", - "@rollup/rollup-linux-riscv64-musl": "4.61.0", - "@rollup/rollup-linux-s390x-gnu": "4.61.0", - "@rollup/rollup-linux-x64-gnu": "4.61.0", - "@rollup/rollup-linux-x64-musl": "4.61.0", - "@rollup/rollup-openbsd-x64": "4.61.0", - "@rollup/rollup-openharmony-arm64": "4.61.0", - "@rollup/rollup-win32-arm64-msvc": "4.61.0", - "@rollup/rollup-win32-ia32-msvc": "4.61.0", - "@rollup/rollup-win32-x64-gnu": "4.61.0", - "@rollup/rollup-win32-x64-msvc": "4.61.0", + "@rollup/rollup-android-arm-eabi": "4.61.1", + "@rollup/rollup-android-arm64": "4.61.1", + "@rollup/rollup-darwin-arm64": "4.61.1", + "@rollup/rollup-darwin-x64": "4.61.1", + "@rollup/rollup-freebsd-arm64": "4.61.1", + "@rollup/rollup-freebsd-x64": "4.61.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", + "@rollup/rollup-linux-arm-musleabihf": "4.61.1", + "@rollup/rollup-linux-arm64-gnu": "4.61.1", + "@rollup/rollup-linux-arm64-musl": "4.61.1", + "@rollup/rollup-linux-loong64-gnu": "4.61.1", + "@rollup/rollup-linux-loong64-musl": "4.61.1", + "@rollup/rollup-linux-ppc64-gnu": "4.61.1", + "@rollup/rollup-linux-ppc64-musl": "4.61.1", + "@rollup/rollup-linux-riscv64-gnu": "4.61.1", + "@rollup/rollup-linux-riscv64-musl": "4.61.1", + "@rollup/rollup-linux-s390x-gnu": "4.61.1", + "@rollup/rollup-linux-x64-gnu": "4.61.1", + "@rollup/rollup-linux-x64-musl": "4.61.1", + "@rollup/rollup-openbsd-x64": "4.61.1", + "@rollup/rollup-openharmony-arm64": "4.61.1", + "@rollup/rollup-win32-arm64-msvc": "4.61.1", + "@rollup/rollup-win32-ia32-msvc": "4.61.1", + "@rollup/rollup-win32-x64-gnu": "4.61.1", + "@rollup/rollup-win32-x64-msvc": "4.61.1", "fsevents": "~2.3.2" } }, @@ -9396,9 +9372,9 @@ } }, "node_modules/semver": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", - "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.2.tgz", + "integrity": "sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -9475,17 +9451,17 @@ } }, "node_modules/shiki": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.1.0.tgz", - "integrity": "sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.2.0.tgz", + "integrity": "sha512-hjNax6o/ylDy9lefQEaSDtzaT3iVNtZ3WmpQnbuQNoG4xvnSKf2kSKbihZVO4JRG1TTMejs7CmNRYlWgAL66pQ==", "license": "MIT", "dependencies": { - "@shikijs/core": "4.1.0", - "@shikijs/engine-javascript": "4.1.0", - "@shikijs/engine-oniguruma": "4.1.0", - "@shikijs/langs": "4.1.0", - "@shikijs/themes": "4.1.0", - "@shikijs/types": "4.1.0", + "@shikijs/core": "4.2.0", + "@shikijs/engine-javascript": "4.2.0", + "@shikijs/engine-oniguruma": "4.2.0", + "@shikijs/langs": "4.2.0", + "@shikijs/themes": "4.2.0", + "@shikijs/types": "4.2.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" }, @@ -9532,18 +9508,18 @@ } }, "node_modules/sitemap/node_modules/@types/node": { - "version": "24.12.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", - "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "version": "24.13.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.1.tgz", + "integrity": "sha512-RSpUJGmvsJ1ZeBehQZFhIdpsz+bIpES0nIQXko4Ybq+N+kX6XvOq3Jo+iJ82FWLdblFq85AsMikd3m35jgezYg==", "license": "MIT", "dependencies": { - "undici-types": "~7.16.0" + "undici-types": "~7.18.0" } }, "node_modules/sitemap/node_modules/undici-types": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", - "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", "license": "MIT" }, "node_modules/slice-ansi": { @@ -10017,9 +9993,9 @@ "license": "MIT" }, "node_modules/tinyclip": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.13.tgz", - "integrity": "sha512-8OqlXQ35euK9+e7L68u8UwcODxkHoIkjbGsgXuARKNyQ5G6xt8nw1YPeMbxMLgCPFkToU+UEK5j05t2t8edKpQ==", + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.14.tgz", + "integrity": "sha512-F1oWdz8tjT17qe1d5JgDK6z03WGOhYYAN0lK3/D/fzNiy93xswLLEw7pk+3g05onhAy6Bsc6PLNUGhdgVjemMQ==", "license": "MIT", "engines": { "node": "^16.14.0 || >= 17.3.0" @@ -11280,6 +11256,13 @@ "vscode-uri": "^3.1.0" } }, + "node_modules/vscode-css-languageservice/node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true, + "license": "MIT" + }, "node_modules/vscode-html-languageservice": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/vscode-html-languageservice/-/vscode-html-languageservice-5.6.2.tgz", @@ -11311,9 +11294,9 @@ } }, "node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.0.tgz", + "integrity": "sha512-+VvMmQPJhtvJ+8O+zu2JKIRiLxXF8NW7krWgyMGeOHrp4Cn23T5hc0v2LknNeopDOB70wghHAds7mKtcZ0I4Sg==", "dev": true, "license": "MIT", "engines": { @@ -11334,14 +11317,14 @@ } }, "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.0.tgz", + "integrity": "sha512-Zdz+kJ12Iz6tc11xfZyEo501bBATHXrCjmMfnaR3pMnf1CoqZBKIynba3P+/bi9VEdrMbNtAVKYpKhbODvqy+Q==", "dev": true, "license": "MIT", "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" + "vscode-jsonrpc": "9.0.0", + "vscode-languageserver-types": "3.18.0" } }, "node_modules/vscode-languageserver-textdocument": { @@ -11352,6 +11335,34 @@ "license": "MIT" }, "node_modules/vscode-languageserver-types": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.0.tgz", + "integrity": "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-languageserver/node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver/node_modules/vscode-languageserver-types": { "version": "3.17.5", "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", @@ -11633,9 +11644,9 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index 9c977e8..c4a40ba 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "starlight-blog": "^0.26.1", "uuid": "^14.0.0", "yaml": "^2.9.0", - "zod": "^3.23.8" + "zod": "^4.4.3" }, "devDependencies": { "@astrojs/check": "^0.9.9", diff --git a/scripts/validate-data.ts b/scripts/validate-data.ts index fa9ed91..956656f 100644 --- a/scripts/validate-data.ts +++ b/scripts/validate-data.ts @@ -22,11 +22,12 @@ let checked = 0; function reportIssue( label: string, - issues: { path: (string | number)[]; message: string }[], + issues: readonly { path: readonly PropertyKey[]; message: string }[], ): void { console.error(`✗ ${label}:`); for (const issue of issues) { - console.error(` ${issue.path.join('.') || '(root)'}: ${issue.message}`); + const path = issue.path.map((p) => String(p)).join('.'); + console.error(` ${path || '(root)'}: ${issue.message}`); } failed++; } diff --git a/standard/schema/citation-system.ts b/standard/schema/citation-system.ts index 805b70e..1dcfad0 100644 --- a/standard/schema/citation-system.ts +++ b/standard/schema/citation-system.ts @@ -17,7 +17,7 @@ export const CitationSystemBase = AdminMetadata.extend({ export const CitationSystem = CitationSystemBase.superRefine((s, ctx) => { if (s.id !== `https://textrefs.org/id/system/${s.key}`) { ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: 'custom', message: 'id MUST be https://textrefs.org/id/system/{key}', path: ['id'], }); @@ -27,7 +27,7 @@ export const CitationSystem = CitationSystemBase.superRefine((s, ctx) => { re = new RegExp(s.locator_regex); } catch { ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: 'custom', message: 'locator_regex is not a valid ECMAScript regex', path: ['locator_regex'], }); @@ -36,7 +36,7 @@ export const CitationSystem = CitationSystemBase.superRefine((s, ctx) => { s.examples.valid.forEach((v, i) => { if (!re.test(v)) ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: 'custom', message: `examples.valid[${i}] does not match locator_regex`, path: ['examples', 'valid', i], }); @@ -44,7 +44,7 @@ export const CitationSystem = CitationSystemBase.superRefine((s, ctx) => { s.examples.invalid.forEach((v, i) => { if (re.test(v)) ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: 'custom', message: `examples.invalid[${i}] must NOT match locator_regex`, path: ['examples', 'invalid', i], }); diff --git a/standard/schema/common.ts b/standard/schema/common.ts index 6eed376..fa06fd6 100644 --- a/standard/schema/common.ts +++ b/standard/schema/common.ts @@ -12,7 +12,7 @@ export const IsoDate = z .string() .regex(/^\d{4}-\d{2}-\d{2}$/, 'must be YYYY-MM-DD'); -export const Iri = z.string().url(); +export const Iri = z.url(); export const AdminMetadata = z.object({ status: Status, diff --git a/standard/schema/work.ts b/standard/schema/work.ts index 51dfb89..aa643bf 100644 --- a/standard/schema/work.ts +++ b/standard/schema/work.ts @@ -26,7 +26,7 @@ export const WorkBase = AdminMetadata.extend({ export const Work = WorkBase.superRefine((w, ctx) => { if (w.id !== `https://textrefs.org/id/work/${w.key}`) { ctx.addIssue({ - code: z.ZodIssueCode.custom, + code: 'custom', message: 'id MUST be https://textrefs.org/id/work/{key}', path: ['id'], }); From 74bce51dd3c00225b5057a50c8e58ffebc3ffd2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Tue, 9 Jun 2026 18:51:48 +0200 Subject: [PATCH 3/9] docs(association): sync statutes board size and review tracks with dossier Vorstand minimum reduced from three to two persons (Statuten Art. 11) in DE and EN; align contributing guides to frame all three review tracks (technical, expert, board reservation) as first-class, matching the governance regulation. Co-Authored-By: Claude Opus 4.7 --- CONTRIBUTING.md | 5 ++--- src/content/docs/association/board.md | 2 +- src/content/docs/association/statutes.md | 2 +- src/content/docs/community/contributing.md | 5 ++--- src/content/docs/de/association/statutes.md | 2 +- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a34c876..2357b80 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,12 +26,11 @@ A contribution does not create a claim to acceptance, prioritization, publicatio ## Review tracks -Changes are routed to one of two tracks: +Changes are routed to one of three tracks: - **Technical review** — typos, formatting, broken links, minor metadata, `last_checked` updates, uncontested aliases, build / tooling fixes. Needs automated validation and one technical reviewer. - **Expert review** — new works, new citation systems, new corpora, contested mappings, changes to deterministic ID inputs, status changes (`active` / `deprecated` / `withdrawn` / `blocked`). Needs technical validation, a documented rationale with sources, and at least one expert reviewer. - -The Board reserves decisions on legal or policy-sensitive matters (takedowns, blocking, licence policy). +- **Board reservation** — takedowns, blocking, licence policy, and other legal or policy-sensitive matters. Decided by the Association Board. ```mermaid flowchart TD diff --git a/src/content/docs/association/board.md b/src/content/docs/association/board.md index 286be65..6ba4504 100644 --- a/src/content/docs/association/board.md +++ b/src/content/docs/association/board.md @@ -5,7 +5,7 @@ sidebar: order: 6 --- -The Board is the association's executive organ. Per the [statutes](/association/statutes/#art-11-board), the Board consists of at least three persons serving two-year terms on a volunteer basis ([Art. 15](/association/statutes/#art-15-volunteer-service-expenses-and-compensation)). +The Board is the association's executive organ. Per the [statutes](/association/statutes/#art-11-board), the Board consists of at least two persons serving two-year terms on a volunteer basis ([Art. 15](/association/statutes/#art-15-volunteer-service-expenses-and-compensation)). ## Current members diff --git a/src/content/docs/association/statutes.md b/src/content/docs/association/statutes.md index e33a9a2..8a91844 100644 --- a/src/content/docs/association/statutes.md +++ b/src/content/docs/association/statutes.md @@ -107,7 +107,7 @@ In the event of a tied vote on substantive matters, the President decides with t ## Art. 11 Board -The Board consists of at least three persons. +The Board consists of at least two persons. The term of office is two years. Re-election is possible. diff --git a/src/content/docs/community/contributing.md b/src/content/docs/community/contributing.md index 26ca6c2..8679cb4 100644 --- a/src/content/docs/community/contributing.md +++ b/src/content/docs/community/contributing.md @@ -31,12 +31,11 @@ A contribution does not create a claim to acceptance, prioritization, publicatio ## Review tracks -Changes are routed to one of two tracks: +Changes are routed to one of three tracks: - **Technical review** — typos, formatting, broken links, minor metadata, `last_checked` updates, uncontested aliases, build / tooling fixes. Needs automated validation and one technical reviewer. - **Expert review** — new works, new citation systems, new corpora, contested mappings, changes to deterministic ID inputs, status changes (`active` / `deprecated` / `withdrawn` / `blocked`). Needs technical validation, a documented rationale with sources, and at least one expert reviewer. - -The Board reserves decisions on legal or policy-sensitive matters (takedowns, blocking, licence policy). +- **Board reservation** — takedowns, blocking, licence policy, and other legal or policy-sensitive matters. Decided by the Association Board. ```mermaid flowchart TD diff --git a/src/content/docs/de/association/statutes.md b/src/content/docs/de/association/statutes.md index a7ab3a7..2429399 100644 --- a/src/content/docs/de/association/statutes.md +++ b/src/content/docs/de/association/statutes.md @@ -107,7 +107,7 @@ Bei Stimmengleichheit entscheidet bei Sachgeschäften die Präsidentin oder der ## Art. 11 Vorstand -Der Vorstand besteht aus mindestens drei Personen. +Der Vorstand besteht aus mindestens zwei Personen. Die Amtsdauer beträgt zwei Jahre. Wiederwahl ist möglich. From 6b0f0e8bea6a3c8fbb4066351f170b6b7e3e2dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Tue, 9 Jun 2026 22:53:07 +0200 Subject: [PATCH 4/9] docs(spec): tighten dereferenceable-location guidance to should (#7) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §1 previously said a conforming registry MAY record dereferenceable locations. A bare identifier with no resolution path is of limited practical use, so tighten to SHOULD to nudge implementers toward providing a resolvable URL per reference. Closes #7. Co-Authored-By: Claude Opus 4.7 --- src/content/docs/standard/specification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/standard/specification.md b/src/content/docs/standard/specification.md index bf6d03f..25d824e 100644 --- a/src/content/docs/standard/specification.md +++ b/src/content/docs/standard/specification.md @@ -14,7 +14,7 @@ sidebar: TextRefs defines a minimal registry standard for stable, machine-addressable references to texts. -A conforming TextRefs registry MUST provide persistent identifiers for canonical references and MUST describe the citation systems by which those references are formed. It MAY record dereferenceable locations for those references and curated mappings to external identifiers or other references. +A conforming TextRefs registry MUST provide persistent identifiers for canonical references and MUST describe the citation systems by which those references are formed. It SHOULD record dereferenceable locations for those references and MAY record curated mappings to external identifiers or other references. The standard is deliberately small. Its centre is a single idea: **a reference is an abstract identity, separate from any location, edition, or translation where the referenced text can be read.** From da48c31d08dacf091e858155edfa5fa3e2d7b47a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Tue, 9 Jun 2026 23:01:06 +0200 Subject: [PATCH 5/9] =?UTF-8?q?docs(spec):=20self-contained=20=C2=A713=20e?= =?UTF-8?q?xample=20with=20@context=20(#8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace §13's compound JSON-shaped wrapper with a single JSON-LD document under @context + @graph. Each record carries full id, type, and administrative metadata so a reader can copy the example out and validate it directly against the published context and Zod schemas. The CanonicalReference id is the deterministic UUID v5 produced by the seed for `new-testament / bible-book-chapter-verse / John.3.16 / 1.0.0`, verified locally against standard/schema/. Closes #8. Co-Authored-By: Claude Opus 4.7 --- src/content/docs/standard/specification.md | 82 +++++++++++++++------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/src/content/docs/standard/specification.md b/src/content/docs/standard/specification.md index 25d824e..146b54f 100644 --- a/src/content/docs/standard/specification.md +++ b/src/content/docs/standard/specification.md @@ -308,32 +308,62 @@ This is the case that motivates separating identity from location. The New Testa ```json { - "work": { - "key": "new-testament", - "type": "Work", - "preferred_label": "New Testament" - }, - "citation_system": { - "key": "bible-book-chapter-verse", - "type": "CitationSystem", - "locator_regex": "^(?[A-Za-z][A-Za-z0-9_]*)\\.(?[1-9][0-9]*)\\.(?[1-9][0-9]*)$" - }, - "canonical_reference": { - "type": "CanonicalReference", - "work_key": "new-testament", - "citation_system_key": "bible-book-chapter-verse", - "locator": "John.3.16", - "resolver_targets": [ - { - "url": "https://www.stepbible.org/?q=version=SBLG|reference=John.3.16", - "language": "grc", - "edition": "SBL Greek New Testament", - "provider": "STEP Bible", - "access": "open", - "license": "CC-BY-4.0" - } - ] - } + "@context": "https://textrefs.org/contexts/v1.jsonld", + "@graph": [ + { + "id": "https://textrefs.org/id/work/new-testament", + "key": "new-testament", + "type": "Work", + "preferred_label": "New Testament", + "status": "active", + "created": "2026-05-31", + "modified": "2026-05-31" + }, + { + "id": "https://textrefs.org/id/system/bible-book-chapter-verse", + "key": "bible-book-chapter-verse", + "type": "CitationSystem", + "preferred_label": "Bible book-chapter-verse (OSIS-style)", + "normalization_version": "1.0.0", + "locator_regex": "^(?[A-Za-z][A-Za-z0-9_]*)\\.(?[1-9][0-9]*)\\.(?[1-9][0-9]*)$", + "examples": { + "valid": ["Genesis.1.1", "Psalms.23.1", "Matthew.5.3"], + "invalid": ["Genesis.0.1", "Genesis.1", "1.1.1", "Genesis 1:1"] + }, + "status": "active", + "created": "2026-05-31", + "modified": "2026-05-31" + }, + { + "id": "https://textrefs.org/id/ref/59a2d83f-6aff-5fbf-b8f7-b243c3ed0594", + "type": "CanonicalReference", + "work_key": "new-testament", + "citation_system_key": "bible-book-chapter-verse", + "locator": "John.3.16", + "normalization_version": "1.0.0", + "resolver_targets": [ + { + "url": "https://www.stepbible.org/?q=version=SBLG|reference=John.3.16", + "language": "grc-Grek", + "edition": "SBL Greek New Testament", + "provider": "STEP Bible", + "access": "open", + "license": "CC-BY-4.0" + }, + { + "url": "https://www.biblegateway.com/passage/?search=John%203%3A16&version=KJV", + "language": "en", + "edition": "King James Version", + "provider": "Bible Gateway", + "access": "open", + "license": "CC0-1.0" + } + ], + "status": "active", + "created": "2026-05-31", + "modified": "2026-05-31" + } + ] } ``` From 56eb06455e15da6ef66489fa31c8a16f8ef03b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Tue, 9 Jun 2026 23:13:06 +0200 Subject: [PATCH 6/9] chore(data): bump submodule with second resolvers on single-resolver works Co-Authored-By: Claude Opus 4.7 --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index 014bc81..5dc79a3 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 014bc81893007baee0f74b0a84b279981b627ec3 +Subproject commit 5dc79a3ffa09e9eaacd30c62ed974e91fa5570a2 From e9b09d4a28957e08fd4874d19ce2550abff50641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Tue, 9 Jun 2026 23:29:29 +0200 Subject: [PATCH 7/9] feat(spec)!: replace target_kind with dcterms:conformsTo (#6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit target_kind was an OPTIONAL human-readable scheme hint with no normative weight; maintaining Appendix B's enumerated label list was upkeep without payoff. Replace it with optional target.conforms_to — an IRI (or array of IRIs) typed as dcterms:conformsTo in the v1 JSON-LD context — mirroring Linked Art's conforms_to pattern. Spec, Appendix B, JSON-LD context, Zod schema, compile pipeline, in-tree fixture, registry detail pages, and get-started prose all migrated. The Astro mapping/work pages drop the scheme-label badge: the identifier IRI is authoritative and self-describing. The data/ submodule pointer moves to the matching textrefs/registry commit (target_kind→conforms_to in every data/works/*.yaml). See decisions/ADR-0001 for the rationale and alternatives considered. BREAKING CHANGE: target.target_kind is removed; downstream consumers that read it MUST migrate to target.conforms_to. Acceptable pre-v1.0.0. Closes #6. Co-Authored-By: Claude Opus 4.7 --- data | 2 +- ...R-0001-conforms-to-replaces-target-kind.md | 57 +++++++++++++++++++ public/contexts/v1.jsonld | 5 +- scripts/compile.ts | 8 +-- src/content/docs/get-started/authoring.md | 2 +- src/content/docs/get-started/how-it-works.md | 4 +- .../mappings-and-resolver-targets.md | 4 +- .../docs/standard/identifier-syntax.md | 2 +- src/content/docs/standard/json-ld.md | 4 +- src/content/docs/standard/specification.md | 32 +++++------ src/lib/registry.fixture.ts | 1 - src/pages/id/mapping/[uuid]/index.astro | 5 -- src/pages/id/work/[key]/index.astro | 3 - standard/schema/mapping-assertion.ts | 2 +- 14 files changed, 91 insertions(+), 40 deletions(-) create mode 100644 decisions/ADR-0001-conforms-to-replaces-target-kind.md diff --git a/data b/data index 5dc79a3..be413a0 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 5dc79a3ffa09e9eaacd30c62ed974e91fa5570a2 +Subproject commit be413a092bd71b36fecc04a91ac3c0b052f9c097 diff --git a/decisions/ADR-0001-conforms-to-replaces-target-kind.md b/decisions/ADR-0001-conforms-to-replaces-target-kind.md new file mode 100644 index 0000000..528bfc7 --- /dev/null +++ b/decisions/ADR-0001-conforms-to-replaces-target-kind.md @@ -0,0 +1,57 @@ +# ADR-0001: Replace `target_kind` with `dcterms:conformsTo` + +- **Status:** Proposed +- **Date:** 2026-06-09 +- **Deciders:** @maehr +- **Tags:** spec + +## Context and problem statement + +`MappingAssertion.target.target_kind` was introduced as an OPTIONAL human-readable scheme hint (`"cts"`, `"wikidata"`, `"doi"`, …). The spec already says validators MUST NOT key behaviour off it and the IRI in `identifier` is authoritative. Issue [#6](https://github.com/textrefs/textrefs.org/issues/6) observes that a field with no normative weight, accompanied by Appendix B's enumerated list of "known" scheme labels, is upkeep without payoff: every new scheme means another table row to police. + +Linked Art's [digital integration model](https://linked.art/model/digital/) handles the same problem with `conforms_to` pointing at the relevant specification (e.g. the IIIF profile URI), letting the IRI carry the conformance claim without a curated label registry. + +## Decision drivers + +- The field is already non-normative; the IRI is authoritative. +- Appendix B's label column would otherwise grow indefinitely. +- Pre-v1.0.0 — breaking field renames are still acceptable. +- Want to align with established Linked Data practice rather than invent a TextRefs-specific convention. + +## Considered options + +1. **Replace `target_kind` with `conforms_to`** — drop the field, introduce an optional `target.conforms_to` typed as `dcterms:conformsTo` in the JSON-LD context, accepting an IRI or array of IRIs. +2. **Deprecate `target_kind`, keep accepting it** — add `conforms_to` alongside, mark `target_kind` deprecated. Smoother for downstream consumers; carries the dead field into v1. +3. **Leave `target_kind` as-is** — no change. Fails to address the upkeep concern that prompted the issue. + +## Decision + +We choose **Option 1**. The replacement happens before v1.0.0 freezes the schema, so a clean break is preferable to carrying a deprecated field into the stable surface. `target.conforms_to` is OPTIONAL; the registry will not synthesise values where none are known. Multiple IRIs are allowed via array form so a target can claim conformance to several specifications. + +In the JSON-LD context, `conforms_to` maps to `dcterms:conformsTo` with `@type: @id` so the value is treated as an IRI reference. + +## Consequences + +### Positive + +- One less curated label registry to maintain. +- IRIs are self-describing; conformance claims are dereferenceable. +- Aligns with Linked Art's established pattern. + +### Negative / trade-offs + +- Breaking rename for any downstream consumer that read `target_kind`. Acceptable pre-v1.0.0. +- Coordinated change across two repos (`textrefs/textrefs.org` schema/docs, `textrefs/registry` YAML data). + +### Follow-up actions + +- [x] Update spec §10 and Appendix B. +- [x] Update the v1 JSON-LD context. +- [x] Update Zod schema, compile pipeline, and in-tree fixture. +- [x] Migrate `data/works/*.yaml` in `textrefs/registry` (carried by registry PR #1). +- [x] Bump `data/` submodule pointer to the migrated registry commit. + +## Links + +- Related issues / PRs: textrefs/textrefs.org#6, textrefs/textrefs.org#5, textrefs/registry#1 +- External references: [Linked Art — Digital Integration](https://linked.art/model/digital/), [DCMI Terms — conformsTo](http://purl.org/dc/terms/conformsTo) diff --git a/public/contexts/v1.jsonld b/public/contexts/v1.jsonld index 88a37d9..19319f4 100644 --- a/public/contexts/v1.jsonld +++ b/public/contexts/v1.jsonld @@ -50,11 +50,14 @@ "@type": "@id" }, "target": "tr:target", - "target_kind": "tr:targetKind", "identifier": { "@id": "tr:identifier", "@type": "@id" }, + "conforms_to": { + "@id": "dcterms:conformsTo", + "@type": "@id" + }, "resolver_targets": "tr:resolverTargets", "provider": "schema:provider", "url": { diff --git a/scripts/compile.ts b/scripts/compile.ts index 62f96fb..b45fb12 100644 --- a/scripts/compile.ts +++ b/scripts/compile.ts @@ -127,8 +127,8 @@ function expandRange(range: ReferenceRange): string[] { type MappingSource = { relation: 'exactMatch' | 'closeMatch'; - target_kind?: string; identifier: string; + conforms_to?: string | string[]; source: string; status: string; created: string; @@ -433,10 +433,10 @@ export function compileRegistry(): CompiledRegistry { subject: workIri, relation: mapping.relation, target: { - ...(mapping.target_kind !== undefined && { - target_kind: mapping.target_kind, - }), identifier: mapping.identifier, + ...(mapping.conforms_to !== undefined && { + conforms_to: mapping.conforms_to, + }), }, source: mapping.source, status: mapping.status, diff --git a/src/content/docs/get-started/authoring.md b/src/content/docs/get-started/authoring.md index 82515ec..45c45d8 100644 --- a/src/content/docs/get-started/authoring.md +++ b/src/content/docs/get-started/authoring.md @@ -36,8 +36,8 @@ citation_system: dhammapada-chapter-verse mappings: - relation: exactMatch - target_kind: wikidata identifier: 'https://www.wikidata.org/entity/Q220114' + conforms_to: 'https://www.wikidata.org/' source: manual-curation status: candidate created: 2026-05-31 diff --git a/src/content/docs/get-started/how-it-works.md b/src/content/docs/get-started/how-it-works.md index e1ff860..3882064 100644 --- a/src/content/docs/get-started/how-it-works.md +++ b/src/content/docs/get-started/how-it-works.md @@ -98,8 +98,8 @@ Work-level equivalences live in a `MappingAssertion`: "subject": "https://textrefs.org/id/work/plato.republic", "relation": "exactMatch", "target": { - "target_kind": "wikidata", - "identifier": "https://www.wikidata.org/entity/Q123397" + "identifier": "https://www.wikidata.org/entity/Q123397", + "conforms_to": "https://www.wikidata.org/" }, "source": "manual-curation", "status": "candidate", diff --git a/src/content/docs/get-started/mappings-and-resolver-targets.md b/src/content/docs/get-started/mappings-and-resolver-targets.md index 354936d..c271d82 100644 --- a/src/content/docs/get-started/mappings-and-resolver-targets.md +++ b/src/content/docs/get-started/mappings-and-resolver-targets.md @@ -40,8 +40,8 @@ Use `exactMatch` only when the target identifies the same work with enough preci "subject": "https://textrefs.org/id/work/dhammapada", "relation": "exactMatch", "target": { - "target_kind": "wikidata", - "identifier": "https://www.wikidata.org/entity/Q220114" + "identifier": "https://www.wikidata.org/entity/Q220114", + "conforms_to": "https://www.wikidata.org/" }, "source": "manual-curation" } diff --git a/src/content/docs/standard/identifier-syntax.md b/src/content/docs/standard/identifier-syntax.md index f0a9648..2835904 100644 --- a/src/content/docs/standard/identifier-syntax.md +++ b/src/content/docs/standard/identifier-syntax.md @@ -117,7 +117,7 @@ relation target.identifier ``` -`subject` MUST be the canonical Work IRI (`https://textrefs.org/id/work/{work_key}`). `relation` MUST be the literal string `exactMatch` or `closeMatch`. `target.identifier` MUST be used as supplied by the source record, after any IRI normalization the source profile already applies. `target.target_kind` is a non-normative hint and does NOT enter the seed. +`subject` MUST be the canonical Work IRI (`https://textrefs.org/id/work/{work_key}`). `relation` MUST be the literal string `exactMatch` or `closeMatch`. `target.identifier` MUST be used as supplied by the source record, after any IRI normalization the source profile already applies. `target.conforms_to` is informative and does NOT enter the seed. The canonical URI is `https://textrefs.org/id/mapping/{uuid}`. diff --git a/src/content/docs/standard/json-ld.md b/src/content/docs/standard/json-ld.md index 2affd27..6c5398a 100644 --- a/src/content/docs/standard/json-ld.md +++ b/src/content/docs/standard/json-ld.md @@ -20,7 +20,7 @@ https://textrefs.org/contexts/v1.jsonld | --------- | -------------------------------------- | -------------------------------------------------------------------------- | | `tr` | `https://textrefs.org/ontology#` | TextRefs object types, keys, and TextRefs-specific metadata | | `skos` | `http://www.w3.org/2004/02/skos/core#` | Labels, schemes (`inScheme`), and mapping relations | -| `dcterms` | `http://purl.org/dc/terms/` | `created`, `modified`, `source`, `language`, `license` | +| `dcterms` | `http://purl.org/dc/terms/` | `created`, `modified`, `source`, `language`, `license`, `conformsTo` | | `schema` | `https://schema.org/` | `url`, `provider`, `edition`, `creator`, `familyName`, `givenName`, `name` | | `xsd` | `http://www.w3.org/2001/XMLSchema#` | `xsd:date` typing for `created` / `modified` / `last_checked` | @@ -70,8 +70,8 @@ Use `exactMatch` only when the mapped object identifies the same reference with "closeMatch": { "@id": "skos:closeMatch", "@type": "@id" }, "subject": { "@id": "tr:subject", "@type": "@id" }, "target": "tr:target", - "target_kind": "tr:targetKind", "identifier": { "@id": "tr:identifier", "@type": "@id" }, + "conforms_to": { "@id": "dcterms:conformsTo", "@type": "@id" }, "resolver_targets": "tr:resolverTargets", "provider": "schema:provider", "url": { "@id": "schema:url", "@type": "@id" }, diff --git a/src/content/docs/standard/specification.md b/src/content/docs/standard/specification.md index 146b54f..0ad3461 100644 --- a/src/content/docs/standard/specification.md +++ b/src/content/docs/standard/specification.md @@ -246,8 +246,8 @@ A `MappingAssertion` records a curated equivalence claim between a TextRefs `Wor "subject": "https://textrefs.org/id/work/new-testament", "relation": "exactMatch", "target": { - "target_kind": "wikidata", - "identifier": "https://www.wikidata.org/entity/Q18813" + "identifier": "https://www.wikidata.org/entity/Q18813", + "conforms_to": "https://www.wikidata.org/" }, "source": "manual-curation", "status": "candidate", @@ -260,7 +260,7 @@ Required: `id`, `type` (`MappingAssertion`), `subject`, `relation`, `target`, `s - `subject` MUST be a `Work` IRI of the form `https://textrefs.org/id/work/{work_key}`. Per-passage external identifiers (e.g. the CTS URN of a single verse) are derived from work-level mappings combined with the reference locator at resolve time; they MUST NOT be stored as separate `MappingAssertion` records. - `target.identifier` MUST be an IRI ([RFC 3987](https://www.rfc-editor.org/rfc/rfc3987)) that identifies a **textual resource**: a work, edition, manuscript, citation system, or another TextRefs `Work`. -- `target.target_kind` is OPTIONAL and is a human-readable scheme hint (e.g. `"cts"`, `"doi"`, `"wikidata"`, `"textrefs"`). Validators MUST NOT key behaviour off it. The presence or absence of `target_kind` carries no normative weight; the IRI in `identifier` is authoritative. See [Appendix B](#appendix-b-well-known-external-identifier-schemes-informative) for non-normative examples. +- `target.conforms_to` is OPTIONAL. When present, it MUST be a dereferenceable IRI — or an array of such IRIs — identifying the specification or identifier scheme to which `target.identifier` conforms (e.g. the home page of the CTS specification, the Wikidata project, or a DOI handbook section). It is informative: validators MUST NOT key behaviour off it; the IRI in `identifier` is authoritative. See [Appendix B](#appendix-b-well-known-external-identifier-schemes-informative) for non-normative examples. - `relation` MUST be one of the SKOS-compatible values `exactMatch` or `closeMatch`. Use `exactMatch` only when the mapped resource identifies the same work with sufficient precision; if there is any uncertainty about edition, coverage, or work boundaries, use `closeMatch`. - `source` documents the basis for the assertion. A structured [W3C PROV-O](https://www.w3.org/TR/prov-o/) mapping is reserved for a future version. @@ -431,19 +431,19 @@ Build on the core registry by keeping these concerns in application, extension, ## Appendix B. Well-known external identifier schemes (informative) -The following identifier schemes commonly satisfy [§10](#10-mappingassertion)'s "textual resource" rule and are useful values for `MappingAssertion.target.identifier`. Treat this table as implementation guidance: the authoritative rule is still whether the IRI identifies a textual resource. - -| Scheme | `target_kind` hint | Example identifier | -| -------- | ------------------ | ------------------------------------------------- | -| TextRefs | `textrefs` | `https://textrefs.org/id/ref/988e0b39-…` | -| CTS URN | `cts` | `urn:cts:greekLit:tlg0031.tlg004:3.16` | -| DTS | `dts` | `https://dts.example/api/collection?id=urn:cts:…` | -| DOI | `doi` | `https://doi.org/10.5281/zenodo.7702622` | -| ARK | `ark` | `https://n2t.net/ark:/12148/btv1b8451636f` | -| Handle | `handle` | `https://hdl.handle.net/1887/4531` | -| PURL | `purl` | `https://purl.org/dc/terms/` | -| URN:NBN | `urn-nbn` | `urn:nbn:de:bvb:12-bsb00012345-2` | -| Wikidata | `wikidata` | `https://www.wikidata.org/entity/Q42` | +The following identifier schemes commonly satisfy [§10](#10-mappingassertion)'s "textual resource" rule and are useful values for `MappingAssertion.target.identifier`. Treat this table as implementation guidance: the authoritative rule is still whether the IRI identifies a textual resource. The `conforms_to` column gives a representative scheme IRI; any dereferenceable IRI that identifies the same specification is equally valid. + +| Scheme | Example identifier | Example `conforms_to` | +| -------- | ------------------------------------------------- | ------------------------------------------------------------- | +| TextRefs | `https://textrefs.org/id/ref/988e0b39-…` | `https://textrefs.org/` | +| CTS URN | `urn:cts:greekLit:tlg0031.tlg004:3.16` | `https://cite-architecture.github.io/` | +| DTS | `https://dts.example/api/collection?id=urn:cts:…` | `https://distributed-text-services.github.io/specifications/` | +| DOI | `https://doi.org/10.5281/zenodo.7702622` | `https://www.doi.org/` | +| ARK | `https://n2t.net/ark:/12148/btv1b8451636f` | `https://arks.org/` | +| Handle | `https://hdl.handle.net/1887/4531` | `https://www.handle.net/` | +| PURL | `https://purl.org/dc/terms/` | `https://purl.archive.org/` | +| URN:NBN | `urn:nbn:de:bvb:12-bsb00012345-2` | `https://nbn-resolving.org/` | +| Wikidata | `https://www.wikidata.org/entity/Q42` | `https://www.wikidata.org/` | TextRefs keeps mappings focused on textual resources. Identifiers of agents, organisations, instruments, or non-textual datasets (e.g. ROR, ORCID, ISNI) belong in external authority systems reached through mapped textual resources, not in `MappingAssertion.target`. diff --git a/src/lib/registry.fixture.ts b/src/lib/registry.fixture.ts index e8fa02a..d903298 100644 --- a/src/lib/registry.fixture.ts +++ b/src/lib/registry.fixture.ts @@ -58,7 +58,6 @@ export const fixtureRegistry: CompiledRegistry = { subject: fixtureWorkIri, relation: 'exactMatch', target: { - target_kind: 'fixture', identifier: 'https://example.org/fixture-work', }, source: 'Local fixture for fast site validation.', diff --git a/src/pages/id/mapping/[uuid]/index.astro b/src/pages/id/mapping/[uuid]/index.astro index 5dfa0b1..e000127 100644 --- a/src/pages/id/mapping/[uuid]/index.astro +++ b/src/pages/id/mapping/[uuid]/index.astro @@ -71,11 +71,6 @@ const jsonHref = `/id/mapping/${uuidOf(mapping.id)}.json`;
  • Target: - { - mapping.target.target_kind && ( - {mapping.target.target_kind} - ) - } {m.relation} - {m.target.target_kind && ( - {m.target.target_kind} - )} {m.target.identifier}
  • ))} diff --git a/standard/schema/mapping-assertion.ts b/standard/schema/mapping-assertion.ts index be7a7a1..aebb7be 100644 --- a/standard/schema/mapping-assertion.ts +++ b/standard/schema/mapping-assertion.ts @@ -20,8 +20,8 @@ export const MappingAssertionBase = AdminMetadata.extend({ subject: WorkIri, relation: z.enum(['exactMatch', 'closeMatch']), target: z.object({ - target_kind: z.string().optional(), identifier: Iri, + conforms_to: z.union([Iri, z.array(Iri).min(1)]).optional(), }), source: z.string().min(1), }); From e54b883cd9ad9b561a24e9adb824f8e83ae125d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Tue, 9 Jun 2026 23:39:32 +0200 Subject: [PATCH 8/9] chore(data): bump submodule to registry main (36cae56) textrefs/registry#1 merged via squash; advance data/ pointer from the feature branch tip to the merge commit on main so the Validate workflow's "pin is on registry main" guard passes. Co-Authored-By: Claude Opus 4.7 --- data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data b/data index be413a0..36cae56 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit be413a092bd71b36fecc04a91ac3c0b052f9c097 +Subproject commit 36cae56593807e6e5ebbdd4eb96878eb74229f9d From 666dc78138b52def591ec15fcac1e52d73f9f3eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= <14755525+maehr@users.noreply.github.com> Date: Wed, 10 Jun 2026 00:00:09 +0200 Subject: [PATCH 9/9] fix(404): mark docs/404.mdx as draft to drop catch-all route conflict Starlight reads docs/404 via getEntry() for its dedicated /404 route AND enumerates the same entry through the [...slug] catch-all, producing a benign but noisy build warning ("Could not render /404 from route /[...slug] as it conflicts with higher priority route /404"). draft: true excludes the entry from the catch-all in production builds while leaving Starlight's direct-by-id lookup intact, so dist/404.html still ships our custom hero. The localised dist/de/404/index.html is dropped (the fallback-route pass uses the same draft-filtered docs list); Cloudflare Pages serves /404.html for missing pages across all locales anyway. Co-Authored-By: Claude Opus 4.7 --- src/content/docs/404.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/content/docs/404.mdx b/src/content/docs/404.mdx index 2f38e0b..8dba66b 100644 --- a/src/content/docs/404.mdx +++ b/src/content/docs/404.mdx @@ -3,6 +3,7 @@ title: '404' description: This page could not be found. Help improve TextRefs by reporting broken links or missing content. template: splash editUrl: false +draft: true hero: title: This reference is missing. tagline: If you expected a TextRefs page here, please help us improve the registry and documentation.