From 0a1e4e9d6b9da8086521534d0dca25f83fc8a5f3 Mon Sep 17 00:00:00 2001 From: Rory& Date: Wed, 25 Feb 2026 10:49:05 +0100 Subject: [PATCH] Add /_spacebar/api/version - resolves #1222 --- src/api/Server.ts | 9 +++++++- src/bundle/start.ts | 27 +---------------------- src/util/util/Version.ts | 47 ++++++++++++++++++++++++++++++++++++++++ src/util/util/index.ts | 1 + 4 files changed, 57 insertions(+), 27 deletions(-) create mode 100644 src/util/util/Version.ts diff --git a/src/api/Server.ts b/src/api/Server.ts index a6bb5178d..6a61d3cba 100644 --- a/src/api/Server.ts +++ b/src/api/Server.ts @@ -16,7 +16,7 @@ along with this program. If not, see . */ -import { Config, ConnectionConfig, ConnectionLoader, Email, JSONReplacer, WebAuthn, initDatabase, initEvent, registerRoutes, getDatabase } from "@spacebar/util"; +import { Config, ConnectionConfig, ConnectionLoader, Email, JSONReplacer, WebAuthn, initDatabase, initEvent, registerRoutes, getDatabase, getRevInfoOrFail } from "@spacebar/util"; import { Authentication, CORS, ImageProxy, BodyParser, ErrorHandler, initRateLimits, initTranslation } from "./middlewares"; import { Request, Response, Router } from "express"; import { Server, ServerOptions } from "lambert-server"; @@ -141,6 +141,13 @@ export class SpacebarServer extends Server { res.sendFile(path.join(ASSETS_FOLDER, "openapi.json")); }); + app.get("/_spacebar/api/version", (req, res) => { + res.json({ + implementation: "spacebar-server-ts", + version: getRevInfoOrFail(), + }); + }); + // current well-known location app.get("/.well-known/spacebar", (req, res) => { res.json({ diff --git a/src/bundle/start.ts b/src/bundle/start.ts index af288f8ee..227964b57 100644 --- a/src/bundle/start.ts +++ b/src/bundle/start.ts @@ -29,37 +29,12 @@ import { config } from "dotenv"; config({ quiet: true }); import { execSync } from "child_process"; -import { centerString, Logo } from "@spacebar/util"; +import { centerString, getRevInfoOrFail, Logo } from "@spacebar/util"; import fs from "fs"; import path from "path"; const cores = process.env.THREADS ? parseInt(process.env.THREADS) : 1; -function getRevInfoOrFail(): { rev: string | null; lastModified: number } { - const rootDir = path.join(__dirname, "../../"); - // sanity check - if (!fs.existsSync(path.join(rootDir, "package.json"))) { - console.log(red("Error: Cannot find package.json in root directory. Are you running from the correct location?")); - } - - // use .rev file if it exists - if (fs.existsSync(path.join(__dirname, "../../.rev"))) { - return JSON.parse(fs.readFileSync(path.join(rootDir, ".rev"), "utf-8")); - } - - // fall back to invoking git - try { - const rev = execSync(`git -C "${rootDir}" rev-parse HEAD`).toString().trim(); - const lastModified = Number(execSync(`git -C "${rootDir}" log -1 --format=%cd --date=unix`).toString().trim()); - return { - rev, - lastModified, - }; - } catch (e) { - return { rev: null, lastModified: 0 }; - } -} - if (cluster.isPrimary) { const revInfo = getRevInfoOrFail(); Logo.printLogo().then(() => { diff --git a/src/util/util/Version.ts b/src/util/util/Version.ts new file mode 100644 index 000000000..2d7c4b566 --- /dev/null +++ b/src/util/util/Version.ts @@ -0,0 +1,47 @@ +/* + Spacebar: A FOSS re-implementation and extension of the Discord.com backend. + Copyright (C) 2026 Spacebar and Spacebar Contributors + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +import path from "path"; +import fs from "fs"; +import { execSync } from "child_process"; +import { red } from "picocolors"; + +export function getRevInfoOrFail(): { rev: string | null; lastModified: number } { + const rootDir = path.join(__dirname, "../../../"); + // sanity check + if (!fs.existsSync(path.join(rootDir, "package.json"))) { + console.log(red("Error: Cannot find package.json in root directory. Are you running from the correct location?")); + } + + // use .rev file if it exists + if (fs.existsSync(path.join(rootDir, ".rev"))) { + return JSON.parse(fs.readFileSync(path.join(rootDir, ".rev"), "utf-8")); + } + + // fall back to invoking git + try { + const rev = execSync(`git -C "${rootDir}" rev-parse HEAD`).toString().trim(); + const lastModified = Number(execSync(`git -C "${rootDir}" log -1 --format=%cd --date=unix`).toString().trim()); + return { + rev, + lastModified, + }; + } catch (e) { + return { rev: null, lastModified: 0 }; + } +} diff --git a/src/util/util/index.ts b/src/util/util/index.ts index aac4e3c03..4c243ade2 100644 --- a/src/util/util/index.ts +++ b/src/util/util/index.ts @@ -55,3 +55,4 @@ export * from "../../schemas/HelperTypes"; export * from "./extensions"; export * from "./Random"; export * from "./Url"; +export * from "./Version";