/** * rSocials module — campaign strategy workflow builder. * * Proxies campaign API + embeds the Next.js campaign editor from rsocials:3000. * Page routes render an iframe inside the rSpace shell so the campaign builder * gets the full rSpace header/nav while the Next.js app runs independently. */ import { Hono } from "hono"; import { renderShell } from "../../server/shell"; import type { RSpaceModule } from "../../shared/module"; import { getModuleInfoList } from "../../shared/module"; const RSOCIALS_INTERNAL = process.env.RSOCIALS_URL || "http://rsocials:3000"; const RSOCIALS_PUBLIC = "https://rsocials.online"; const routes = new Hono(); // ── API proxy ──────────────────────────────────────────── // Proxy all campaign API calls to the rsocials container routes.get("/api/campaigns", async (c) => { const res = await fetch(`${RSOCIALS_INTERNAL}/api/campaigns`); return c.json(await res.json(), res.status as StatusCode); }); routes.get("/api/campaigns/:id", async (c) => { const res = await fetch(`${RSOCIALS_INTERNAL}/api/campaigns/${c.req.param("id")}`); return c.json(await res.json(), res.status as StatusCode); }); routes.post("/api/campaigns", async (c) => { const body = await c.req.text(); const res = await fetch(`${RSOCIALS_INTERNAL}/api/campaigns`, { method: "POST", headers: { "Content-Type": "application/json" }, body, }); return c.json(await res.json(), res.status as StatusCode); }); routes.put("/api/campaigns/:id", async (c) => { const body = await c.req.text(); const res = await fetch(`${RSOCIALS_INTERNAL}/api/campaigns/${c.req.param("id")}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body, }); return c.json(await res.json(), res.status as StatusCode); }); routes.delete("/api/campaigns/:id", async (c) => { const res = await fetch(`${RSOCIALS_INTERNAL}/api/campaigns/${c.req.param("id")}`, { method: "DELETE", }); return c.json(await res.json(), res.status as StatusCode); }); // ── Page routes ────────────────────────────────────────── function campaignFrame(src: string, space: string, title: string) { return renderShell({ title, moduleId: "rsocials", spaceSlug: space, modules: getModuleInfoList(), theme: "dark", styles: ``, body: `
`, }); } // /rsocials/ → campaign list routes.get("/", (c) => { const space = c.req.param("space") || "demo"; return c.html( campaignFrame(`${RSOCIALS_PUBLIC}/campaigns`, space, `Campaigns | rSocials`) ); }); // /rsocials/campaign → campaign list (alias) routes.get("/campaign", (c) => { const space = c.req.param("space") || "demo"; return c.html( campaignFrame(`${RSOCIALS_PUBLIC}/campaigns`, space, `Campaigns | rSocials`) ); }); // /rsocials/campaign/:id → specific campaign editor routes.get("/campaign/:id", (c) => { const space = c.req.param("space") || "demo"; const id = c.req.param("id"); return c.html( campaignFrame( `${RSOCIALS_PUBLIC}/campaigns/${id}`, space, `Campaign Editor | rSocials` ) ); }); type StatusCode = 200 | 201 | 204 | 400 | 401 | 403 | 404 | 409 | 500 | 502; export const rsocialsModule: RSpaceModule = { id: "rsocials", name: "rSocials", icon: "\uD83D\uDCE2", description: "Campaign strategy workflow builder", routes, standaloneDomain: "rsocials.online", };