Files
xll-mini-program/scripts/utils/serverInfo.mjs
王冕 a619938e0c Initial commit: 小羚羚小程序 Axhub Make workspace.
Include xll-miniapp prototype, PRD resources, annotation directory sync, agent skills, and cloud publishing setup.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 15:32:30 +08:00

109 lines
3.0 KiB
JavaScript

import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
const MAKE_STATE_DIR = path.join('.axhub', 'make');
const RUNTIME_SERVER_INFO_RELATIVE_PATH = path.join(MAKE_STATE_DIR, '.dev-server-info.json');
const ADMIN_SERVER_INFO_RELATIVE_PATH = path.join(MAKE_STATE_DIR, '.admin-server-info.json');
const MAKE_HOME_DIR_ENV = 'AXHUB_MAKE_HOME_DIR';
function resolveProjectRoot(projectRoot) {
return path.resolve(projectRoot);
}
function getServerInfoPath(projectRoot, role) {
if (role === 'admin') {
return getAdminServerInfoPath();
}
return path.join(resolveProjectRoot(projectRoot), RUNTIME_SERVER_INFO_RELATIVE_PATH);
}
function getGlobalHomeDir(options = {}) {
return options.homeDir || process.env[MAKE_HOME_DIR_ENV] || os.homedir();
}
export function getAdminServerInfoPath(_projectRoot, options = {}) {
return path.join(path.resolve(getGlobalHomeDir(options)), ADMIN_SERVER_INFO_RELATIVE_PATH);
}
export function getRuntimeServerInfoPath(projectRoot) {
return getServerInfoPath(projectRoot, 'runtime');
}
function normalizeServerInfo(data) {
if (!data || typeof data !== 'object') {
return null;
}
if (
typeof data.pid !== 'number'
|| typeof data.port !== 'number'
|| typeof data.host !== 'string'
|| typeof data.origin !== 'string'
|| typeof data.projectRoot !== 'string'
|| typeof data.startedAt !== 'string'
) {
return null;
}
return {
pid: data.pid,
port: data.port,
host: data.host,
origin: data.origin,
projectRoot: resolveProjectRoot(data.projectRoot),
startedAt: data.startedAt,
};
}
export function readServerInfo(projectRoot, role, options = {}) {
const infoPath = role === 'admin'
? getAdminServerInfoPath(projectRoot, options)
: getServerInfoPath(projectRoot, role);
if (!fs.existsSync(infoPath)) {
return null;
}
try {
return normalizeServerInfo(JSON.parse(fs.readFileSync(infoPath, 'utf8')));
} catch {
return null;
}
}
export function writeServerInfo(projectRoot, role, info, options = {}) {
const normalized = {
...info,
projectRoot: resolveProjectRoot(info.projectRoot),
};
const infoPath = role === 'admin'
? getAdminServerInfoPath(projectRoot, options)
: getServerInfoPath(projectRoot, role);
fs.mkdirSync(path.dirname(infoPath), { recursive: true });
fs.writeFileSync(infoPath, `${JSON.stringify(normalized, null, 2)}\n`, 'utf8');
return normalized;
}
export async function fetchHealth(origin, timeoutMs = 1000) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(new URL('/api/health', origin), {
signal: controller.signal,
headers: { accept: 'application/json' },
});
if (!response.ok) {
return null;
}
return await response.json();
} catch {
return null;
} finally {
clearTimeout(timeout);
}
}
export function normalizeHealthServerInfo(data) {
if (!data || typeof data !== 'object') {
return null;
}
return normalizeServerInfo(data.server ?? data);
}