node-api / server /_core /index.ts
taqarub's picture
Deploy Taqarub Node API server
cd2a4c2
Raw History Blame Contribute Delete
3 kB
import "dotenv/config";
import express from "express";
import { createServer } from "http";
import net from "net";
import { createExpressMiddleware } from "@trpc/server/adapters/express";
import { registerOAuthRoutes } from "./oauth";
import { appRouter } from "../routers";
import { createContext } from "./context";
import { registerVoiceWebSocket } from "../voice-ws";
function isPortAvailable(port: number): Promise<boolean> {
return new Promise((resolve) => {
const server = net.createServer();
server.listen(port, "0.0.0.0", () => {
server.close(() => resolve(true));
});
server.on("error", () => resolve(false));
});
}
async function findAvailablePort(startPort: number = 3000): Promise<number> {
for (let port = startPort; port < startPort + 20; port++) {
if (await isPortAvailable(port)) {
return port;
}
}
throw new Error(`No available port found starting from ${startPort}`);
}
async function startServer() {
const app = express();
const server = createServer(app);
// Enable CORS for all routes
// In production, restrict to known origins; in dev, reflect any origin.
const ALLOWED_ORIGINS = process.env.CORS_ORIGINS
? process.env.CORS_ORIGINS.split(",").map((o) => o.trim())
: null; // null = allow all (dev mode)
app.use((req, res, next) => {
const origin = req.headers.origin;
if (origin) {
const isAllowed = !ALLOWED_ORIGINS || ALLOWED_ORIGINS.includes(origin);
if (isAllowed) {
res.header("Access-Control-Allow-Origin", origin);
}
}
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization",
);
res.header("Access-Control-Allow-Credentials", "true");
// Handle preflight requests
if (req.method === "OPTIONS") {
res.sendStatus(200);
return;
}
next();
});
app.use(express.json({ limit: "50mb" }));
app.use(express.urlencoded({ limit: "50mb", extended: true }));
registerOAuthRoutes(app);
app.get("/api/health", (_req, res) => {
res.json({ ok: true, timestamp: Date.now() });
});
app.use(
"/api/trpc",
createExpressMiddleware({
router: appRouter,
createContext,
}),
);
const preferredPort = parseInt(process.env.PORT || "3000");
const port = await findAvailablePort(preferredPort);
if (port !== preferredPort) {
console.warn(`⚠️ Port ${preferredPort} is busy, using port ${port} instead`);
console.warn(`⚠️ Update EXPO_PUBLIC_API_BASE_URL in .env to use port ${port}`);
}
// تسجيل WebSocket للتعرف الفوري على الصوت
registerVoiceWebSocket(server);
server.listen(port, "0.0.0.0", () => {
console.log(`[api] server listening on http://0.0.0.0:${port}`);
console.log(`[api] LAN clients should connect to http://<YOUR_PC_IP>:${port}`);
});
}
startServer().catch(console.error);