From 70ddf74ee59646653a3c6ca2adea73e26ca27522 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:05:50 +0200 Subject: [PATCH 01/12] chore: add textrefs/.github as submodule at github-profile/ --- .gitmodules | 4 ++++ github-profile | 1 + 2 files changed, 5 insertions(+) create mode 160000 github-profile diff --git a/.gitmodules b/.gitmodules index 3889a1b..b977b73 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,7 @@ path = data url = https://github.com/textrefs/registry.git branch = main +[submodule "github-profile"] + path = github-profile + url = https://github.com/textrefs/.github.git + branch = main diff --git a/github-profile b/github-profile new file mode 160000 index 0000000..5fbd182 --- /dev/null +++ b/github-profile @@ -0,0 +1 @@ +Subproject commit 5fbd182911f37ff025647c874133b7ce491bbf9e From 5f63ebedf2fad529060ab425d7a60cb266f6b4f1 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:06:03 +0200 Subject: [PATCH 02/12] docs: revise get-started prose and document staging deploy flow Rewrite the Get Started body around the single-identity narrative ("a passage has one identity, the editions that carry it are many"), keeping the Keep reading and Live examples lists as deep-link entry points. Document the branching model in CONTRIBUTING.md: main is the production source and auto-deploys; staging is a long-lived batching branch for content edits; publish by squash-merging staging into main. Manual workflow_dispatch from staging is available as an escape-hatch preview that temporarily replaces production. Co-Authored-By: Claude Opus 4.7 --- CONTRIBUTING.md | 18 +++++++++++++++--- src/content/docs/get-started/index.md | 22 ++++++++++------------ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6d941c1..a34c876 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,13 +91,25 @@ The commit-msg hook (commitlint) rejects non-conforming messages, so a plain `gi The changelog is generated from this history via `npm run changelog` (git-cliff). +## Branching model + +The production site (`textrefs.org`) is built and deployed from `main`. To keep `main`'s history low-noise while still allowing many small content edits, day-to-day docs/blog/copy work batches on a long-lived `staging` branch and is squash-merged into `main` to publish. + +- `main` — production source. Pushes here auto-deploy via `.github/workflows/pages.yml`. Release tags (`vX.Y.Z`, `vYYYY.MM.N`) are cut from `main`. +- `staging` — long-lived batching branch for docs, blog posts, copy, registry-pointer bumps, and other content edits. Does **not** auto-deploy. Edits accumulate here as many small commits. +- To publish: open a PR `staging → main` and squash-merge. The squash-commit lands on `main` as one conventional commit (so `git-cliff` stays clean) and triggers the production deploy. +- Manual preview / ad-hoc deploy: from the GitHub Actions UI, run the **Pages** workflow via `workflow_dispatch` and pick `staging` (or any branch) as the ref. This deploys that ref to production until the next push to `main`. There is no separate preview URL — GitHub Pages serves a single site per repo, so manual staging deploys temporarily replace production. Use sparingly. +- Infrastructure changes (CI, release workflow, build tooling, deploy config) target `main` directly so they are not gated on the next staging-to-main snapshot. + +Squash merging is the only enabled merge style on the canonical repo, so `staging`'s noisy history is collapsed into a single conventional-commit message on `main` and `git-cliff` still produces a clean `CHANGELOG.md`. + ## Submitting a pull request -1. Branch from `main`. +1. Branch from `staging` for content/docs/blog; branch from `main` for infra, CI, or release-workflow changes. 2. Keep PRs focused — one logical change per PR. 3. Link related issues in the PR description. 4. Include local verification results: `npm run verify:fast` for routine work, or `npm run verify` plus `npm run validate:data` for registry-data, standard, release, production-build, or CI changes. -5. Open the PR against `main`. GitHub requests `@textrefs/maintainers` by default via `.github/CODEOWNERS`; maintainers may add technical or expert reviewers based on the track. +5. Open the PR against the branch you started from (`staging` or `main`). GitHub requests `@textrefs/maintainers` by default via `.github/CODEOWNERS`; maintainers may add technical or expert reviewers based on the track. ## Project layout @@ -112,7 +124,7 @@ Two release trains. The Zenodo–GitHub webhook MUST be enabled once per reposit 1. Bump `version` in `package.json` to match the new tag. 2. `npm run changelog` to regenerate `CHANGELOG.md`. 3. Update spec page frontmatter `maturity:` if the release transitions the ladder. -4. Commit, open PR, merge to `main`. +4. Open a PR `staging → main` and squash-merge it. The squash message should be a conventional commit (`docs(release): vX.Y.Z` or similar) so the changelog stays clean. 5. Tag `vX.Y.Z[-pre]` on `main`; push the tag. 6. Verify the GitHub Release fires and Zenodo mints the version DOI. 7. Fill the concept DOI into `CITATION.cff` `identifiers:` and the badge in `README.md` (once, after the first release). diff --git a/src/content/docs/get-started/index.md b/src/content/docs/get-started/index.md index 363cf55..fa24ead 100644 --- a/src/content/docs/get-started/index.md +++ b/src/content/docs/get-started/index.md @@ -1,27 +1,25 @@ --- title: Get started -description: Why TextRefs exists, who it's for, and how it fits with existing identifier systems. +description: Why a passage needs one persistent identity, and how TextRefs supplies it without replacing existing editions or identifiers. sidebar: order: 1 --- -## The gap +A passage has one identity. The editions that carry it are many. -Citations like "Plato, _Republic_ 514a" or "Aristotle, _Eth. Nic._ 1094a1" are foundational to scholarship in classics, theology, law, philosophy, and adjacent disciplines. Every serious edition, commentary, and database uses them. Yet none of them has a native, persistent, machine-readable identifier you can paste into a tool, link from a paper, or feed to an indexing pipeline. They live as plain text inside footnotes and prose, dependent on the reader knowing the citation convention. +"Plato, _Republic_ 514a" is the same passage in Burnet's Oxford text, the Slings OCT that replaced it, Shorey's Loeb, and every translation that keeps the Stephanus numbers. Pagination, apparatus and language differ. The reference does not. It is the most durable thing in the scholarly record: central to classics, theology, law and philosophy, used by every edition and commentary, and understood across centuries. -That mismatch — central in scholarship, invisible to software — is what TextRefs addresses. +To software it is invisible. The number lives as plain text in a footnote, dependent on a reader who knows the convention. No tool can resolve it, no link can carry it, no pipeline can index it. A reference that survived four hundred years on paper breaks in a decade online, because the edition behind it sits in a repository the citation cannot reach. -## What TextRefs is +TextRefs closes that gap. Every canonical reference is minted as a persistent identity of its own, a single HTTP URI for the passage a scholar means. Editions, translations, corpora and databases attach to it as curated mappings: a Stephanus locator, a CTS URN, a Wikidata QID, a DOI for the Loeb, the reading URL of the archive that holds the text. The citation becomes the doorway, and everything that carries the passage is reachable through it. -TextRefs is an open registry. For each canonical reference we mint a persistent HTTP URI, attach curated mappings to relevant external identifiers (CTS URNs, Wikidata QIDs, DOIs, library and edition URLs), record resolver targets where readers can inspect the passage, document provenance and uncertainty, and publish everything as JSON-LD under non-profit governance. The registry is read-only and changes happen via reviewed pull requests; data is released under CC0 so it can flow into any tool that needs it. +This is the interoperability scholarship has lacked. Every scholar already keeps the map privately. Bekker for the _Metaphysics_, Corcilius for the _De anima_, Rashed for _On Generation and Corruption_. Exact, hard-won, and gone the moment the article closes. TextRefs makes it shared and machine-readable. Oxford and the Loeb, Leipzig and Perseus, Wikidata and VIAF keep their own identifiers, their own homes, their own richer work, joined through the one reference they share. No central host. No redundancy. Authority stays with the institutions that earned it, and the archive that digitised an edition is now one mapping away from every citation of the passage it holds. -The same model covers a Stephanus passage in Plato, a Bekker line in Aristotle, a chapter-and-verse in the Vulgate, an article in the _Summa_, and a fragment in the _Digesta_ — every traditional reference system is a `CitationSystem` with its own locator rules. +The division is deliberate. TextRefs holds the reference layer only and nothing else. It hosts no text, replaces no edition, claims no apparatus. The same model covers every field that cites by structure: a Stephanus passage in Plato, a Bekker line in Aristotle, an article in the _Summa_, a chapter and verse in the Vulgate, a fragment in the _Digesta_. Each citation system carries its own locator rules. The registry stays small, persistent and legally reusable, released under CC0 so the data flows into any tool that needs it, curated by scholars through reviewed contributions, governed as non-profit infrastructure, not owned by a press. -## Use TextRefs with existing systems +Four record types carry the model. `Work`, `CitationSystem`, `CanonicalReference`, and `MappingAssertion` for equivalence, published as JSON-LD against SKOS, Dublin Core and schema.org. Existing systems are layered, never displaced. A DOI still names the edition. A CTS URN still names the passage in Perseus. TextRefs holds the canonical reference they share, and makes it resolve. -Use TextRefs for the stable citation identity: the passage, article, line, section, or fragment a scholar means when they write a traditional reference. Keep edition text, commentary, apparatus, translations, and platform-specific records in the systems that already curate them. - -This division is deliberate. TextRefs stays small, persistent, and legally reusable; libraries, editions, catalogues, and reading platforms keep doing the richer work they are built for. The registry connects them through curated mappings instead of trying to replace them. See the [related systems comparison](/get-started/related-systems/) for the full picture. +[Browse the registry](/reg/). [Read the standard](/standard/). [Bring your corpus in](/get-started/authoring/). ## Keep reading @@ -30,6 +28,7 @@ This division is deliberate. TextRefs stays small, persistent, and legally reusa - [Mappings and resolver targets](/get-started/mappings-and-resolver-targets/) — how to model external identifiers, reading URLs, and canonical-citation candidates. - [Authoring registry data](/get-started/authoring/) — the contributor YAML format and the `npm run build:data` pipeline. - [Related identifier systems](/get-started/related-systems/) — how TextRefs relates to DOI, ARK, CTS, DTS, Wikidata, VIAF, and friends. +- [URL layout](/get-started/url-layout/) — how `/id/`, `/reg/`, `/cite/`, and `/api/` fit together. - [The standard](/standard/) — the normative specification text (`v0.1.0-draft`). - [The association](/association/) — the non-profit behind TextRefs, its statutes, and the open board search. @@ -39,4 +38,3 @@ This division is deliberate. TextRefs stays small, persistent, and legally reusa - [`/id/work/plato.republic/`](/id/work/plato.republic/) — Plato's _Republic_ with Stephanus pagination. - [`/cite/plato.republic/514a`](/cite/plato.republic/514a) — a short alias that redirects to the canonical reference URL. - [`/reg/`](/reg/) — the registry browser. -- [URL layout](/get-started/url-layout/) — how `/id/`, `/reg/`, `/cite/`, and `/api/` fit together. 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 03/12] 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 04/12] 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 05/12] 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 06/12] 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 07/12] =?UTF-8?q?docs(spec):=20self-contained=20=C2=A713?= =?UTF-8?q?=20example=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 08/12] 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 09/12] 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 10/12] 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 11/12] 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. From 24b2e362c56734e0e6609268383c9af3865ce2b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20M=C3=A4hr?= Date: Fri, 26 Jun 2026 10:19:09 +0200 Subject: [PATCH 12/12] docs: add ORCID for Luz Christopher Seiberth (#19) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(profile): bump github-profile submodule Refresh org profile README and add a top-level README in textrefs/.github. Co-Authored-By: Claude Opus 4.8 * docs: add ORCID for Luz Christopher Seiberth Record ORCID 0000-0002-5606-0964 for the second author/creator in CITATION.cff and the project's Zenodo metadata, matching the existing ORCID entry for the first author. Checksum-verified valid. Co-Authored-By: Claude Opus 4.8 --------- Co-authored-by: Moritz Mähr <14755525+maehr@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 --- .zenodo.json | 3 ++- CITATION.cff | 2 +- github-profile | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index e3da71a..b9f58dd 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -17,7 +17,8 @@ }, { "name": "Seiberth, Luz Christopher", - "affiliation": "TextRefs" + "affiliation": "TextRefs", + "orcid": "0000-0002-5606-0964" } ], "keywords": [ diff --git a/CITATION.cff b/CITATION.cff index 55cc761..ee1ee82 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -13,8 +13,8 @@ authors: - family-names: Seiberth given-names: Luz Christopher email: luz@seiberth.de + orcid: 'https://orcid.org/0000-0002-5606-0964' affiliation: TextRefs - # ORCID: TBD repository-code: 'https://github.com/textrefs/textrefs.org' url: 'https://textrefs.org' license: diff --git a/github-profile b/github-profile index 5fbd182..9b707b9 160000 --- a/github-profile +++ b/github-profile @@ -1 +1 @@ -Subproject commit 5fbd182911f37ff025647c874133b7ce491bbf9e +Subproject commit 9b707b984843736e0d917aea1060d1def560634e