← Commit history

0.14.1: read the app version per request, not once at boot

Drew Owens ·2f3c7863f2 · ·parent a245f8e
The header version was cached at server startup. gantt.html is read per request, so a deploy that only changes the HTML needs no restart, and that deploy left the header showing the previous release: exactly the drift the injection was built to prevent. It reads package.json on the page request now.
3 files changed +11−8
package.json+1−1
@@ -2,7 +2,7 @@   "slug": "adom-gantt",   "title": "Adom Gantt",   "type": "app",-  "version": "0.14.0",+  "version": "0.14.1",   "description": "Interactive Gantt chart viewer for project timelines, with a table view over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.",   "main": "server.js",   "bin": {
page.json+2−2
@@ -2,7 +2,7 @@   "slug": "adom-gantt",   "title": "Adom Gantt",   "type": "app",-  "version": "0.14.0",+  "version": "0.14.1",   "description": "Interactive Gantt chart viewer for project timelines, with a table view over the same data. Data-driven, dark by default with a print-friendly light mode, and fully editable in the browser: drag bars to move or resize, multi-select and batch-shift dates, manage dependency arrows inline, reorder rows, filter by phase, and undo. Toggle to the table for every task and milestone as a row with owner, deadline and status, filtered per owner and edited in place. Every edit is recorded in an append-only changelog so an AI can read what a human changed and build on it. Imports JSON, CSV, MS Project XML and Jira CSV; exports JSON, CSV, SVG and a self-contained HTML snapshot.",   "main": "server.js",   "bin": {@@ -63,4 +63,4 @@     "name": "Drew Owens",     "email": "[email protected]"   }-}\ No newline at end of file+}
server.js+8−5
@@ -22,14 +22,17 @@ if (!fs.existsSync(DATA_FILE)) { const STATE_FILE = DATA_FILE.replace(/\.json$/, '-state.json'); const LOG_FILE = DATA_FILE.replace(/\.json$/, '-changelog.jsonl'); const APP_DIR = __dirname;-// Read once from our own manifest so the header cannot drift from the released-// version. gantt.html ships a placeholder; it is substituted on the way out.-const APP_VERSION = (() => {+// Read from our own manifest per request, not once at boot. gantt.html is already+// read per request, so a deploy that only changes the HTML needs no restart; if+// the version were cached at startup that deploy would leave the header showing+// the previous release, which is exactly the drift this was built to prevent.+// Cheap: a small file, and only on the page request.+function appVersion() {   try { return JSON.parse(fs.readFileSync(path.join(APP_DIR, 'package.json'), 'utf8')).version || ''; }   catch { return ''; }-})();+} function serveApp() {-  return fs.readFileSync(path.join(APP_DIR, 'gantt.html'), 'utf8').split('__APP_VERSION__').join(APP_VERSION);+  return fs.readFileSync(path.join(APP_DIR, 'gantt.html'), 'utf8').split('__APP_VERSION__').join(appVersion()); } const DATA_DIR = path.dirname(DATA_FILE);