import express from "express"; import path from "path"; import { fileURLToPath } from "url"; import dotenv from "dotenv"; import cookieParser from "cookie-parser"; import { createRepo, uploadFiles, whoAmI, spaceInfo, } from "@huggingface/hub"; import { InferenceClient } from "@huggingface/inference"; import bodyParser from "body-parser"; import checkUser from "./middlewares/checkUser.js"; // Assuming this middleware exists // Removed PROVIDERS import import { COLORS } from "./utils/colors.js"; // Assuming this utility exists // Load environment variables from .env file dotenv.config(); const app = express(); const ipAddresses = new Map(); // For rate limiting unauthenticated users const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const PORT = process.env.APP_PORT || 3000; const REDIRECT_URI = process.env.REDIRECT_URI || `http://localhost:${PORT}/auth/login`; // --- Updated Model ID --- const MODEL_ID = "deepseek-ai/deepseek-llm-7b-chat"; // Using the chat model const MAX_NEW_TOKENS = 512; // Default max tokens for generation const MAX_REQUESTS_PER_IP = 5; // Rate limit for unauthenticated users app.use(cookieParser()); app.use(bodyParser.json()); // Serve static files from 'dist' and also the root for the new index.html app.use(express.static(path.join(__dirname, "dist"))); app.use(express.static(path.join(__dirname))); // Serve index.html from root // --- Helper Function (Keep as is) --- const getPTag = (repoId) => { // ... (keep the original getPTag function) return `
`; }; // --- Auth Routes (Keep as is) --- app.get("/api/login", (_req, res) => { // ... (keep original /api/login) res.redirect( 302, `https://huggingface.co/oauth/authorize?client_id=${process.env.OAUTH_CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=openid%20profile%20write-repos%20manage-repos%20inference-api&prompt=consent&state=1234567890` ); }); app.get("/auth/login", async (req, res) => { // ... (keep original /auth/login) const { code } = req.query; if (!code) { return res.redirect(302, "/"); } const Authorization = `Basic ${Buffer.from( `${process.env.OAUTH_CLIENT_ID}:${process.env.OAUTH_CLIENT_SECRET}` ).toString("base64")}`; try { const request_auth = await fetch("https://huggingface.co/oauth/token", { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded", Authorization, }, body: new URLSearchParams({ grant_type: "authorization_code", code: code, redirect_uri: REDIRECT_URI, }), }); const response = await request_auth.json(); if (!response.access_token) { console.error("OAuth Error:", response); return res.redirect(302, "/?error=auth_failed"); } res.cookie("hf_token", response.access_token, { httpOnly: false, // Set to true if JS doesn't need to read it directly secure: process.env.NODE_ENV === 'production', // Use secure cookies in production sameSite: "lax", // More common default than 'none' unless cross-site needed maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days }); return res.redirect(302, "/"); } catch(err) { console.error("Error during OAuth token exchange:", err); return res.redirect(302, "/?error=auth_exception"); } }); app.get("/auth/logout", (req, res) => { // ... (keep original /auth/logout) res.clearCookie("hf_token", { httpOnly: false, secure: process.env.NODE_ENV === 'production', sameSite: "lax", }); return res.redirect(302, "/"); }); // --- User Info Route (Keep as is) --- app.get("/api/@me", checkUser, async (req, res) => { // ... (keep original /api/@me) const { hf_token } = req.cookies; try { const request_user = await fetch("https://huggingface.co/oauth/userinfo", { headers: { Authorization: `Bearer ${hf_token}`, }, }); if (!request_user.ok) { throw new Error(`User info request failed with status ${request_user.status}`); } const user = await request_user.json(); res.send(user); } catch (err) { console.error("Error fetching user info:", err.message); // Don't clear cookie on transient errors, only perhaps on 401? // res.clearCookie("hf_token", { ... }); res.status(401).send({ ok: false, message: err.message, }); } }); // --- Deploy Route (Keep as is, maybe update html replace logic if needed) --- app.post("/api/deploy", checkUser, async (req, res) => { // ... (keep original /api/deploy, ensure getPTag logic matches if you modify it) const { html, title, path } = req.body; if (!html || !title) { return res.status(400).send({ ok: false, message: "Missing required fields", }); } const { hf_token } = req.cookies; try { const repo = { type: "space", name: path ?? "", }; let readme; let newHtml = html; if (!path || path === "") { const { name: username } = await whoAmI({ accessToken: hf_token }); const newTitle = title .toLowerCase() .replace(/[^a-z0-9]+/g, "-") .split("-") .filter(Boolean) .join("-") .slice(0, 96); const repoId = `${username}/${newTitle}`; repo.name = repoId; // Check if repo exists before creating? Might need adjustment await createRepo({ repo, accessToken: hf_token, spaceSdk: "static", // Explicitly set SDK for new repos }); const colorFrom = COLORS[Math.floor(Math.random() * COLORS.length)]; const colorTo = COLORS[Math.floor(Math.random() * COLORS.length)]; readme = `--- title: ${newTitle} emoji: 🐳 colorFrom: ${colorFrom} colorTo: ${colorTo} sdk: static pinned: false tags: - deepsite --- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference`; } // Ensure the p-tag replacement is robust const pTag = getPTag(repo.name); // Generate the tag to add/replace // Remove existing tag if present before adding newHtml = newHtml.replace(//s, ""); newHtml = newHtml.replace(/<\/body>/i, `${pTag}