realtime-minutes/server/preflight.ts
2026-04-17 16:11:31 +09:00

115 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { config as dotenvConfig } from "dotenv";
import fs from "node:fs";
import net from "node:net";
import { REQUIRED_KEYS, DEFAULT_PORT } from "./constants.js";
const MIN_NODE_VERSION = 20;
function fail(label: string, ...lines: string[]): never {
console.error(`\n[check] ${label} ... NG\n`);
for (const line of lines) console.error(line);
console.error();
process.exit(1);
}
function checkNodeVersion(): void {
const major = parseInt(process.versions.node.split(".")[0]!, 10);
if (major < MIN_NODE_VERSION) {
fail(
`Node.js v${process.versions.node}`,
` Node.js v${MIN_NODE_VERSION} 以上が必要です(現在 v${process.versions.node})。`,
" https://nodejs.org/ から最新版をインストールしてください。",
);
}
}
function checkEnvFile(): void {
if (!fs.existsSync(".env")) {
fail(
".env",
" .env ファイルが見つかりません。",
" 以下の手順で作成してください:",
"",
" 1. cp .env.example .env",
' 2. テキストエディタで .env を開く(例: code .env',
" 3. API キーを貼り付ける",
"",
" API キーの取得先:",
" Deepgram : https://console.deepgram.com/",
" Google AI : https://aistudio.google.com/apikey",
);
}
}
function checkRequiredKeys(): void {
for (const key of REQUIRED_KEYS) {
const val = process.env[key];
if (!val || val.trim() === "") {
fail(
key,
` ${key} が設定されていません。`,
" .env ファイルを開いて値を設定してください。",
"",
" API キーの取得先:",
" Deepgram : https://console.deepgram.com/",
" Google AI : https://aistudio.google.com/apikey",
);
}
}
}
function resolvePort(): number {
const portStr = process.env["PORT"] ?? String(DEFAULT_PORT);
const port = parseInt(portStr, 10);
if (isNaN(port) || port < 1 || port > 65535) {
fail("PORT", ` PORT の値が不正です: ${portStr}`);
}
return port;
}
function checkPortAvailable(port: number): Promise<void> {
return new Promise((resolve) => {
const server = net.createServer();
server.once("error", (err: NodeJS.ErrnoException) => {
if (err.code === "EADDRINUSE") {
fail(
`ポート ${port}`,
` ポート ${port} が使用中です。`,
" 前回のサーバーが残っている場合: just stop を実行",
" 他のアプリが使用中の場合: そのアプリを終了してください",
);
} else if (err.code === "EACCES") {
fail(
`ポート ${port}`,
` ポート ${port} にアクセス権がありません。`,
" 1024 以上のポート番号を .env の PORT に設定してください。",
);
} else {
fail(`ポート ${port}`, ` ポートチェックでエラーが発生しました: ${err.message}`);
}
});
server.listen({ port, host: "0.0.0.0" }, () => {
server.close(() => resolve());
});
});
}
async function main(): Promise<void> {
checkNodeVersion();
checkEnvFile();
dotenvConfig();
checkRequiredKeys();
const port = resolvePort();
await checkPortAvailable(port);
console.log(
`[check] 環境チェック完了 (Node.js v${process.versions.node}, .env, APIキー, ポート${port})`,
);
}
main().catch((e) => {
console.error("プリフライトチェックで予期しないエラーが発生しました:", e);
process.exit(1);
});