diff --git a/BUILD-AND-DEPLOY.md b/BUILD-AND-DEPLOY.md index 3c7556b..0bc6e83 100644 --- a/BUILD-AND-DEPLOY.md +++ b/BUILD-AND-DEPLOY.md @@ -127,6 +127,9 @@ never enters the repo), build the regular installer, then: node tools/build-full-installer.cjs ``` +This builds on the laptop too: 7-Zip only packs the payload, and the Windows SFX stub is concatenated +onto it byte-for-byte, so the host platform makes no difference to the result. + Machines that already have the model keep using the regular installer. ## 6. Git diff --git a/UPDATES.md b/UPDATES.md index 9b4eba8..a9e7dce 100644 --- a/UPDATES.md +++ b/UPDATES.md @@ -1,58 +1,30 @@ # Updating the Bible App -The app updates itself from **a folder you control** — a network share, a folder on this PC, a USB -drive, or a small web server. No GitHub, no app store, no internet required (a network share is -enough). +The app updates itself from **a source you control** — the church's own Gitea server, a network +share, a folder on this PC, or any small web server. No GitHub, no app store, nothing leaves the +building. --- ## One-time setup (per installed machine) 1. Open the app → **menu (☰) → Settings → Updates** -2. Put your update location in **Update folder or address**, for example: - - `\\WATERS-SERVER\builds\bible-app` (network share — recommended) - - `D:\BibleAppBuilds` (folder on this PC) - - `http://server.local/bible-app` (web server) -3. Leave **“Check for updates automatically when the app starts”** ticked. +2. Put the update source in **Update folder or address**. The church's is: + + ``` + http://chronicles-ab.waterschurch.org:3000/api/packages/christian/generic/bible-app/latest + ``` + + Anything else the app accepts also works: `\\WATERS-SERVER\builds\bible-app` (network share), + `D:\BibleAppBuilds` (folder on this PC), `http://server.local/bible-app` (web server). +3. Leave **"Check for updates automatically when the app starts"** ticked. 4. Click **Save**. That's it. From now on the stage PC never needs a hand-carried .exe. ---- - -## Publishing a new version (on the dev machine) - -```bash -# 1. bump the version in package.json (e.g. 1.4.0 -> 1.4.1) -# 2. build + publish in one step: -npm run release -``` - -That produces the regular ~300 MB installer and publishes it — this is what existing machines -download. To also make the one-file installer for a **new** machine (app + AI model in a single -2.2 GB .exe), run this afterwards: - -```bash -node tools/build-full-installer.cjs -``` - -It lands in `dist-installer/Bible App Full Setup .exe`. You only need it when setting up a -PC that has never had the app. - -`npm run release` builds the installer and copies it, plus a `latest.json` manifest, into the update -folder. To publish somewhere specific, or to add release notes the operator will see: - -```bash -npm run publish-update -- "\\WATERS-SERVER\builds\bible-app" "Faster laser, new popup cards" -``` - -Publish destination is chosen in this order: -1. the path you pass on the command line -2. the `BIBLEAPP_UPDATE_DIR` environment variable -3. the folder configured in the app on this machine -4. `dist-installer/publish` (fallback) - -The script keeps the 3 most recent installers in that folder and deletes older ones. +> **Checking is automatic; installing is not.** With that box ticked the app asks the server at +> startup and remembers the answer, which Settings → Updates then shows. It never installs on its +> own — installing closes and reopens the app, so it stays a deliberate tap. --- @@ -60,7 +32,7 @@ The script keeps the 3 most recent installers in that folder and deletes older o 1. **Settings → Updates → Check for Updates** 2. If a new version exists it shows the version number and notes → **Download & Install** -3. A progress bar runs while the installer copies (~1.4 GB, fast over a LAN) +3. A progress bar runs while the installer downloads (~750 MB, a couple of minutes over the LAN) 4. The app closes, the installer runs, and the app reopens **Everything is kept:** notes, graphics, announcements, maps, annotations, service profiles, @@ -71,27 +43,62 @@ folder, which the installer never touches. --- +## Publishing a new version (on the laptop) + +```bash +npm run release -- "Faster laser, new popup cards" +git commit -am "Release " && git push +``` + +That bumps the patch version, builds the Windows installer, uploads it and a `latest.json` manifest +to the update source, and clears out builds older than the previous one. The Windows installer builds +on the Mac — see BUILD-AND-DEPLOY.md. + +To publish an existing build, or to publish somewhere other than the default: + +```bash +npm run publish-update # newest build -> default target +npm run publish-update -- "\\WATERS-SERVER\builds\bible-app" "Notes" +``` + +Publish destination is chosen in this order: + +1. the path or URL you pass on the command line +2. the `BIBLEAPP_UPDATE_DIR` environment variable +3. `bibleApp.updateTarget` in `package.json` (the church's Gitea registry) +4. the source configured in the app on this machine +5. `dist-installer/publish` (fallback) + +Uploading to Gitea needs a token — `GITEA_TOKEN`, or the macOS keychain item `gitea-mcp` that the +git tooling already uses. Downloading does not: the published installer is readable without a +login, which is what lets the TV fetch it. The source repository stays private. + +--- + ## What `latest.json` looks like The publish script writes it for you; you only need this if you're placing a build by hand: ```json { - "version": "1.4.1", - "file": "Bible App Setup 1.4.1.exe", + "version": "1.4.35", + "file": "Bible App Setup 1.4.35.exe", + "size": 784268993, + "sha256": "7a628d27…", "notes": "What changed in this version", - "date": "2026-08-12" + "date": "2026-09-24" } ``` -Both the `.exe` and `latest.json` must sit in the same folder. Version numbers are compared -numerically, so `1.4.10` correctly beats `1.4.9`. +Both the `.exe` and `latest.json` must sit in the same place. Version numbers are compared +numerically, so `1.4.10` correctly beats `1.4.9` — and the app only ever offers a HIGHER version, +so re-publishing the same version number is invisible to it. --- ## Setting up a brand-new machine — one file -Use **`Bible App Full Setup .exe`** (about 2.2 GB). It is a single self-extracting file +Use **`Bible App Full Setup .exe`** (about 2.7 GB). It is a single self-extracting file containing the app *and* the offline AI model. Copy it to the new PC any way you like (USB stick, network, cloud) and double-click it. @@ -105,15 +112,15 @@ survives every future update. Settings → Updates will show *"AI model installe this PC"*. > Why two different installers? A Windows installer cannot exceed 2 GB, and the app plus the model is -> over that. The regular `Bible App Setup .exe` (~300 MB) is what the in-app updater -> downloads, which keeps ordinary updates fast. The **Full** one exists for new machines. +> over that. The regular `Bible App Setup .exe` (~750 MB) is what the in-app updater +> downloads. The **Full** one exists for new machines. **Always check the file after copying it.** An interrupted copy or a cloud placeholder leaves a 0 KB file, and Windows then says *"This app can't run on your PC"* — which looks like an app problem but isn't: -```bash -Get-FileHash "Bible App Full Setup 1.4.1.exe" -Algorithm SHA256 +```powershell +Get-FileHash "Bible App Full Setup 1.4.35.exe" -Algorithm SHA256 ``` Compare that to the `.sha256` file next to the installer. If they match, install it. If not (or the @@ -124,21 +131,18 @@ anything, and refuses a damaged download instead of installing it. ### Keeping several machines in step -Point every machine at the same update location so nobody hand-carries files again: - -- **Same building:** a network share, e.g. `\\WATERS-SERVER\builds\bible-app` -- **Different site:** any web address the app can reach (`http://...`), or a synced cloud folder - that lands on that PC's disk +Point every machine at the same update source and nobody hand-carries files again. The Gitea URL +above works from anywhere on the church network; a network share or a web address works too. ## If something goes wrong | Symptom | Fix | |---|---| -| “Could not read update info” | The folder path is wrong, or `latest.json` isn't in it. Check Settings → Updates. | -| “Installer not found” | `latest.json`'s `file` name doesn't match the actual .exe in the folder. | +| "Could not read update info" | The address is wrong, or `latest.json` isn't there. Check Settings → Updates, and that the machine can reach the Gitea server. | +| "Installer not found" | `latest.json`'s `file` name doesn't match the actual .exe. Re-run `npm run publish-update`. | | Network share not reachable | Confirm the stage PC can open that share in File Explorer. | | Update seems stuck | The installer is large; watch the progress bar. It resumes fine if you retry. | -| “came across empty (0 bytes)” / “is incomplete” | The copy into the update folder didn't finish. Re-copy the installer there and try again. | -| “was damaged in transfer (checksum mismatch)” | The file arrived corrupted. Publish or copy it again. | -| Windows: “This app can't run on your PC” | The .exe you're double-clicking is 0 KB or corrupt — check its size, verify the hash, and re-copy. | -| Need to roll back | Run an older installer from the update folder by hand — it installs over the top. | +| "came across empty (0 bytes)" / "is incomplete" | The transfer didn't finish. Publish again and retry. | +| "was damaged in transfer (checksum mismatch)" | The file arrived corrupted. Publish or copy it again. | +| Windows: "This app can't run on your PC" | The .exe is 0 KB, corrupt, or the wrong architecture — check its size and verify the hash. | +| Need to roll back | `git checkout v` and `npm run release -- --no-bump "Rolling back"`, or run the previous installer (still in the update source) by hand — it installs over the top. | diff --git a/package.json b/package.json index 4b7073c..39b1ebc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bible-app", - "version": "1.4.34", + "version": "1.4.35", "description": "Minimalist Bible App for Portrait-Oriented Touchscreen TV", "type": "module", "main": "main.cjs", diff --git a/tools/build-full-installer.cjs b/tools/build-full-installer.cjs index d239439..62caef2 100644 --- a/tools/build-full-installer.cjs +++ b/tools/build-full-installer.cjs @@ -31,7 +31,19 @@ const installerName = `Bible App Setup ${version}.exe`; const installerPath = path.join(DIST, installerName); const modelPath = path.join(ROOT, 'vendor', 'llama', 'model.gguf'); const sfxModule = path.join(ROOT, 'tools', 'sfx', '7zSD.sfx'); -const sevenZip = path.join(ROOT, 'node_modules', '7zip-bin', 'win', 'x64', '7za.exe'); +/* + * 7za only packs the payload archive; the SFX stub and its config are plain byte concatenation, so + * the HOST's own 7za produces exactly the same Windows .exe. This used to be hard-coded to + * win/x64/7za.exe, which made the one-file installer buildable on Windows only — now the laptop can + * build it too. + */ +const sevenZip = (() => { + const base = path.join(ROOT, 'node_modules', '7zip-bin'); + const arch = ['arm64', 'ia32', 'x64'].includes(process.arch) ? process.arch : 'x64'; + if (process.platform === 'win32') return path.join(base, 'win', arch, '7za.exe'); + if (process.platform === 'darwin') return path.join(base, 'mac', arch === 'arm64' ? 'arm64' : 'x64', '7za'); + return path.join(base, 'linux', arch, '7za'); +})(); const outName = `Bible App Full Setup ${version}.exe`; const outPath = path.join(DIST, outName); @@ -45,7 +57,7 @@ function need(p, what) { need(installerPath, 'installer'); need(modelPath, 'AI model (vendor/llama/model.gguf)'); need(sfxModule, 'SFX module (tools/sfx/7zSD.sfx)'); -need(sevenZip, '7za.exe'); +need(sevenZip, `7za for ${process.platform}/${process.arch}`); const mb = (n) => (n / 1048576).toFixed(1); console.log(`Building one-file installer for ${version}`); @@ -90,7 +102,7 @@ fs.writeFileSync(path.join(stage, 'install.cmd'), [ // LZMA would burn many minutes for ~0% gain. const bundle = path.join(stage, 'payload.7z'); console.log(' packing : building archive (store mode)…'); -execFileSync(sevenZip, ['a', '-t7z', '-mx0', '-bso0', '-bsp0', bundle, path.join(stage, '*')], { stdio: 'inherit' }); +execFileSync(sevenZip, ['a', '-t7z', '-mx0', '-bso0', '-bsp0', bundle, installerName, 'model.gguf', 'install.cmd'], { cwd: stage, stdio: 'inherit' }); /* * ExecuteFile, NOT RunProgram. RunProgram launches via CreateProcess, which cannot start a .cmd at