Files
memind/scripts/check-stream-runtime.mjs
T
2026-07-02 07:06:25 +08:00

100 lines
3.1 KiB
JavaScript
Executable File

#!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';
import { Agent, fetch as undiciFetch } from 'undici';
function loadEnvFile(filePath) {
if (!fs.existsSync(filePath)) return;
for (const line of fs.readFileSync(filePath, 'utf8').split('\n')) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) continue;
const idx = trimmed.indexOf('=');
if (idx < 0) continue;
const key = trimmed.slice(0, idx).trim();
const value = trimmed.slice(idx + 1).trim();
if (!process.env[key]) process.env[key] = value;
}
}
loadEnvFile(path.join(process.cwd(), '.env'));
const insecureDispatcher = new Agent({ connect: { rejectUnauthorized: false } });
const publicBase = (process.env.H5_PUBLIC_BASE_URL || 'https://mm.tkmind.cn').replace(/\/$/, '');
const targets = (process.env.TKMIND_API_TARGETS || process.env.TKMIND_API_TARGET || '')
.split(',')
.map((value) => value.trim())
.filter(Boolean);
async function fetchText(url, init = {}) {
const res = await undiciFetch(url, {
...init,
dispatcher: url.startsWith('https://127.0.0.1') ? insecureDispatcher : undefined,
});
const text = await res.text();
return { res, text };
}
async function checkJson(pathname) {
const { res, text } = await fetchText(`${publicBase}${pathname}`);
let json = null;
try {
json = JSON.parse(text);
} catch {
json = null;
}
return { ok: res.ok, status: res.status, json, text: json ? undefined : text.slice(0, 160) };
}
async function checkSseHeaders(pathname) {
const { res } = await fetchText(`${publicBase}${pathname}`, {
method: 'HEAD',
headers: { Accept: 'text/event-stream' },
});
return {
ok: res.status === 401 || res.ok,
status: res.status,
xAccelBuffering: res.headers.get('x-accel-buffering'),
contentType: res.headers.get('content-type'),
cacheControl: res.headers.get('cache-control'),
};
}
async function checkTarget(target) {
const { res, text } = await fetchText(new URL('/status', target).toString());
return { target, ok: res.ok, status: res.status, text: text.slice(0, 80) };
}
const result = {
ok: true,
publicBase,
checkedAt: new Date().toISOString(),
status: await checkJson('/api/status').catch((err) => ({ ok: false, error: err.message })),
runtime: await checkJson('/api/runtime/status').catch((err) => ({ ok: false, error: err.message })),
sse: {
sessions: await checkSseHeaders('/api/sessions/check-stream-runtime/events').catch((err) => ({
ok: false,
error: err.message,
})),
agentRuns: await checkSseHeaders('/api/agent/runs/check-stream-runtime/events').catch((err) => ({
ok: false,
error: err.message,
})),
},
targets: await Promise.all(targets.map((target) => checkTarget(target).catch((err) => ({
target,
ok: false,
error: err.message,
})))),
};
result.ok = Boolean(
result.status.ok &&
result.runtime.ok &&
result.sse.sessions.ok &&
result.sse.agentRuns.ok &&
result.targets.every((target) => target.ok),
);
console.log(JSON.stringify(result, null, 2));
process.exit(result.ok ? 0 : 1);