feat: reverse-proxy Postiz at /rsocials/scheduler instead of iframe
The rSpace Traefik router catches demo.rsocials.online (priority 120) before the Postiz container can serve it, making iframe embedding fail. Replace the iframe approach with a reverse proxy: /rsocials/scheduler/* proxies to the Postiz container (postiz:5000) on the Docker network. Rewrites redirect headers to stay within the scheduler path. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ea99a83678
commit
bb37727f18
|
|
@ -163,6 +163,10 @@ class FolkSocialsCanvas extends HTMLElement {
|
||||||
return match ? match[0] : "";
|
return match ? match[0] : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getSchedulerUrl(): string {
|
||||||
|
return `${this.getApiBase()}/scheduler`;
|
||||||
|
}
|
||||||
|
|
||||||
private buildCanvasNodes() {
|
private buildCanvasNodes() {
|
||||||
this.canvasNodes = [];
|
this.canvasNodes = [];
|
||||||
for (const c of this.campaigns) {
|
for (const c of this.campaigns) {
|
||||||
|
|
@ -403,7 +407,7 @@ class FolkSocialsCanvas extends HTMLElement {
|
||||||
<span class="sc-postiz-title">Postiz — Post Scheduler</span>
|
<span class="sc-postiz-title">Postiz — Post Scheduler</span>
|
||||||
<button class="sc-postiz-close" id="close-postiz">\u2715</button>
|
<button class="sc-postiz-close" id="close-postiz">\u2715</button>
|
||||||
</div>
|
</div>
|
||||||
<iframe class="sc-postiz-iframe" src="${this.postizOpen ? "https://demo.rsocials.online" : "about:blank"}" title="Postiz"></iframe>
|
<iframe class="sc-postiz-iframe" src="${this.postizOpen ? "${this.getSchedulerUrl()}" : "about:blank"}" title="Postiz"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -419,7 +423,7 @@ class FolkSocialsCanvas extends HTMLElement {
|
||||||
const panel = this.shadow.getElementById("postiz-panel");
|
const panel = this.shadow.getElementById("postiz-panel");
|
||||||
const iframe = panel?.querySelector("iframe");
|
const iframe = panel?.querySelector("iframe");
|
||||||
if (panel) panel.classList.toggle("open", this.postizOpen);
|
if (panel) panel.classList.toggle("open", this.postizOpen);
|
||||||
if (iframe && this.postizOpen) iframe.src = "https://demo.rsocials.online";
|
if (iframe && this.postizOpen) iframe.src = "${this.getSchedulerUrl()}";
|
||||||
if (iframe && !this.postizOpen) iframe.src = "about:blank";
|
if (iframe && !this.postizOpen) iframe.src = "about:blank";
|
||||||
});
|
});
|
||||||
this.shadow.getElementById("close-postiz")?.addEventListener("click", () => {
|
this.shadow.getElementById("close-postiz")?.addEventListener("click", () => {
|
||||||
|
|
|
||||||
|
|
@ -514,17 +514,84 @@ function renderDemoFeedHTML(): string {
|
||||||
|
|
||||||
// ── Path-based sub-routes ──
|
// ── Path-based sub-routes ──
|
||||||
|
|
||||||
routes.get("/scheduler", (c) => {
|
// ── Postiz reverse proxy at /scheduler/* ──
|
||||||
|
// Proxies to the Postiz container on the Docker network, avoiding
|
||||||
|
// the Traefik priority conflict with rSpace's rsocials.online catch-all.
|
||||||
|
const POSTIZ_UPSTREAM = process.env.POSTIZ_URL || "http://postiz:5000";
|
||||||
|
|
||||||
|
routes.all("/scheduler/*", async (c) => {
|
||||||
|
const subPath = c.req.path.replace(/^\/[^/]+\/rsocials\/scheduler/, "") || "/";
|
||||||
|
const upstreamUrl = `${POSTIZ_UPSTREAM}${subPath}`;
|
||||||
|
const url = new URL(upstreamUrl);
|
||||||
|
// Preserve query string
|
||||||
|
const reqUrl = new URL(c.req.url);
|
||||||
|
url.search = reqUrl.search;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const headers = new Headers(c.req.raw.headers);
|
||||||
|
headers.delete("host");
|
||||||
|
|
||||||
|
const resp = await fetch(url.toString(), {
|
||||||
|
method: c.req.method,
|
||||||
|
headers,
|
||||||
|
body: c.req.method !== "GET" && c.req.method !== "HEAD" ? c.req.raw.body : undefined,
|
||||||
|
redirect: "manual",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rewrite Location headers to stay within /scheduler/
|
||||||
|
const respHeaders = new Headers(resp.headers);
|
||||||
|
const location = respHeaders.get("location");
|
||||||
|
if (location) {
|
||||||
|
try {
|
||||||
|
const locUrl = new URL(location, upstreamUrl);
|
||||||
|
if (locUrl.origin === new URL(POSTIZ_UPSTREAM).origin) {
|
||||||
|
const space = c.req.param("space") || "demo";
|
||||||
|
respHeaders.set("location", `/${space}/rsocials/scheduler${locUrl.pathname}${locUrl.search}`);
|
||||||
|
}
|
||||||
|
} catch { /* keep original */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(resp.body, {
|
||||||
|
status: resp.status,
|
||||||
|
headers: respHeaders,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return c.text("Postiz scheduler unavailable", 502);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
routes.get("/scheduler", async (c) => {
|
||||||
const space = c.req.param("space") || "demo";
|
const space = c.req.param("space") || "demo";
|
||||||
return c.html(renderExternalAppShell({
|
const upstreamUrl = `${POSTIZ_UPSTREAM}/`;
|
||||||
title: `${space} — Postiz | rSpace`,
|
try {
|
||||||
moduleId: "rsocials",
|
const headers = new Headers(c.req.raw.headers);
|
||||||
spaceSlug: space,
|
headers.delete("host");
|
||||||
modules: getModuleInfoList(),
|
const reqUrl = new URL(c.req.url);
|
||||||
appUrl: "https://demo.rsocials.online",
|
|
||||||
appName: "Postiz",
|
const resp = await fetch(`${upstreamUrl}${reqUrl.search}`, {
|
||||||
theme: "dark",
|
method: "GET",
|
||||||
}));
|
headers,
|
||||||
|
redirect: "manual",
|
||||||
|
});
|
||||||
|
|
||||||
|
const respHeaders = new Headers(resp.headers);
|
||||||
|
const location = respHeaders.get("location");
|
||||||
|
if (location) {
|
||||||
|
try {
|
||||||
|
const locUrl = new URL(location, upstreamUrl);
|
||||||
|
if (locUrl.origin === new URL(POSTIZ_UPSTREAM).origin) {
|
||||||
|
respHeaders.set("location", `/${space}/rsocials/scheduler${locUrl.pathname}${locUrl.search}`);
|
||||||
|
}
|
||||||
|
} catch { /* keep original */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Response(resp.body, {
|
||||||
|
status: resp.status,
|
||||||
|
headers: respHeaders,
|
||||||
|
});
|
||||||
|
} catch {
|
||||||
|
return c.text("Postiz scheduler unavailable", 502);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
routes.get("/feed", (c) => {
|
routes.get("/feed", (c) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue