59 lines
1.7 KiB
TypeScript
59 lines
1.7 KiB
TypeScript
/**
|
|
* Cart standalone server — independent deployment at rcart.online.
|
|
*/
|
|
|
|
import { Hono } from "hono";
|
|
import { cors } from "hono/cors";
|
|
import { resolve } from "node:path";
|
|
import { cartModule } from "./mod";
|
|
|
|
const PORT = Number(process.env.PORT) || 3000;
|
|
const DIST_DIR = resolve(import.meta.dir, "../../dist");
|
|
|
|
const app = new Hono();
|
|
app.use("/api/*", cors({
|
|
origin: "*",
|
|
exposeHeaders: ["X-PAYMENT-REQUIRED", "X-PAYMENT-RESPONSE"],
|
|
allowHeaders: ["Content-Type", "Authorization", "X-PAYMENT", "X-PAYMENT-RESPONSE"],
|
|
}));
|
|
|
|
app.get("/.well-known/webauthn", (c) => {
|
|
return c.json(
|
|
{ origins: ["https://rspace.online"] },
|
|
200,
|
|
{ "Access-Control-Allow-Origin": "*", "Cache-Control": "public, max-age=3600" }
|
|
);
|
|
});
|
|
|
|
app.route("/", cartModule.routes);
|
|
|
|
function getContentType(path: string): string {
|
|
if (path.endsWith(".html")) return "text/html";
|
|
if (path.endsWith(".js")) return "application/javascript";
|
|
if (path.endsWith(".css")) return "text/css";
|
|
if (path.endsWith(".json")) return "application/json";
|
|
if (path.endsWith(".svg")) return "image/svg+xml";
|
|
if (path.endsWith(".png")) return "image/png";
|
|
if (path.endsWith(".ico")) return "image/x-icon";
|
|
return "application/octet-stream";
|
|
}
|
|
|
|
Bun.serve({
|
|
port: PORT,
|
|
async fetch(req) {
|
|
const url = new URL(req.url);
|
|
if (url.pathname !== "/" && !url.pathname.startsWith("/api/")) {
|
|
const assetPath = url.pathname.slice(1);
|
|
if (assetPath.includes(".")) {
|
|
const file = Bun.file(resolve(DIST_DIR, assetPath));
|
|
if (await file.exists()) {
|
|
return new Response(file, { headers: { "Content-Type": getContentType(assetPath) } });
|
|
}
|
|
}
|
|
}
|
|
return app.fetch(req);
|
|
},
|
|
});
|
|
|
|
console.log(`rCart standalone server running on http://localhost:${PORT}`);
|