121 lines
3.7 KiB
TypeScript
121 lines
3.7 KiB
TypeScript
/**
|
|
* 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: `<style>
|
|
main.rsocials-frame { padding: 0 !important; margin: 0; }
|
|
.rsocials-iframe {
|
|
width: 100%; border: none;
|
|
height: calc(100vh - 57px);
|
|
display: block;
|
|
}
|
|
</style>`,
|
|
body: `<main class="rsocials-frame">
|
|
<iframe class="rsocials-iframe" src="${src}" allow="clipboard-write"></iframe>
|
|
</main>`,
|
|
});
|
|
}
|
|
|
|
// /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",
|
|
};
|