emotions / server.mjs
tfrere's picture
tfrere HF Staff
feat(deploy): switch Space from static to Docker SDK
9bd4f7f
Raw
History Blame Contribute Delete
3.07 kB
/**
* Tiny static file server for the Docker Space runtime.
*
* On `sdk: static` Spaces, HF injects `window.huggingface.variables`
* (OAuth client id, space host, ...) into the served HTML natively.
* On `sdk: docker` Spaces it does NOT - those values arrive as
* environment variables instead. This server reproduces the native
* injection: it splices a `window.huggingface` bootstrap script into
* `index.html` at request time from the process env, so the SDK's
* `authenticate()` keeps working exactly like on a static Space.
*/
import http from "node:http";
import { readFile, stat } from "node:fs/promises";
import { extname, join, normalize } from "node:path";
import { fileURLToPath } from "node:url";
const ROOT = fileURLToPath(new URL("./dist/", import.meta.url));
const PORT = Number(process.env.PORT) || 8080;
const MIME = {
".html": "text/html; charset=utf-8",
".js": "text/javascript; charset=utf-8",
".mjs": "text/javascript; charset=utf-8",
".css": "text/css; charset=utf-8",
".json": "application/json; charset=utf-8",
".svg": "image/svg+xml",
".png": "image/png",
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".gif": "image/gif",
".webp": "image/webp",
".ico": "image/x-icon",
".mp3": "audio/mpeg",
".wav": "audio/wav",
".woff": "font/woff",
".woff2": "font/woff2",
".ttf": "font/ttf",
".map": "application/json; charset=utf-8",
".txt": "text/plain; charset=utf-8",
};
// Only public-safe variables - never expose OAUTH_CLIENT_SECRET.
const hfVariables = {
OAUTH_CLIENT_ID: process.env.OAUTH_CLIENT_ID,
OAUTH_SCOPES: process.env.OAUTH_SCOPES,
OPENID_PROVIDER_URL: process.env.OPENID_PROVIDER_URL,
SPACE_CREATOR_USER_ID: process.env.SPACE_CREATOR_USER_ID,
SPACE_HOST: process.env.SPACE_HOST,
SPACE_ID: process.env.SPACE_ID,
};
const injection = `<script>window.huggingface=${JSON.stringify({
variables: hfVariables,
})};</script>`;
async function serveIndex(res, status = 200) {
let html = await readFile(join(ROOT, "index.html"), "utf8");
html = html.replace("<head>", `<head>${injection}`);
res.writeHead(status, { "content-type": MIME[".html"] });
res.end(html);
}
const server = http.createServer(async (req, res) => {
try {
const path = decodeURIComponent((req.url || "/").split("?")[0]);
if (path === "/" || path === "/index.html") return serveIndex(res);
const resolved = normalize(join(ROOT, path));
if (!resolved.startsWith(ROOT)) {
res.writeHead(403);
return res.end("Forbidden");
}
try {
const info = await stat(resolved);
if (info.isDirectory()) return serveIndex(res);
const body = await readFile(resolved);
res.writeHead(200, {
"content-type": MIME[extname(resolved)] || "application/octet-stream",
});
return res.end(body);
} catch {
// SPA fallback: unknown paths return the app shell.
return serveIndex(res, 200);
}
} catch (err) {
res.writeHead(500);
res.end(String(err));
}
});
server.listen(PORT, () => console.log(`serving dist/ on :${PORT}`));