#!/usr/bin/env node import { existsSync } from "node:fs"; const baseUrl = (process.env.LIVE_SMOKE_BASE_URL || "https://oa.hyinda.com").trim().replace(/\/$/, ""); function present(key) { return Boolean(process.env[key]?.trim()); } function maskedPresence(keys) { return Object.fromEntries(keys.map((key) => [key, present(key)])); } function existingFileFrom(keys) { const values = keys.map((key) => process.env[key]?.trim()).filter(Boolean); return values.find((value) => existsSync(value)) || ""; } async function fetchJson(url) { try { const response = await fetch(url, { signal: AbortSignal.timeout(10_000) }); const text = await response.text(); let json = null; try { json = text ? JSON.parse(text) : null; } catch { json = null; } return { ok: response.ok, status: response.status, json, text: text.slice(0, 300) }; } catch (error) { return { ok: false, status: 0, error: error instanceof Error ? error.message : String(error) }; } } function buildStaticChecks() { const liveSmokeKeys = [ "LIVE_SMOKE_ADMIN_IDENTIFIER", "LIVE_SMOKE_ADMIN_PASSWORD", "LIVE_SMOKE_EMPLOYEE_IDENTIFIER", "LIVE_SMOKE_EMPLOYEE_PASSWORD", ]; const liveSmokeReady = liveSmokeKeys.every(present); const ocrUserReady = ( (present("PLAYWRIGHT_OCR_LIVE_IDENTIFIER") && present("PLAYWRIGHT_OCR_LIVE_PASSWORD")) || (present("LIVE_SMOKE_EMPLOYEE_IDENTIFIER") && present("LIVE_SMOKE_EMPLOYEE_PASSWORD")) ); const invoiceFile = existingFileFrom(["PLAYWRIGHT_OCR_LIVE_FILE", "LIVE_OCR_INVOICE_FILE"]); const invoiceBatchDir = process.env.PLAYWRIGHT_OCR_LIVE_DIR?.trim() || ""; const invoiceSampleReady = Boolean(invoiceFile) || (Boolean(invoiceBatchDir) && existsSync(invoiceBatchDir)); return { baseUrl, liveSmokeReady, liveSmoke: maskedPresence(liveSmokeKeys), liveSmokeOptional: maskedPresence([ "LIVE_EXPECT_WECOM_STATUS", "LIVE_SMOKE_MANAGER_IDENTIFIER", "LIVE_SMOKE_MANAGER_PASSWORD", "LIVE_SMOKE_FINANCE_IDENTIFIER", "LIVE_SMOKE_FINANCE_PASSWORD", ]), liveOcrReady: ocrUserReady && invoiceSampleReady, liveOcr: { userReady: ocrUserReady, invoiceSampleReady, invoiceFileProvided: Boolean(invoiceFile), invoiceBatchDirProvided: Boolean(invoiceBatchDir), allowDuplicate: process.env.PLAYWRIGHT_OCR_ALLOW_DUPLICATE === "1", }, missing: [], }; } function addMissing(checks) { if (!checks.liveSmokeReady) { for (const [key, value] of Object.entries(checks.liveSmoke)) { if (!value) checks.missing.push(key); } } if (!checks.liveOcr.userReady) { checks.missing.push("PLAYWRIGHT_OCR_LIVE_IDENTIFIER/PASSWORD 或 LIVE_SMOKE_EMPLOYEE_*"); } if (!checks.liveOcr.invoiceSampleReady) { checks.missing.push("PLAYWRIGHT_OCR_LIVE_FILE 或 PLAYWRIGHT_OCR_LIVE_DIR"); } } async function main() { const strict = process.argv.includes("--strict"); const jsonOnly = process.argv.includes("--json"); const checks = buildStaticChecks(); addMissing(checks); const ready = await fetchJson(`${baseUrl}/ready`); const wecomConfig = await fetchJson(`${baseUrl}/api/auth/wecom/config`); const result = { checkedAt: new Date().toISOString(), ...checks, publicReady: { ok: ready.ok, status: ready.status, }, wecomConfig: { ok: wecomConfig.ok, status: wecomConfig.status, statusText: wecomConfig.json?.data?.status ?? null, entryEnabled: wecomConfig.json?.data?.entryEnabled ?? null, oauthEnabled: wecomConfig.json?.data?.oauthEnabled ?? null, defaultReturnTo: wecomConfig.json?.data?.defaultReturnTo ?? null, loginUrl: wecomConfig.json?.data?.loginUrl ?? null, }, }; if (jsonOnly) { console.log(JSON.stringify(result, null, 2)); } else { console.log(`[live-smoke-env] base=${result.baseUrl}`); console.log(`[live-smoke-env] publicReady=${result.publicReady.ok} status=${result.publicReady.status}`); console.log(`[live-smoke-env] wecom=${result.wecomConfig.statusText ?? "unknown"} entry=${result.wecomConfig.entryEnabled} oauth=${result.wecomConfig.oauthEnabled}`); console.log(`[live-smoke-env] liveSmokeReady=${result.liveSmokeReady}`); console.log(`[live-smoke-env] liveOcrReady=${result.liveOcrReady}`); if (result.missing.length) { console.log(`[live-smoke-env] missing=${result.missing.join(", ")}`); } } if (strict && (!result.liveSmokeReady || !result.liveOcrReady || !result.publicReady.ok || !result.wecomConfig.ok)) { process.exit(1); } } main().catch((error) => { console.error(`[live-smoke-env][ERROR] ${error instanceof Error ? error.message : String(error)}`); process.exit(1); });