From 564eaea5a06b2bd9b55a0f99452357927e965be5 Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 11 Jul 2026 22:10:34 -0500 Subject: [PATCH] Phase 3 expand machine catalogs --- CHANGELOG.md | 8 +- CONVENTIONS.md | 8 ++ package-lock.json | 4 +- package.json | 2 +- packages/json/catalog.json | 122 ++++++++++++++++++++- packages/json/kjv-eng-kjv2006/catalog.json | 89 ++++++++++++++- scripts/import-usfm.js | 53 +++++++-- 7 files changed, 271 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a67489..fa059fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,16 @@ ## Current -- Added generated human-facing resource docs for Gitea and future ChristIT.com catalog work. +- Expanded machine catalogs so ChristIT.com and apps can read rich resource metadata directly from JSON. + +## 0.1.3 - 2026-07-12 + +- Phase 3 machine catalog foundation: expanded aggregate and per-resource JSON catalogs with schema version, resource identity, translation metadata, contributors, features, attachments, source/license details, package paths, checksums, and file sizes. ## 0.1.2 - 2026-07-12 +- Added generated human-facing resource docs for Gitea and future ChristIT.com catalog work. + - Phase 2 generated public docs: added a docs generator that writes `RESOURCE_INDEX.md` and per-resource detail pages from source manifests and generated package catalogs. ## 0.1.1 - 2026-07-12 diff --git a/CONVENTIONS.md b/CONVENTIONS.md index d80a46a..b6677a7 100644 --- a/CONVENTIONS.md +++ b/CONVENTIONS.md @@ -99,6 +99,14 @@ Attachment metadata should identify: - Build/import scripts should fail when required source, license, checksum, or package metadata is missing. - The public catalog must not silently disagree with the source manifest. +## Machine Catalogs + +- `packages/json/catalog.json` is the machine-readable index for ChristIT.com, Libre Study, GracePress Bible Tooltip, and future consumers. +- Per-resource package catalogs, such as `packages/json//catalog.json`, should carry the full resource metadata needed to render a public detail page without scraping Markdown. +- Machine catalogs should include schema version, project name, resource id, resource type, title, abbreviation, language, script, canon, translation/edition metadata, contributors, features, attachments, source, license, display summary, package paths, counts, file checksums, and source check metadata. +- Markdown docs are a human-readable projection of the same metadata. They must not become a separate truth source. +- Public ChristIT.com pages and app/plugin package discovery should read machine catalogs first, then link to Markdown docs for explanation. + ## Update Workflow - Update checks must be mechanical and repeatable. diff --git a/package-lock.json b/package-lock.json index e5acf8d..28c178c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "libre-bible-data", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "libre-bible-data", - "version": "0.1.2", + "version": "0.1.3", "dependencies": { "adm-zip": "^0.5.16" } diff --git a/package.json b/package.json index 0847765..51ebe8b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "libre-bible-data", - "version": "0.1.2", + "version": "0.1.3", "private": true, "type": "module", "scripts": { diff --git a/packages/json/catalog.json b/packages/json/catalog.json index a7e1198..508b70b 100644 --- a/packages/json/catalog.json +++ b/packages/json/catalog.json @@ -1,15 +1,51 @@ { - "generated_at": "2026-07-12T02:51:51.354Z", + "schema_version": "librebible.index-catalog.v1", + "project": "LibreBible", + "generated_at": "2026-07-12T03:10:02.881Z", "resources": [ { "id": "kjv-eng-kjv2006", + "resource_type": "translation", "title": "King James (Authorized) Version", + "short_title": "King James Version", "abbreviation": "KJV", + "alternate_ids": [ + "ENGKJV", + "eng-kjv2006" + ], "language": { "code": "eng", "name": "English", "dialect": "archaic British" }, + "script": "Latn", + "canon": { + "scope": "protocanon", + "notes": "eBible describes this package as protocanon only." + }, + "translation": { + "base_title": "King James Version", + "edition": "1769 standardized text with Strong's numbers added", + "translation_year": 1611, + "edition_year": 1769, + "source_text_basis": "Authorized Version / King James Version standardized text of 1769", + "tradition": "Protestant", + "public_description": "The King James Version or Authorized Version of the Holy Bible, using the standardized text of 1769, protocanon only, with Strong's numbers added." + }, + "contributors": [ + { + "name": "King James Version translators", + "role": "translation" + }, + { + "name": "CrossWire Bible Society", + "role": "source text provider" + }, + { + "name": "eBible.org", + "role": "publisher and package provider" + } + ], "features": [ { "id": "bible-text", @@ -43,6 +79,64 @@ "embedded": false } ], + "attachments": { + "included": [ + { + "id": "kjv-eng-kjv2006-strongs-links", + "resource_type": "concordance_links", + "label": "Strong's links", + "relationship": "word-to-strongs", + "anchor_types": [ + "verse", + "word", + "strongs_number" + ], + "languages": [ + "hebrew", + "aramaic", + "greek" + ], + "systems": [ + "strongs" + ], + "source": "Embedded in the eBible USFM package.", + "package": "packages/json/kjv-eng-kjv2006/strongs-links.jsonl" + } + ], + "supported_future_types": [ + "study_notes", + "commentary", + "cross_references", + "morphology", + "lemma_links", + "lexicon", + "dictionary", + "maps", + "timeline", + "media" + ] + }, + "source": { + "provider": "eBible.org", + "url": "https://ebible.org/find/show.php?id=eng-kjv2006", + "download_url": "https://ebible.org/Scriptures/eng-kjv2006_usfm.zip", + "format": "usfm-zip", + "upstream_id": "eng-kjv2006", + "upstream_last_updated": "2026-05-16", + "available_formats": [ + "browser", + "mobile-html", + "epub", + "pdf", + "sword", + "plain-text", + "vpl-sql", + "browser-bible", + "usfx", + "usfm", + "xetex" + ] + }, "license": { "name": "Public Domain", "redistribution": true, @@ -54,11 +148,37 @@ ], "restricted_notes": "Printing this translation in the United Kingdom or importing printed copies into the UK may require permission from the Crown patent holders." }, + "catalog_display": { + "primary_features": [ + "Bible text", + "Strong's-linked words", + "USFM source" + ], + "summary": "Public-domain KJV package based on the 1769 standardized text, with Strong's numbers embedded in the source USFM." + }, "package_path": "packages/json/kjv-eng-kjv2006/catalog.json", + "source_manifest_path": "sources/kjv-eng-kjv2006.json", + "detail_doc_path": "docs/resources/kjv-eng-kjv2006.md", "counts": { "books": 66, "verses": 31102, "strongs_links": 348884 + }, + "files": { + "verses_jsonl": { + "path": "verses.jsonl", + "bytes": 8700726, + "sha256": "e3102f854a99c4788ed259ec61cb93fea830845c0788c8c0929bc77e9db6ca10" + }, + "strongs_jsonl": { + "path": "strongs-links.jsonl", + "bytes": 62690394, + "sha256": "fa9702224776509275ea17fb245cb72150f1c262c4fbe44c7161e8e83866c779" + } + }, + "checks": { + "expected_sha256": "4ea6952590d070bfa22985aded48a49581e31b568a60aa09e25f73462e700e7d", + "last_checked_at": "2026-07-12T02:18:30Z" } } ] diff --git a/packages/json/kjv-eng-kjv2006/catalog.json b/packages/json/kjv-eng-kjv2006/catalog.json index d15cb09..fa9f5df 100644 --- a/packages/json/kjv-eng-kjv2006/catalog.json +++ b/packages/json/kjv-eng-kjv2006/catalog.json @@ -1,12 +1,48 @@ { + "schema_version": "librebible.resource-catalog.v1", + "project": "LibreBible", "id": "kjv-eng-kjv2006", + "resource_type": "translation", "title": "King James (Authorized) Version", + "short_title": "King James Version", "abbreviation": "KJV", + "alternate_ids": [ + "ENGKJV", + "eng-kjv2006" + ], "language": { "code": "eng", "name": "English", "dialect": "archaic British" }, + "script": "Latn", + "canon": { + "scope": "protocanon", + "notes": "eBible describes this package as protocanon only." + }, + "translation": { + "base_title": "King James Version", + "edition": "1769 standardized text with Strong's numbers added", + "translation_year": 1611, + "edition_year": 1769, + "source_text_basis": "Authorized Version / King James Version standardized text of 1769", + "tradition": "Protestant", + "public_description": "The King James Version or Authorized Version of the Holy Bible, using the standardized text of 1769, protocanon only, with Strong's numbers added." + }, + "contributors": [ + { + "name": "King James Version translators", + "role": "translation" + }, + { + "name": "CrossWire Bible Society", + "role": "source text provider" + }, + { + "name": "eBible.org", + "role": "publisher and package provider" + } + ], "features": [ { "id": "bible-text", @@ -40,6 +76,43 @@ "embedded": false } ], + "attachments": { + "included": [ + { + "id": "kjv-eng-kjv2006-strongs-links", + "resource_type": "concordance_links", + "label": "Strong's links", + "relationship": "word-to-strongs", + "anchor_types": [ + "verse", + "word", + "strongs_number" + ], + "languages": [ + "hebrew", + "aramaic", + "greek" + ], + "systems": [ + "strongs" + ], + "source": "Embedded in the eBible USFM package.", + "package": "packages/json/kjv-eng-kjv2006/strongs-links.jsonl" + } + ], + "supported_future_types": [ + "study_notes", + "commentary", + "cross_references", + "morphology", + "lemma_links", + "lexicon", + "dictionary", + "maps", + "timeline", + "media" + ] + }, "source": { "provider": "eBible.org", "url": "https://ebible.org/find/show.php?id=eng-kjv2006", @@ -72,12 +145,24 @@ ], "restricted_notes": "Printing this translation in the United Kingdom or importing printed copies into the UK may require permission from the Crown patent holders." }, + "catalog_display": { + "primary_features": [ + "Bible text", + "Strong's-linked words", + "USFM source" + ], + "summary": "Public-domain KJV package based on the 1769 standardized text, with Strong's numbers embedded in the source USFM." + }, "importer": { "name": "scripts/import-usfm.js", "version": "0.1.0" }, - "generated_at": "2026-07-12T02:51:51.354Z", + "generated_at": "2026-07-12T03:10:02.881Z", "source_sha256": "4ea6952590d070bfa22985aded48a49581e31b568a60aa09e25f73462e700e7d", + "checks": { + "expected_sha256": "4ea6952590d070bfa22985aded48a49581e31b568a60aa09e25f73462e700e7d", + "last_checked_at": "2026-07-12T02:18:30Z" + }, "counts": { "books": 66, "verses": 31102, @@ -86,10 +171,12 @@ "files": { "verses_jsonl": { "path": "verses.jsonl", + "bytes": 8700726, "sha256": "e3102f854a99c4788ed259ec61cb93fea830845c0788c8c0929bc77e9db6ca10" }, "strongs_jsonl": { "path": "strongs-links.jsonl", + "bytes": 62690394, "sha256": "fa9702224776509275ea17fb245cb72150f1c262c4fbe44c7161e8e83866c779" } } diff --git a/scripts/import-usfm.js b/scripts/import-usfm.js index 7341cf2..3e393e7 100644 --- a/scripts/import-usfm.js +++ b/scripts/import-usfm.js @@ -1,5 +1,5 @@ import AdmZip from 'adm-zip' -import { mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import { mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises' import path from 'node:path' import { cleanUsfmText, @@ -110,50 +110,85 @@ await writeFile( 'utf8', ) +const versesPackage = await packageFile(outputDir, 'verses.jsonl') +const strongsPackage = await packageFile(outputDir, 'strongs-links.jsonl') + const catalog = { + schema_version: 'librebible.resource-catalog.v1', + project: manifest.project_name ?? 'LibreBible', id: manifest.id, + resource_type: manifest.resource_type, title: manifest.title, + short_title: manifest.short_title, abbreviation: manifest.abbreviation, + alternate_ids: manifest.alternate_ids ?? [], language: manifest.language, + script: manifest.script, + canon: manifest.canon, + translation: manifest.translation, + contributors: manifest.contributors ?? [], features: manifest.features, + attachments: manifest.attachments, source: manifest.source, license: manifest.license, + catalog_display: manifest.catalog_display, importer: manifest.importer, generated_at: new Date().toISOString(), source_sha256: archiveSha, + checks: manifest.checks, counts: { books: new Set(verses.map((verse) => verse.book_id)).size, verses: verses.length, strongs_links: strongsLinks.length, }, files: { - verses_jsonl: { - path: 'verses.jsonl', - sha256: await sha256File(path.join(outputDir, 'verses.jsonl')), - }, - strongs_jsonl: { - path: 'strongs-links.jsonl', - sha256: await sha256File(path.join(outputDir, 'strongs-links.jsonl')), - }, + verses_jsonl: versesPackage, + strongs_jsonl: strongsPackage, }, } await writeJson(path.join(outputDir, 'catalog.json'), catalog) await writeJson(path.join(root, 'packages', 'json', 'catalog.json'), { + schema_version: 'librebible.index-catalog.v1', + project: manifest.project_name ?? 'LibreBible', generated_at: catalog.generated_at, resources: [ { id: catalog.id, + resource_type: catalog.resource_type, title: catalog.title, + short_title: catalog.short_title, abbreviation: catalog.abbreviation, + alternate_ids: catalog.alternate_ids, language: catalog.language, + script: catalog.script, + canon: catalog.canon, + translation: catalog.translation, + contributors: catalog.contributors, features: catalog.features, + attachments: catalog.attachments, + source: catalog.source, license: catalog.license, + catalog_display: catalog.catalog_display, package_path: `packages/json/${catalog.id}/catalog.json`, + source_manifest_path: `sources/${path.basename(manifestPath)}`, + detail_doc_path: `docs/resources/${catalog.id}.md`, counts: catalog.counts, + files: catalog.files, + checks: catalog.checks, }, ], }) console.log(`${manifest.id}: imported ${catalog.counts.verses} verses`) console.log(`${manifest.id}: imported ${catalog.counts.strongs_links} Strong's links`) + +async function packageFile(outputDir, fileName) { + const filePath = path.join(outputDir, fileName) + const fileStat = await stat(filePath) + return { + path: fileName, + bytes: fileStat.size, + sha256: await sha256File(filePath), + } +}