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/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/data b/data index 6d04b70..36cae56 160000 --- a/data +++ b/data @@ -1 +1 @@ -Subproject commit 6d04b70c61fce0c3402ea2f8eac7a5a9ea886e79 +Subproject commit 36cae56593807e6e5ebbdd4eb96878eb74229f9d 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/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/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/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/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/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. 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. 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 68d429f..3882064 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" } ], @@ -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 bf6d03f..0ad3461 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.** @@ -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. @@ -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" + } + ] } ``` @@ -401,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/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/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), }); 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'], });