/** * Canvas module — the collaborative infinite canvas. * * This is the original rSpace canvas restructured as an rSpace module. * Routes are relative to the mount point (/:space/rspace in unified mode, * / in standalone mode). */ import { Hono } from "hono"; import { resolve } from "node:path"; import { renderShell } from "../../server/shell"; import { getModuleInfoList } from "../../shared/module"; import type { RSpaceModule } from "../../shared/module"; import { loadCommunity, getDocumentData } from "../../server/community-store"; import { renderLanding } from "./landing"; const DIST_DIR = resolve(import.meta.dir, "../../dist"); const routes = new Hono(); // GET /api/meta — space metadata (owner, members) for space-settings fallback routes.get("/api/meta", async (c) => { const space = c.req.param("space") || "demo"; try { await loadCommunity(space); const doc = getDocumentData(space); if (!doc) return c.json({ meta: {} }); return c.json({ meta: { ownerDID: doc.meta?.ownerDID, members: doc.members } }); } catch { return c.json({ meta: {} }); } }); /** * Extract body content and scripts from the full canvas.html page. * Strips the shell chrome (header, tab-bar, welcome overlay) that renderShell provides, * and returns just the canvas-specific DOM + inline styles + module scripts. */ /** Strip a
and all its nested children by counting open/close tags. */ function stripNestedDiv(html: string, className: string): string { const re = new RegExp(`]*class="[^"]*${className}[^"]*"[^>]*>`); const match = html.match(re); if (!match || match.index === undefined) return html; let depth = 1; let pos = match.index + match[0].length; while (depth > 0 && pos < html.length) { const nextOpen = html.indexOf("", pos); if (nextClose === -1) break; if (nextOpen !== -1 && nextOpen < nextClose) { depth++; pos = nextOpen + 4; } else { depth--; pos = nextClose + 6; } } return html.substring(0, match.index) + html.substring(pos); } function extractCanvasContent(html: string): { body: string; styles: string; scripts: string } { // Extract inline