[object Object]

← back to AsSeenInMovies

api/version: deploy fingerprint endpoint (name, version, git SHA, node, started_at)

3f7e5d7003171d4b75f96f6ecf7eaab3d4cca7df · 2026-05-13 10:04:34 -0700 · SteveStudio2

Files touched

Diff

commit 3f7e5d7003171d4b75f96f6ecf7eaab3d4cca7df
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 13 10:04:34 2026 -0700

    api/version: deploy fingerprint endpoint (name, version, git SHA, node, started_at)
---
 server.js | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/server.js b/server.js
index e6e4d23..0b6cbd4 100644
--- a/server.js
+++ b/server.js
@@ -20,6 +20,22 @@ const path = require('path');
 const fs = require('fs');
 const { Pool } = require('pg');
 
+// Cached version metadata: package.json version + git short SHA (best-effort).
+// Resolved once at boot to keep /api/version sub-1ms. SHA falls back to 'unknown'
+// when git isn't on PATH or the project isn't a repo.
+const PKG_VERSION = (() => {
+  try { return require('./package.json').version || '0.0.0'; }
+  catch (_) { return '0.0.0'; }
+})();
+const GIT_SHA = (() => {
+  try {
+    return require('child_process')
+      .execSync('git rev-parse --short HEAD', { cwd: __dirname, stdio: ['ignore', 'pipe', 'ignore'] })
+      .toString().trim() || 'unknown';
+  } catch (_) { return 'unknown'; }
+})();
+const STARTED_AT_ISO = new Date().toISOString();
+
 const PORT = parseInt(process.env.PORT || '9742', 10);
 const DB_URL = process.env.DATABASE_URL || 'postgresql:///dw_unified?host=/tmp&user=stevestudio2';
 
@@ -86,6 +102,7 @@ app.get('/api', (_req, res) => {
     base: process.env.ASIM_PUBLIC_URL || 'https://asseeninmovies.com',
     endpoints: {
       'GET /api/health':         'Liveness probe + cached counts (movies/people/spotted)',
+      'GET /api/version':        'Deploy fingerprint — JSON {name, version, git, node, started_at}',
       'GET /api/search?q=…':     'ILIKE search across movies + people (poster-having subset)',
       'GET /api/movie/:id':      'Single movie row by id (TMDB id, not slug)',
       'GET /api/person/:id':     'Single person row by id',
@@ -111,6 +128,19 @@ app.get('/healthz', (_req, res) => {
   res.json({ ok: true, ts: Date.now() });
 });
 
+// /api/version — deploy fingerprint. Lets Steve verify which build is live
+// without inspecting pm2 logs. Static at boot, so no DB hit.
+app.get('/api/version', (_req, res) => {
+  res.setHeader('Cache-Control', 'no-store');
+  res.json({
+    name:       'asseeninmovies',
+    version:    PKG_VERSION,
+    git:        GIT_SHA,
+    node:       process.version,
+    started_at: STARTED_AT_ISO,
+  });
+});
+
 app.get('/api/health', async (_req, res) => {
   try {
     // Cheap liveness: SELECT 1 only. The count(*) counts come from the

← b8ab370 smoke: uptime_s assertion on /api/health  ·  back to AsSeenInMovies  ·  smoke: 4 assertions for /api/version (200, name, git sha, no d1d1f7a →