From f62b203bebdec1de31991f198904a10b7cd73e62 Mon Sep 17 00:00:00 2001 From: Ivan Date: Fri, 10 Jul 2026 13:02:33 -0500 Subject: [PATCH] refactor(docs): update Reticulum manual fetching process to remove GitHub update functionality and ensure build-time fetching with --force option --- docs/en/installation.md | 4 +- meshchatx/meshchat.py | 21 --- meshchatx/src/backend/docs_manager.py | 63 +-------- .../src/frontend/components/docs/DocsPage.vue | 120 ++++++------------ meshchatx/src/frontend/locales/de.json | 7 +- meshchatx/src/frontend/locales/en.json | 13 +- meshchatx/src/frontend/locales/es.json | 7 +- meshchatx/src/frontend/locales/fi.json | 7 +- meshchatx/src/frontend/locales/fr.json | 7 +- meshchatx/src/frontend/locales/it.json | 7 +- meshchatx/src/frontend/locales/nl.json | 7 +- meshchatx/src/frontend/locales/ru.json | 7 +- meshchatx/src/frontend/locales/zh.json | 7 +- .../public/meshchatx-docs/en/installation.md | 4 +- package.json | 2 +- scripts/build/fetch_reticulum_manual.py | 2 +- scripts/build/reticulum_docs_bundle.json | 6 +- tests/backend/fixtures/http_api_routes.json | 4 - tests/backend/test_docs_manager.py | 44 ------- 19 files changed, 59 insertions(+), 280 deletions(-) diff --git a/docs/en/installation.md b/docs/en/installation.md index 2d55425a..0204cf0e 100644 --- a/docs/en/installation.md +++ b/docs/en/installation.md @@ -126,13 +126,13 @@ CLI flags override environment variables when both are set. ## Reticulum manual bundle -The Reticulum HTML manual is fetched at build time. After cloning the repository, run: +The Reticulum HTML manual is fetched from the upstream website **master** branch at build time. There is no in-app clearnet refresh. After cloning the repository, or before packaging a release, run: ```bash pnpm run build-docs ``` -This populates `meshchatx/public/reticulum-docs-bundled/current/`. Without that step the Reticulum tab may show an upload prompt until you build docs or upload a manual ZIP. +That command always re-fetches (`--force`) into `meshchatx/public/reticulum-docs-bundled/current/`. CI release builds run the same step. Without a bundled copy the Reticulum tab may show an upload prompt until you build docs or upload a manual ZIP offline. ## Identity bootstrap diff --git a/meshchatx/meshchat.py b/meshchatx/meshchat.py index aa4f0f72..85f79448 100644 --- a/meshchatx/meshchat.py +++ b/meshchatx/meshchat.py @@ -7808,27 +7808,6 @@ class ReticulumMeshChat: except Exception as e: return web.json_response({"error": str(e)}, status=500) - # pull latest Reticulum manual from GitHub - @routes.post("/api/v1/docs/update-from-github") - async def docs_update_from_github(request): - try: - self._require_outbound_http("Reticulum docs update") - if not self.docs_manager: - return web.json_response( - {"error": "Documentation manager is unavailable"}, - status=503, - ) - loop = asyncio.get_running_loop() - success, version = await loop.run_in_executor( - None, - self.docs_manager.update_from_github, - ) - return web.json_response({"success": success, "version": version}) - except OutboundHttpBlockedError as e: - return web.json_response({"error": str(e)}, status=403) - except Exception as e: - return web.json_response({"error": str(e)}, status=500) - # switch docs version @routes.post("/api/v1/docs/switch") async def docs_switch(request): diff --git a/meshchatx/src/backend/docs_manager.py b/meshchatx/src/backend/docs_manager.py index 4bbf3274..c593e4b9 100644 --- a/meshchatx/src/backend/docs_manager.py +++ b/meshchatx/src/backend/docs_manager.py @@ -7,10 +7,6 @@ import logging import os import re import shutil -import time -import urllib.error -import urllib.parse -import urllib.request import zipfile from meshchatx.src.backend.markdown_renderer import MarkdownRenderer @@ -18,16 +14,6 @@ from meshchatx.src.backend.markdown_renderer import MarkdownRenderer BUNDLED_DOCS_SUBDIR = os.path.join("reticulum-docs-bundled", "current") MANIFEST_FILENAME = "manifest.json" DOC_FILE_SUFFIXES = (".md", ".txt") -RETICULUM_DOCS_GITHUB_URL = ( - "https://github.com/markqvist/reticulum_website/archive/refs/heads/main.zip" -) -RETICULUM_DOCS_ALLOWED_HOSTS = frozenset( - { - "github.com", - "codeload.github.com", - "objects.githubusercontent.com", - } -) class DocsManager: @@ -37,9 +23,8 @@ class DocsManager: ``/reticulum-docs-bundled/current``. Users may upload a replacement archive which is extracted into ``/reticulum-docs`` and takes precedence at request time. Removing the user upload restores the - bundled copy. Users can also pull the latest upstream ZIP from GitHub at - runtime (blocked when privacy mode is enabled). Build-time staging still - uses ``scripts/build/fetch_reticulum_manual.py``. + bundled copy. There is no runtime download path. Fresh manuals are staged at + build time with ``scripts/build/fetch_reticulum_manual.py`` (``pnpm run build-docs``). """ def __init__(self, config, public_dir, project_root=None, storage_dir=None): @@ -838,50 +823,6 @@ class DocsManager: logging.exception(f"Failed to upload docs: {e}") return False - @staticmethod - def _resolve_docs_source_url(source_url=None): - url = ( - source_url - or os.environ.get("MESHCHATX_RETICULUM_DOCS_URL") - or RETICULUM_DOCS_GITHUB_URL - ).strip() - if not url.lower().startswith("https://"): - raise ValueError("docs source URL must be https") - host = urllib.parse.urlparse(url).hostname or "" - host = host.lower() - if host not in RETICULUM_DOCS_ALLOWED_HOSTS and not host.endswith( - ".githubusercontent.com" - ): - raise ValueError(f"docs source host not allowed: {host}") - return url - - def update_from_github(self, version=None, source_url=None, timeout=120.0): - """Download the Reticulum website docs ZIP and install it as a version.""" - url = self._resolve_docs_source_url(source_url) - if not version: - version = f"github-{time.strftime('%Y%m%d-%H%M%S')}" - - self.upload_status = "downloading" - self.upload_progress = 0 - self.last_error = None - - try: - req = urllib.request.Request( - url, - headers={"User-Agent": "MeshChatX-docs-update"}, - ) - with urllib.request.urlopen(req, timeout=timeout) as response: - zip_bytes = response.read() - if not zip_bytes: - raise ValueError("downloaded archive is empty") - success = self.upload_zip(zip_bytes, version) - return success, version - except Exception as e: - self.last_error = str(e) - self.upload_status = "error" - logging.exception(f"Failed to update docs from GitHub: {e}") - raise - def _extract_docs(self, zip_path, version): safe_version = os.path.basename(version) if not safe_version or safe_version in (".", ".."): diff --git a/meshchatx/src/frontend/components/docs/DocsPage.vue b/meshchatx/src/frontend/components/docs/DocsPage.vue index e4c08c9d..60ceeefc 100644 --- a/meshchatx/src/frontend/components/docs/DocsPage.vue +++ b/meshchatx/src/frontend/components/docs/DocsPage.vue @@ -186,22 +186,6 @@ - - - - - + @@ -699,7 +683,7 @@ export default { selectedDocPath: null, selectedDocContent: null, selectedReticulumPath: null, - githubUpdatePending: false, + reticulumDocsCacheBust: 0, languages: { en: "English", de: "Deutsch", @@ -719,10 +703,17 @@ export default { return this.$i18n.locale; }, localDocsUrl() { + let path; if (this.selectedReticulumPath) { - return `/reticulum-docs/${this.selectedReticulumPath}`; + path = `/reticulum-docs/${this.selectedReticulumPath}`; + } else { + path = bundledReticulumDocsUrl(this.currentLang); } - return bundledReticulumDocsUrl(this.currentLang); + if (this.reticulumDocsCacheBust) { + const sep = path.includes("?") ? "&" : "?"; + return `${path}${sep}v=${this.reticulumDocsCacheBust}`; + } + return path; }, allLanguages() { return Object.entries(this.languages).map(([code, name]) => ({ @@ -737,11 +728,6 @@ export default { reticulumDocsQueryParam() { return this.$route?.query?.reticulum; }, - docsBusy() { - return ( - this.githubUpdatePending || this.status.status === "downloading" || this.status.status === "extracting" - ); - }, visibleDocSections() { const lang = this.meshchatxDocsLang; const fallback = this.defaultDocsLanguage || "en"; @@ -963,6 +949,7 @@ export default { } ); this.fetchStatus(); + this.reticulumDocsCacheBust = Date.now(); ToastUtils.success(this.$t("docs.upload_success")); } catch (error) { console.error("Failed to upload docs zip:", error); @@ -970,37 +957,6 @@ export default { DialogUtils.alert(this.$t("docs.failed_upload_alert", { message }), "error"); } }, - async updateFromGithub() { - if (this.docsBusy) { - return; - } - this.githubUpdatePending = true; - this.status = { - ...this.status, - status: "downloading", - progress: 0, - last_error: null, - }; - try { - const response = await window.api.post("/api/v1/docs/update-from-github"); - const version = response.data?.version; - await this.fetchStatus(); - this.activeTab = "reticulum"; - this.selectedReticulumPath = null; - ToastUtils.success( - version - ? this.$t("docs.update_github_success_version", { version }) - : this.$t("docs.update_github_success") - ); - } catch (error) { - console.error("Failed to update docs from GitHub:", error); - const message = error.response?.data?.error || error.message || ""; - DialogUtils.alert(this.$t("docs.failed_update_github", { message }), "error"); - await this.fetchStatus(); - } finally { - this.githubUpdatePending = false; - } - }, async exportDocs() { window.location.href = "/api/v1/docs/export"; }, diff --git a/meshchatx/src/frontend/locales/de.json b/meshchatx/src/frontend/locales/de.json index de4c7577..f5dd11a4 100644 --- a/meshchatx/src/frontend/locales/de.json +++ b/meshchatx/src/frontend/locales/de.json @@ -1967,19 +1967,14 @@ "prompt_version_name": "Versionsname für diesen Upload eingeben:", "status_title": "Dokumentationsstatus", "status_extracting": "Wird entpackt...", - "status_downloading": "Dokumentation wird heruntergeladen...", "status_available": "Offline-Handbuch verfügbar", "status_not_available": "Handbuch nicht verfügbar", "btn_upload": "Handbuch hochladen", - "btn_update_github": "Von GitHub aktualisieren", "btn_share": "Reticulum-Handbuch als wieder hochladbares ZIP teilen", - "empty_state_hint": "Lade das neueste Reticulum-Handbuch von GitHub, oder lade ein ZIP hoch, um es offline anzuzeigen.", + "empty_state_hint": "Lade ein ZIP des Reticulum-Handbuchs hoch, um es offline anzuzeigen. Releases enthalten eine gebündelte Offline-Kopie aus dem Build.", "error": "Fehler", "failed_upload_docs": "Hochladen der Dokumentation fehlgeschlagen", "upload_success": "Dokumentation hochgeladen", - "update_github_success": "Reticulum-Handbuch von GitHub aktualisiert", - "update_github_success_version": "Reticulum-Handbuch aktualisiert ({version})", - "failed_update_github": "Aktualisierung von GitHub fehlgeschlagen: {message}", "docs_link_copied": "Dokumentationslink in Zwischenablage kopiert", "failed_copy_link": "Link kopieren fehlgeschlagen", "load_list_failed": "Anleitungsliste konnte nicht geladen werden. Bitte später erneut versuchen.", diff --git a/meshchatx/src/frontend/locales/en.json b/meshchatx/src/frontend/locales/en.json index b5ef2c78..395973a3 100644 --- a/meshchatx/src/frontend/locales/en.json +++ b/meshchatx/src/frontend/locales/en.json @@ -2087,23 +2087,14 @@ "status_available": "Offline Manual Available", "status_not_available": "Manual Not Available", "btn_upload": "Upload Manual", - "btn_update_github": "Update from GitHub", - "btn_share": "Share Reticulum manual as a re-uploadable ZIP", - "empty_state_hint": "Pull the latest Reticulum manual from GitHub, or upload a ZIP to view it offline.", - "error": "Error", - "failed_upload_docs": "Failed to upload documentation", - "upload_success": "Documentation uploaded", - "update_github_success": "Reticulum manual updated from GitHub", - "update_github_success_version": "Reticulum manual updated ({version})", - "failed_update_github": "Failed to update from GitHub: {message}", - "status_downloading": "Downloading Documentation...", "docs_link_copied": "Documentation link copied to clipboard", "failed_copy_link": "Failed to copy link", "load_list_failed": "Could not load the guide list. Try again in a moment.", "load_doc_failed": "Could not load this guide.", "search_failed": "Search failed. Check your connection and try again.", "manifest_warning": "The documentation index file could not be read. Showing available files without section grouping.", - "failed_upload_alert": "Failed to upload documentation: {message}" + "failed_upload_alert": "Failed to upload documentation: {message}", + "empty_state_hint": "Upload a Reticulum manual ZIP to view it offline. Releases ship a bundled offline copy built at packaging time." }, "licenses": { "section_label": "Legal", diff --git a/meshchatx/src/frontend/locales/es.json b/meshchatx/src/frontend/locales/es.json index cc6aa30b..cb42a768 100644 --- a/meshchatx/src/frontend/locales/es.json +++ b/meshchatx/src/frontend/locales/es.json @@ -2084,19 +2084,14 @@ "prompt_version_name": "Introduce un nombre de versión para esta subida:", "status_title": "Situación de la documentación", "status_extracting": "Extrayendo...", - "status_downloading": "Descargando documentación...", "status_available": "Manual disponible", "status_not_available": "Manual no disponible", "btn_upload": "Subir Manual", - "btn_update_github": "Actualizar desde GitHub", "btn_share": "Compartir el manual de Reticulum como ZIP reimportable", - "empty_state_hint": "Descarga el manual de Reticulum más reciente desde GitHub, o sube un ZIP para verlo sin conexión.", + "empty_state_hint": "Sube un ZIP del manual de Reticulum para consultarlo sin conexión. Las versiones incluyen una copia sin conexión empaquetada en el build.", "error": "Error", "failed_upload_docs": "Error al subir la documentación", "upload_success": "Documentación subida", - "update_github_success": "Manual de Reticulum actualizado desde GitHub", - "update_github_success_version": "Manual de Reticulum actualizado ({version})", - "failed_update_github": "Error al actualizar desde GitHub: {message}", "docs_link_copied": "Enlace de documentación copiado al portapapeles", "failed_copy_link": "No se pudo copiar el enlace", "load_list_failed": "No se pudo cargar la lista de guías. Inténtalo de nuevo en un momento.", diff --git a/meshchatx/src/frontend/locales/fi.json b/meshchatx/src/frontend/locales/fi.json index 4333435f..961e6a78 100644 --- a/meshchatx/src/frontend/locales/fi.json +++ b/meshchatx/src/frontend/locales/fi.json @@ -2084,19 +2084,14 @@ "prompt_version_name": "Anna tälle lataukselle version nimi:", "status_title": "Dokumentaation tila", "status_extracting": "Viedään dokumentaatiota...", - "status_downloading": "Ladataan dokumentaatiota...", "status_available": "Paikallinen ohjekirja saatavilla", "status_not_available": "Ohjekirja ei ole saatavilla", "btn_upload": "Tuo ohjekirja", - "btn_update_github": "Päivitä GitHubista", "btn_share": "Jaa Reticulum-ohjekirja ZIP-tiedostona, jonka voi myöhemmin tuoda sovellukseen", - "empty_state_hint": "Hae uusin Reticulum-ohjekirja GitHubista tai tuo ZIP paikallista käyttöä varten.", + "empty_state_hint": "Tuo Reticulum-ohjekirjan ZIP paikallista käyttöä varten. Julkaisut sisältävät buildissa pakatun offline-kopion.", "error": "Virhe", "failed_upload_docs": "Dokumentaation tuominen epäonnistui", "upload_success": "Dokumentaatio ladattu", - "update_github_success": "Reticulum-ohjekirja päivitetty GitHubista", - "update_github_success_version": "Reticulum-ohjekirja päivitetty ({version})", - "failed_update_github": "Päivitys GitHubista epäonnistui: {message}", "docs_link_copied": "Dokumentaation linkki kopioitu leikepöydälle", "failed_copy_link": "Linkin kopiointi epäonnistui", "load_list_failed": "Ohjeluetteloa ei voitu ladata. Yritä hetken kuluttua uudelleen.", diff --git a/meshchatx/src/frontend/locales/fr.json b/meshchatx/src/frontend/locales/fr.json index 35719f14..f6c3b860 100644 --- a/meshchatx/src/frontend/locales/fr.json +++ b/meshchatx/src/frontend/locales/fr.json @@ -2084,19 +2084,14 @@ "prompt_version_name": "Entrez un nom de version pour ce téléversement :", "status_title": "État de la documentation", "status_extracting": "Extraction...", - "status_downloading": "Téléchargement de la documentation...", "status_available": "Manuel hors ligne disponible", "status_not_available": "Manuel non disponible", "btn_upload": "Téléverser le manuel", - "btn_update_github": "Mettre à jour depuis GitHub", "btn_share": "Partager le manuel Reticulum sous forme de ZIP réimportable", - "empty_state_hint": "Récupérez le dernier manuel Reticulum depuis GitHub, ou téléversez une archive ZIP pour le consulter hors ligne.", + "empty_state_hint": "Téléversez une archive ZIP du manuel Reticulum pour la consulter hors ligne. Les versions livrent une copie hors ligne intégrée au build.", "error": "Erreur", "failed_upload_docs": "Échec du téléversement de la documentation", "upload_success": "Documentation téléversée", - "update_github_success": "Manuel Reticulum mis à jour depuis GitHub", - "update_github_success_version": "Manuel Reticulum mis à jour ({version})", - "failed_update_github": "Échec de la mise à jour depuis GitHub : {message}", "docs_link_copied": "Lien de documentation copié dans le presse-papiers", "failed_copy_link": "Impossible de copier le lien", "load_list_failed": "Impossible de charger la liste des guides. Réessayez dans un instant.", diff --git a/meshchatx/src/frontend/locales/it.json b/meshchatx/src/frontend/locales/it.json index d7758794..f33e9b0b 100644 --- a/meshchatx/src/frontend/locales/it.json +++ b/meshchatx/src/frontend/locales/it.json @@ -2136,19 +2136,14 @@ "prompt_version_name": "Inserisci un nome di versione per questo caricamento:", "status_title": "Stato Documentazione", "status_extracting": "Estrazione in corso...", - "status_downloading": "Download della documentazione...", "status_available": "Manuale Offline Disponibile", "status_not_available": "Manuale Non Disponibile", "btn_upload": "Carica Manuale", - "btn_update_github": "Aggiorna da GitHub", "btn_share": "Condividi il manuale Reticulum come ZIP ricaricabile", - "empty_state_hint": "Scarica l'ultimo manuale Reticulum da GitHub, oppure carica uno ZIP per consultarlo offline.", + "empty_state_hint": "Carica uno ZIP del manuale Reticulum per consultarlo offline. Le release includono una copia offline inclusa nel build.", "error": "Errore", "failed_upload_docs": "Caricamento della documentazione non riuscito", "upload_success": "Documentazione caricata", - "update_github_success": "Manuale Reticulum aggiornato da GitHub", - "update_github_success_version": "Manuale Reticulum aggiornato ({version})", - "failed_update_github": "Aggiornamento da GitHub non riuscito: {message}", "docs_link_copied": "Link alla documentazione copiato negli appunti", "failed_copy_link": "Impossibile copiare il link", "load_list_failed": "Impossibile caricare l'elenco delle guide. Riprova tra un momento.", diff --git a/meshchatx/src/frontend/locales/nl.json b/meshchatx/src/frontend/locales/nl.json index dedbba5c..9f70b2af 100644 --- a/meshchatx/src/frontend/locales/nl.json +++ b/meshchatx/src/frontend/locales/nl.json @@ -2084,19 +2084,14 @@ "prompt_version_name": "Voer een versienaam in voor deze upload:", "status_title": "Documentatiestatus", "status_extracting": "Uitpakken...", - "status_downloading": "Documentatie downloaden...", "status_available": "Offline handleiding beschikbaar", "status_not_available": "Handleiding niet beschikbaar", "btn_upload": "Handleiding uploaden", - "btn_update_github": "Bijwerken vanaf GitHub", "btn_share": "Reticulum-handleiding delen als opnieuw uploadbare ZIP", - "empty_state_hint": "Haal de nieuwste Reticulum-handleiding van GitHub, of upload een ZIP om deze offline te bekijken.", + "empty_state_hint": "Upload een ZIP van de Reticulum-handleiding om deze offline te bekijken. Releases bevatten een gebundelde offline kopie uit de build.", "error": "Fout", "failed_upload_docs": "Documentatie uploaden mislukt", "upload_success": "Documentatie geüpload", - "update_github_success": "Reticulum-handleiding bijgewerkt vanaf GitHub", - "update_github_success_version": "Reticulum-handleiding bijgewerkt ({version})", - "failed_update_github": "Bijwerken vanaf GitHub mislukt: {message}", "docs_link_copied": "Documentatiekoppeling gekopieerd naar klembord", "failed_copy_link": "Kopiëren van verwijzing is mislukt", "load_list_failed": "Kan de gidsenlijst niet laden. Probeer het zo opnieuw.", diff --git a/meshchatx/src/frontend/locales/ru.json b/meshchatx/src/frontend/locales/ru.json index 1cbd69a4..159f1e55 100644 --- a/meshchatx/src/frontend/locales/ru.json +++ b/meshchatx/src/frontend/locales/ru.json @@ -1967,19 +1967,14 @@ "prompt_version_name": "Введите имя версии для этой загрузки:", "status_title": "Статус документации", "status_extracting": "Извлечение...", - "status_downloading": "Загрузка документации...", "status_available": "Доступно офлайн", "status_not_available": "Руководство недоступно", "btn_upload": "Загрузить руководство", - "btn_update_github": "Обновить с GitHub", "btn_share": "Поделиться руководством Reticulum как загружаемым ZIP", - "empty_state_hint": "Загрузите актуальное руководство Reticulum с GitHub или загрузите ZIP для офлайн-просмотра.", + "empty_state_hint": "Загрузите ZIP руководства Reticulum для офлайн-просмотра. В релизах есть встроенная офлайн-копия из сборки.", "error": "Ошибка", "failed_upload_docs": "Не удалось загрузить документацию", "upload_success": "Документация загружена", - "update_github_success": "Руководство Reticulum обновлено с GitHub", - "update_github_success_version": "Руководство Reticulum обновлено ({version})", - "failed_update_github": "Не удалось обновить с GitHub: {message}", "docs_link_copied": "Ссылка на документацию скопирована в буфер обмена", "failed_copy_link": "Не удалось скопировать ссылку", "load_list_failed": "Не удалось загрузить список справок. Повторите попытку позже.", diff --git a/meshchatx/src/frontend/locales/zh.json b/meshchatx/src/frontend/locales/zh.json index 7c146be4..d8ba3df2 100644 --- a/meshchatx/src/frontend/locales/zh.json +++ b/meshchatx/src/frontend/locales/zh.json @@ -2084,19 +2084,14 @@ "prompt_version_name": "为此上传输入版本名称:", "status_title": "文件状况", "status_extracting": "正在解压...", - "status_downloading": "正在下载文档...", "status_available": "离线手册可用", "status_not_available": "手册不可用", "btn_upload": "上传手册", - "btn_update_github": "从 GitHub 更新", "btn_share": "以可重新上传的 ZIP 共享 Reticulum 手册", - "empty_state_hint": "从 GitHub 拉取最新 Reticulum 手册,或上传 ZIP 以便离线查看。", + "empty_state_hint": "上传 Reticulum 手册 ZIP 以便离线查看。发行版在构建时打包离线副本。", "error": "错误", "failed_upload_docs": "上传文档失败", "upload_success": "文档已上传", - "update_github_success": "已从 GitHub 更新 Reticulum 手册", - "update_github_success_version": "已更新 Reticulum 手册({version})", - "failed_update_github": "从 GitHub 更新失败:{message}", "docs_link_copied": "复制到剪贴板的文档链接", "failed_copy_link": "复制链接失败", "load_list_failed": "无法加载指南列表。请稍后再试。", diff --git a/meshchatx/src/frontend/public/meshchatx-docs/en/installation.md b/meshchatx/src/frontend/public/meshchatx-docs/en/installation.md index 2d55425a..0204cf0e 100644 --- a/meshchatx/src/frontend/public/meshchatx-docs/en/installation.md +++ b/meshchatx/src/frontend/public/meshchatx-docs/en/installation.md @@ -126,13 +126,13 @@ CLI flags override environment variables when both are set. ## Reticulum manual bundle -The Reticulum HTML manual is fetched at build time. After cloning the repository, run: +The Reticulum HTML manual is fetched from the upstream website **master** branch at build time. There is no in-app clearnet refresh. After cloning the repository, or before packaging a release, run: ```bash pnpm run build-docs ``` -This populates `meshchatx/public/reticulum-docs-bundled/current/`. Without that step the Reticulum tab may show an upload prompt until you build docs or upload a manual ZIP. +That command always re-fetches (`--force`) into `meshchatx/public/reticulum-docs-bundled/current/`. CI release builds run the same step. Without a bundled copy the Reticulum tab may show an upload prompt until you build docs or upload a manual ZIP offline. ## Identity bootstrap diff --git a/package.json b/package.json index 9774e84e..2dea7751 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "predev": "node scripts/sync-meshchatx-docs.js", "build-frontend": "vite build", "build-backend": "node scripts/build-backend.js", - "build-docs": "python3 scripts/build/fetch_reticulum_manual.py", + "build-docs": "python3 scripts/build/fetch_reticulum_manual.py --force", "build-repository-wheels": "python3 scripts/build/fetch_repository_wheels.py", "version:sync": "node scripts/sync_version.js", "build": "pnpm run version:sync && pnpm run build-frontend && pnpm run build-docs && pnpm run build-repository-wheels && pnpm run build-backend", diff --git a/scripts/build/fetch_reticulum_manual.py b/scripts/build/fetch_reticulum_manual.py index 7c96696d..e53d4bf1 100755 --- a/scripts/build/fetch_reticulum_manual.py +++ b/scripts/build/fetch_reticulum_manual.py @@ -39,7 +39,7 @@ from datetime import UTC, datetime from pathlib import Path DEFAULT_SOURCES = ( - "https://github.com/markqvist/reticulum_website/archive/refs/heads/main.zip", + "https://codeload.github.com/markqvist/reticulum_website/zip/refs/heads/master", ) DEFAULT_DEST = ( diff --git a/scripts/build/reticulum_docs_bundle.json b/scripts/build/reticulum_docs_bundle.json index ee876ddb..dded1e5f 100644 --- a/scripts/build/reticulum_docs_bundle.json +++ b/scripts/build/reticulum_docs_bundle.json @@ -1,7 +1,7 @@ { "dest": "meshchatx/public/reticulum-docs-bundled/current", - "fetched_utc": "2026-07-07T05:31:03Z", - "html_files": 201, + "fetched_utc": "2026-07-10T17:45:25Z", + "html_files": 206, "skipped_binary_files": 2, - "source_url": "https://github.com/markqvist/reticulum_website/archive/refs/heads/main.zip" + "source_url": "https://codeload.github.com/markqvist/reticulum_website/zip/refs/heads/master" } diff --git a/tests/backend/fixtures/http_api_routes.json b/tests/backend/fixtures/http_api_routes.json index 80d63f75..6d686ebd 100644 --- a/tests/backend/fixtures/http_api_routes.json +++ b/tests/backend/fixtures/http_api_routes.json @@ -268,10 +268,6 @@ "method": "POST", "path": "/api/v1/docs/upload" }, - { - "method": "POST", - "path": "/api/v1/docs/update-from-github" - }, { "method": "DELETE", "path": "/api/v1/docs/version/{version}" diff --git a/tests/backend/test_docs_manager.py b/tests/backend/test_docs_manager.py index 6a703f1c..5bf1eafc 100644 --- a/tests/backend/test_docs_manager.py +++ b/tests/backend/test_docs_manager.py @@ -544,47 +544,3 @@ def test_get_doc_content_returns_none_on_read_error(tmp_path, monkeypatch): monkeypatch.setattr("builtins.open", fail_open) assert dm.get_doc_content("en/guide.md") is None - - -def test_resolve_docs_source_url_rejects_non_https(): - with pytest.raises(ValueError, match="https"): - DocsManager._resolve_docs_source_url( - "http://github.com/markqvist/reticulum_website/archive/refs/heads/main.zip" - ) - - -def test_resolve_docs_source_url_rejects_unknown_host(): - with pytest.raises(ValueError, match="not allowed"): - DocsManager._resolve_docs_source_url("https://evil.example/docs.zip") - - -def test_update_from_github_downloads_and_installs(docs_manager, monkeypatch): - payload = _make_docs_zip( - files={ - "reticulum_website-main/docs/index.html": "github", - }, - ) - - class FakeResponse: - def __enter__(self): - return self - - def __exit__(self, *_args): - return False - - def read(self): - return payload - - monkeypatch.setattr( - "meshchatx.src.backend.docs_manager.urllib.request.urlopen", - lambda *_args, **_kwargs: FakeResponse(), - ) - - success, version = docs_manager.update_from_github(version="github-test") - assert success is True - assert version == "github-test" - assert docs_manager.upload_status == "completed" - resolved = docs_manager.find_docs_file("index.html") - assert resolved is not None - with open(resolved) as fh: - assert "github" in fh.read()