78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import { Hono } from "hono";
|
|
import { logger } from "hono/logger";
|
|
import { cors } from "hono/cors";
|
|
import { initDb } from "./db/schema.js";
|
|
import { InstanceStore } from "./db/queries.js";
|
|
import { siweAuth } from "./middleware/siwe-auth.js";
|
|
import { tokenGate } from "./middleware/token-gate.js";
|
|
import { rateLimiter, provisionRateLimiter } from "./middleware/rate-limit.js";
|
|
import { setupX402FromEnv } from "./middleware/x402.js";
|
|
import { healthRoutes } from "./routes/health.js";
|
|
import { authRoutes } from "./routes/auth.js";
|
|
import { spacesRoutes } from "./routes/spaces.js";
|
|
import { provisionRoutes } from "./routes/provision.js";
|
|
import { usageRoutes } from "./routes/usage.js";
|
|
import { adminRoutes } from "./routes/admin.js";
|
|
|
|
const PORT = parseInt(process.env.PORT ?? "3001", 10);
|
|
const DB_PATH = process.env.DATABASE_PATH ?? "./data/instances.db";
|
|
|
|
// Initialize database
|
|
const db = initDb(DB_PATH);
|
|
const store = new InstanceStore(db);
|
|
|
|
// Create app
|
|
const app = new Hono();
|
|
|
|
// Global middleware
|
|
app.use("*", logger());
|
|
app.use("*", cors());
|
|
|
|
// Public routes
|
|
app.route("/health", healthRoutes(store));
|
|
app.route("/v1/auth", authRoutes());
|
|
|
|
// Protected routes (SIWE wallet or API key)
|
|
app.use("/v1/spaces/*", siweAuth);
|
|
app.use("/v1/spaces/*", tokenGate);
|
|
app.use("/v1/spaces/*", rateLimiter);
|
|
|
|
// x402 payment gate on provisioning (only if X402_PAY_TO is set)
|
|
const x402Middleware = setupX402FromEnv();
|
|
if (x402Middleware) {
|
|
// Apply x402 only to POST (provisioning) and pay endpoint
|
|
app.use("/v1/spaces", async (c, next) => {
|
|
if (c.req.method === "POST") return x402Middleware(c, next);
|
|
return next();
|
|
});
|
|
}
|
|
|
|
// Provision rate limiter (stricter — 2/hour)
|
|
app.post("/v1/spaces", provisionRateLimiter);
|
|
|
|
// Space routes
|
|
app.route("/v1/spaces", provisionRoutes(store));
|
|
app.route("/v1/spaces", spacesRoutes(store));
|
|
app.route("/v1/spaces", usageRoutes(store));
|
|
|
|
// Admin routes (API key only)
|
|
app.use("/v1/admin/*", siweAuth); // reuse auth (checks API key first)
|
|
app.use("/v1/admin/*", rateLimiter);
|
|
app.route("/v1/admin", adminRoutes(store));
|
|
|
|
// 404 handler
|
|
app.notFound((c) => c.json({ error: "Not found" }, 404));
|
|
|
|
// Error handler
|
|
app.onError((err, c) => {
|
|
console.error("Unhandled error:", err);
|
|
return c.json({ error: "Internal server error" }, 500);
|
|
});
|
|
|
|
console.log(`rSocials API starting on port ${PORT}`);
|
|
|
|
export default {
|
|
port: PORT,
|
|
fetch: app.fetch,
|
|
};
|