@mesh-tech/mesh-cli
Version:
CLI for Mesh platform development utilities
63 lines (62 loc) • 2.46 kB
JavaScript
import * as fs from 'fs';
import * as net from 'net';
import * as path from 'path';
export const ENV_FILE_MODE = 0o600;
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
export function quoteShellValue(value) {
return `'${value.replace(/'/g, "'\\''")}'`;
}
export function renderEnvFile(env) {
const lines = [
'# Auto-generated by mesh dev — do not edit.',
'# Sourced by service launch/restart commands; this file IS the',
"# session's env contract for the service (restart fidelity).",
];
for (const [key, value] of Object.entries(env)) {
if (!ENV_KEY_RE.test(key)) {
throw new Error(`Invalid env var name for env file: ${JSON.stringify(key)}`);
}
lines.push(`export ${key}=${quoteShellValue(value)}`);
}
return lines.join('\n') + '\n';
}
export function envFileName(serviceName) {
return `${serviceName.replace(/[^A-Za-z0-9._-]/g, '-')}.env.sh`;
}
export function writeEnvFile(filePath, env) {
fs.mkdirSync(path.dirname(filePath), { recursive: true });
fs.writeFileSync(filePath, renderEnvFile(env), { mode: ENV_FILE_MODE });
fs.chmodSync(filePath, ENV_FILE_MODE);
}
export function buildLaunchCommand(envFilePath, dir, command, logShipper) {
const base = `cd ${quoteShellValue(dir)} && source ${quoteShellValue(envFilePath)} && `;
if (!logShipper)
return `${base}${command}`;
return `${base}{ ${command}; } 2>&1 | NODE_OPTIONS= node ${quoteShellValue(logShipper)}`;
}
export async function waitForPort(host, port, timeoutMs, intervalMs = 500) {
const deadline = Date.now() + timeoutMs;
for (;;) {
const remaining = deadline - Date.now();
const attemptTimeout = Math.max(250, Math.min(1000, remaining));
if (await tryConnect(host, port, attemptTimeout))
return true;
if (Date.now() + intervalMs >= deadline)
return false;
await new Promise((resolve) => setTimeout(resolve, intervalMs));
}
}
function tryConnect(host, port, timeoutMs) {
return new Promise((resolve) => {
const socket = net.connect({ host, port });
const done = (ok) => {
socket.removeAllListeners();
socket.destroy();
resolve(ok);
};
socket.setTimeout(timeoutMs);
socket.once('connect', () => done(true));
socket.once('timeout', () => done(false));
socket.once('error', () => done(false));
});
}