mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-26 11:49:16 +00:00
fix(fleet): resolve getSenchoVersion crash in Docker containers (#396)
* fix(fleet): resolve getSenchoVersion crash in Docker containers Replace the runtime __dirname walk (which fails in Docker because the root package.json is absent from the final image) with a build-time version injection. A prebuild script reads the root package.json and generates src/generated/version.ts with the version baked in as a constant. The compiled output carries the correct version regardless of the container's filesystem layout. Retains a filesystem walk fallback for dev environments where the prebuild hook may not have run. * fix(fleet): skip postinstall version generation when script is absent The Docker prod-deps stage copies only package.json (no source files) before running npm ci --omit=dev. The postinstall hook now checks for the script file before executing, so it no-ops in stages where scripts/generate-version.js has not been copied.
This commit is contained in:
@@ -56,6 +56,7 @@ backend/public/
|
||||
|
||||
# Auto-generated files
|
||||
backend/cookies.txt
|
||||
backend/src/generated/version.ts
|
||||
|
||||
# Local-only projects (separate repos)
|
||||
demo-video/
|
||||
|
||||
+1
-1
@@ -330,7 +330,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
* **licensing:** license card now shows "Duration: Lifetime" for lifetime licenses instead of an empty renewal date
|
||||
* **fleet:** remote node capability detection now works reliably; `/api/meta` and `/api/health` are exempt from the global rate limiter so they are never blocked by proxied traffic, and a backend-side cache with stale-while-revalidate prevents transient failures from disabling capability-gated features (Auto-Update, Schedules, Audit, Console) on remote nodes
|
||||
* **fleet:** failed capability fetches now retry after 30 seconds instead of being cached for the full 5-minute TTL
|
||||
* **fleet:** `getSenchoVersion()` now resolves `package.json` via `__dirname` walk instead of a hardcoded relative path; the previous `require('../../../package.json')` resolved correctly in dev but crashed with a 500 in Docker (compiled path `dist/services/` has a different depth than source `src/services/`), causing `/api/meta` to always fail on containerized instances and all capability-gated features to appear unsupported on remote nodes
|
||||
* **fleet:** `getSenchoVersion()` no longer crashes in Docker containers; version is now baked in at build time via a prebuild script that reads the root `package.json` and generates a TypeScript constant, with a filesystem walk fallback for dev environments where the prebuild hook may not have run
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -4,8 +4,11 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"postinstall": "test -f scripts/generate-version.js && node scripts/generate-version.js || true",
|
||||
"prebuild": "node scripts/generate-version.js",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js",
|
||||
"predev": "node scripts/generate-version.js",
|
||||
"dev": "nodemon --watch src --ext ts,json --exec ts-node src/index.ts",
|
||||
"test": "vitest run",
|
||||
"lint": "eslint src"
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env node
|
||||
// Reads the version from the root package.json and writes it into
|
||||
// src/generated/version.ts so it's available as a compiled constant.
|
||||
// Invoked automatically by prebuild/predev/postinstall npm hooks.
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const rootPkg = path.resolve(__dirname, '..', '..', 'package.json');
|
||||
const outFile = path.resolve(__dirname, '..', 'src', 'generated', 'version.ts');
|
||||
|
||||
let version = '0.0.0-dev';
|
||||
try {
|
||||
const pkg = JSON.parse(fs.readFileSync(rootPkg, 'utf8'));
|
||||
if (pkg.version) version = pkg.version;
|
||||
} catch {
|
||||
console.warn('[generate-version] Could not read root package.json, using fallback version');
|
||||
}
|
||||
|
||||
const content = `// Auto-generated by prebuild script. Do not edit manually.
|
||||
// Regenerated on every \`npm run build\` from the root package.json.
|
||||
export const SENCHO_VERSION: string = ${JSON.stringify(version)};
|
||||
`;
|
||||
|
||||
fs.mkdirSync(path.dirname(outFile), { recursive: true });
|
||||
fs.writeFileSync(outFile, content, 'utf8');
|
||||
console.log(`[generate-version] Wrote ${version} to src/generated/version.ts`);
|
||||
@@ -1,6 +1,7 @@
|
||||
import axios from 'axios';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { SENCHO_VERSION } from '../generated/version';
|
||||
|
||||
/**
|
||||
* Static registry of capabilities supported by THIS Sencho instance.
|
||||
@@ -34,24 +35,29 @@ export const CAPABILITIES = [
|
||||
|
||||
export type Capability = (typeof CAPABILITIES)[number];
|
||||
|
||||
export function getSenchoVersion(): string {
|
||||
// Walk up from __dirname to find the root package.json (name === 'sencho').
|
||||
// In dev this is 3 levels up (src/services/ -> root), in Docker it's 2
|
||||
// (dist/services/ -> /app/). Skips intermediate package.json files like
|
||||
// backend/package.json which has a different name and version.
|
||||
// Resolved once per process at import time, then cached.
|
||||
function resolveVersion(): string {
|
||||
if (SENCHO_VERSION !== '0.0.0-dev') return SENCHO_VERSION;
|
||||
|
||||
// Fallback for manual ts-node runs without the predev hook.
|
||||
let dir = __dirname;
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const candidate = path.join(dir, 'package.json');
|
||||
if (fs.existsSync(candidate)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const pkg = require(candidate);
|
||||
try {
|
||||
const pkg = JSON.parse(fs.readFileSync(candidate, 'utf8'));
|
||||
if (pkg.name === 'sencho') return pkg.version;
|
||||
}
|
||||
} catch { /* not found, keep walking */ }
|
||||
dir = path.dirname(dir);
|
||||
}
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
const cachedVersion = resolveVersion();
|
||||
|
||||
export function getSenchoVersion(): string {
|
||||
return cachedVersion;
|
||||
}
|
||||
|
||||
export interface RemoteMeta {
|
||||
version: string | null;
|
||||
capabilities: string[];
|
||||
|
||||
Reference in New Issue
Block a user