Spaces:
Running
Running
File size: 4,727 Bytes
3e8ea5d 919485b 3e8ea5d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | import { spawnSync } from 'node:child_process';
import { resolve } from 'node:path';
import { pathToFileURL } from 'node:url';
const DEFAULT_MAX_BUFFER = 20 * 1024 * 1024;
const DEFAULT_FETCH_TIMEOUT_MS = 5000;
export function isMainModule(moduleUrl, argvPath) {
return Boolean(argvPath) && moduleUrl === pathToFileURL(resolve(argvPath)).href;
}
export function runCommand(command, args = [], options = {}) {
const startedAt = Date.now();
const result = spawnSync(command, args, {
cwd: options.cwd,
encoding: options.encoding || 'utf8',
env: options.env,
input: options.input,
maxBuffer: options.maxBuffer || DEFAULT_MAX_BUFFER,
stdio: ['pipe', 'pipe', 'pipe'],
timeout: options.timeoutMs
});
const elapsedMs = Date.now() - startedAt;
if (result.error) {
return {
ok: false,
command,
args,
status: result.status,
stdout: String(result.stdout || ''),
stderr: String(result.stderr || ''),
elapsed_ms: elapsedMs,
error: result.error.message,
signal: result.signal
};
}
return {
ok: result.status === 0,
command,
args,
status: result.status,
stdout: String(result.stdout || ''),
stderr: String(result.stderr || ''),
elapsed_ms: elapsedMs,
signal: result.signal
};
}
export function runCommandStrict(command, args = [], options = {}) {
const result = runCommand(command, args, options);
if (!result.ok) throw new Error(commandFailureMessage(result));
return result.stdout;
}
export function commandFailureMessage(result) {
return pickFailureOutput(result) || `${result.command} ${result.args.join(' ')} failed`;
}
export function printJson(payload) {
console.log(JSON.stringify(payload, null, 2));
}
export function parseJsonPayload(output, label = 'command') {
const lines = output.split(/\r?\n/);
let lastError;
let sawCandidate = false;
for (let start = 0; start < lines.length; start += 1) {
const trimmed = lines[start].trimStart();
if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) continue;
sawCandidate = true;
for (let end = lines.length; end > start; end -= 1) {
try {
return JSON.parse(lines.slice(start, end).join('\n'));
} catch (error) {
lastError = error;
}
}
}
if (!sawCandidate) throw new Error(`${label} did not return JSON output.`);
throw new Error(`${label} returned invalid JSON: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
}
export function redactBaseUrl(value) {
const parsed = new URL(value);
const path = parsed.pathname === '/' ? '' : parsed.pathname.replace(/\/+$/, '');
return `${parsed.protocol}//${parsed.host}${path}`;
}
export async function fetchJsonWithTimeout(url, options = {}) {
const timeoutMs = options.timeoutMs || DEFAULT_FETCH_TIMEOUT_MS;
const pathname = safeUrlPathname(url);
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), timeoutMs);
try {
const response = await fetch(url, { signal: controller.signal });
const text = await response.text();
const bodySnippet = formatResponseBodySnippet(text);
if (!response.ok) throw new Error(`${pathname} failed with HTTP ${response.status}${bodySnippet}`);
try {
return JSON.parse(text);
} catch (error) {
if (error instanceof SyntaxError) throw new Error(`${pathname} did not return JSON${bodySnippet}`);
throw error;
}
} catch (error) {
if (error?.name === 'AbortError') throw new Error(`${pathname} timed out after ${timeoutMs}ms.`);
throw error;
} finally {
clearTimeout(timer);
}
}
function formatResponseBodySnippet(text) {
if (!text || process.env.NODE_ENV === 'production') return '';
return `: ${text.slice(0, 100)}`;
}
function safeUrlPathname(url) {
try {
return new URL(url).pathname;
} catch {
return String(url);
}
}
export function pickFailureOutput(result, maxLength = 4000) {
const output = [
result.stdout,
result.stderr,
result.status !== undefined && result.status !== null ? `status: ${result.status}` : '',
result.error ? `error: ${result.error}` : '',
result.signal ? `signal: ${result.signal}` : ''
]
.filter(Boolean)
.join('\n')
.trim();
return output.length > maxLength ? `${output.slice(0, maxLength)}...` : output;
}
|