119 lines
4.1 KiB
TypeScript
119 lines
4.1 KiB
TypeScript
/**
|
|
* Funds module — budget flows, river visualization, and treasury management.
|
|
*
|
|
* Proxies flow-service API calls and serves the BudgetRiver visualization.
|
|
*/
|
|
|
|
import { Hono } from "hono";
|
|
import { renderShell } from "../../server/shell";
|
|
import type { RSpaceModule } from "../../shared/module";
|
|
import { getModuleInfoList } from "../../shared/module";
|
|
|
|
const FLOW_SERVICE_URL = process.env.FLOW_SERVICE_URL || "http://payment-flow:3010";
|
|
|
|
const routes = new Hono();
|
|
|
|
// ─── Flow Service API proxy ─────────────────────────────
|
|
// These proxy to the payment-flow backend so the frontend
|
|
// can call them from the same origin.
|
|
|
|
routes.get("/api/flows", async (c) => {
|
|
const owner = c.req.header("X-Owner-Address") || "";
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows?owner=${encodeURIComponent(owner)}`);
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.get("/api/flows/:flowId", async (c) => {
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}`);
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.post("/api/flows", async (c) => {
|
|
const body = await c.req.text();
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body,
|
|
});
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.post("/api/flows/:flowId/deposit", async (c) => {
|
|
const body = await c.req.text();
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/deposit`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body,
|
|
});
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.post("/api/flows/:flowId/withdraw", async (c) => {
|
|
const body = await c.req.text();
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/withdraw`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body,
|
|
});
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.post("/api/flows/:flowId/activate", async (c) => {
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/activate`, { method: "POST" });
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.post("/api/flows/:flowId/pause", async (c) => {
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/pause`, { method: "POST" });
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.post("/api/flows/:flowId/funnels", async (c) => {
|
|
const body = await c.req.text();
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/funnels`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body,
|
|
});
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.post("/api/flows/:flowId/outcomes", async (c) => {
|
|
const body = await c.req.text();
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/outcomes`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body,
|
|
});
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
routes.get("/api/flows/:flowId/transactions", async (c) => {
|
|
const res = await fetch(`${FLOW_SERVICE_URL}/api/flows/${c.req.param("flowId")}/transactions`);
|
|
return c.json(await res.json(), res.status as any);
|
|
});
|
|
|
|
// ─── Page route ─────────────────────────────────────────
|
|
|
|
routes.get("/", (c) => {
|
|
const spaceSlug = c.req.param("space") || "demo";
|
|
return c.html(renderShell({
|
|
title: `${spaceSlug} — Funds | rSpace`,
|
|
moduleId: "funds",
|
|
spaceSlug,
|
|
modules: getModuleInfoList(),
|
|
theme: "light",
|
|
styles: `<link rel="stylesheet" href="/modules/funds/funds.css">`,
|
|
body: `<folk-budget-river simulate="true"></folk-budget-river>`,
|
|
scripts: `<script type="module" src="/modules/funds/folk-budget-river.js"></script>`,
|
|
}));
|
|
});
|
|
|
|
export const fundsModule: RSpaceModule = {
|
|
id: "funds",
|
|
name: "rFunds",
|
|
icon: "\uD83C\uDF0A",
|
|
description: "Budget flows, river visualization, and treasury management",
|
|
routes,
|
|
};
|