From 0cf1db56f4223091b3c783942236104d62e345c7 Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Mon, 9 Mar 2026 19:54:10 -0700 Subject: [PATCH] feat(rmeets): register rMeets as rApp with Jitsi embed Adds rMeets module with hub page (Quick Meet, Join Room, Jitsi Lobby) and room pages that embed jeffsi.localvibe.live via renderExternalAppShell. Jitsi URL configurable via JITSI_URL env var. Co-Authored-By: Claude Opus 4.6 --- modules/rmeets/mod.ts | 116 ++++++++++++++++++++++++++++++++++++++++++ server/index.ts | 2 + 2 files changed, 118 insertions(+) create mode 100644 modules/rmeets/mod.ts diff --git a/modules/rmeets/mod.ts b/modules/rmeets/mod.ts new file mode 100644 index 0000000..4484928 --- /dev/null +++ b/modules/rmeets/mod.ts @@ -0,0 +1,116 @@ +/** + * rMeets module — video meetings powered by Jitsi. + * + * Hub page with Quick Meet + room name input, + * room pages embed Jitsi via renderExternalAppShell. + */ + +import { Hono } from "hono"; +import { renderShell, renderExternalAppShell, escapeHtml } from "../../server/shell"; +import { getModuleInfoList } from "../../shared/module"; +import type { RSpaceModule } from "../../shared/module"; + +const JITSI_URL = process.env.JITSI_URL || "https://jeffsi.localvibe.live"; +const routes = new Hono(); + +// ── Room embed ── + +routes.get("/room/:room", (c) => { + const space = c.req.param("space") || "demo"; + const room = c.req.param("room"); + return c.html(renderExternalAppShell({ + title: `${room} — rMeets | rSpace`, + moduleId: "rmeets", + spaceSlug: space, + modules: getModuleInfoList(), + appUrl: `${JITSI_URL}/${encodeURIComponent(room)}`, + appName: "Jitsi Meet", + theme: "dark", + })); +}); + +// ── Direct Jitsi lobby ── + +routes.get("/meet", (c) => { + const space = c.req.param("space") || "demo"; + return c.html(renderExternalAppShell({ + title: `Jitsi Meet — rMeets | rSpace`, + moduleId: "rmeets", + spaceSlug: space, + modules: getModuleInfoList(), + appUrl: JITSI_URL, + appName: "Jitsi Meet", + theme: "dark", + })); +}); + +// ── Hub page ── + +routes.get("/", (c) => { + const space = c.req.param("space") || "demo"; + const base = `/${escapeHtml(space)}/rmeets`; + const randomId = Math.random().toString(36).slice(2, 10); + return c.html(renderShell({ + title: `rMeets — ${space} | rSpace`, + moduleId: "rmeets", + spaceSlug: space, + modules: getModuleInfoList(), + theme: "dark", + styles: ``, + body: `
+

rMeets

+

Video meetings powered by Jitsi — no account required

+ +
`, + })); +}); + +// ── Module export ── + +export const meetsModule: RSpaceModule = { + id: "rmeets", + name: "rMeets", + icon: "📹", + description: "Video meetings powered by Jitsi", + scoping: { defaultScope: "space", userConfigurable: false }, + routes, + externalApp: { url: JITSI_URL, name: "Jitsi Meet" }, +}; diff --git a/server/index.ts b/server/index.ts index e12673f..92382cd 100644 --- a/server/index.ts +++ b/server/index.ts @@ -66,6 +66,7 @@ import { dataModule } from "../modules/rdata/mod"; import { splatModule } from "../modules/rsplat/mod"; import { photosModule } from "../modules/rphotos/mod"; import { socialsModule } from "../modules/rsocials/mod"; +import { meetsModule } from "../modules/rmeets/mod"; // import { docsModule } from "../modules/rdocs/mod"; // import { designModule } from "../modules/rdesign/mod"; import { scheduleModule } from "../modules/rschedule/mod"; @@ -111,6 +112,7 @@ registerModule(socialsModule); // registerModule(docsModule); // placeholder — not yet an rApp // registerModule(designModule); // placeholder — not yet an rApp registerModule(scheduleModule); +registerModule(meetsModule); // ── Config ── const PORT = Number(process.env.PORT) || 3000;