- Add getAppVersion() utility that walks up directories to find package.json - Add parseSemver() for semver string parsing with major/minor/patch components - Add CentralCore version sync methods (getAppVersion, syncVersion, getLastSyncTime, getSyncStatus) - Add CentralCore events for version sync lifecycle (version-sync-started, version-sync-completed, version-sync-failed) - Add schema v4 migration with appVersion and lastSyncTime columns to projects table - Export new types (CentralSyncStatus, SyncResult) and utilities via @fusion/core - Update memory.md documentation with new types - Fix TypeScript error in app-version.ts (return pkg.version directly instead of cached variable)
64 lines
2.1 KiB
TypeScript
64 lines
2.1 KiB
TypeScript
import { readFileSync } from "node:fs";
|
|
import { join, dirname } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
/**
|
|
* Cached app version once resolved.
|
|
*/
|
|
let cachedVersion: string | null = null;
|
|
|
|
/**
|
|
* Get the current Fusion application version by reading the nearest package.json.
|
|
* Walks up from the current file to find the root package.json.
|
|
* Results are cached for the process lifetime.
|
|
*
|
|
* @returns Semver version string (e.g., "0.1.0")
|
|
*/
|
|
export function getAppVersion(): string {
|
|
if (cachedVersion !== null) return cachedVersion;
|
|
|
|
// Start from this file's directory and walk up
|
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
let currentDir = __dirname;
|
|
|
|
// Walk up to 10 levels looking for package.json
|
|
for (let i = 0; i < 10; i++) {
|
|
try {
|
|
const pkgPath = join(currentDir, "package.json");
|
|
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
if (pkg.version && typeof pkg.version === "string") {
|
|
cachedVersion = pkg.version;
|
|
return pkg.version;
|
|
}
|
|
} catch {
|
|
// package.json not found or not parseable — continue walking up
|
|
}
|
|
const parentDir = dirname(currentDir);
|
|
if (parentDir === currentDir) break; // Reached filesystem root
|
|
currentDir = parentDir;
|
|
}
|
|
|
|
// Fallback if no package.json found
|
|
cachedVersion = "0.0.0";
|
|
return cachedVersion;
|
|
}
|
|
|
|
/**
|
|
* Parse a semver string into its components.
|
|
* Supports basic semver format: MAJOR.MINOR.PATCH with optional prerelease suffix.
|
|
* The string must match the pattern starting from the beginning.
|
|
*
|
|
* @param version - Semver version string (e.g., "1.2.3", "1.2.3-beta.1")
|
|
* @returns Parsed components or null if invalid
|
|
*/
|
|
export function parseSemver(version: string): { major: number; minor: number; patch: number } | null {
|
|
// Strict semver regex: anchored to start, requires MAJOR.MINOR.PATCH, allows optional prerelease/build
|
|
const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/);
|
|
if (!match) return null;
|
|
return {
|
|
major: parseInt(match[1], 10),
|
|
minor: parseInt(match[2], 10),
|
|
patch: parseInt(match[3], 10),
|
|
};
|
|
}
|