From 2907935c50587a859c2966ee0aba79754556b3cb Mon Sep 17 00:00:00 2001 From: Jeff Emmett Date: Tue, 31 Mar 2026 22:46:33 -0700 Subject: [PATCH] fix(rtime): use getApiBase() for subdomain-compatible URL routing Replace all hardcoded /${space}/rtime paths with getApiBase() which derives the correct API base from window.location.pathname. This supports both subdomain routing (demo.rspace.online/rtime) and path-based fallback (/demo/rtime). Co-Authored-By: Claude Opus 4.6 --- modules/rtime/components/folk-timebank-app.ts | 21 ++++++++++++------- modules/rtime/mod.ts | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/modules/rtime/components/folk-timebank-app.ts b/modules/rtime/components/folk-timebank-app.ts index 1cae700..f6c0732 100644 --- a/modules/rtime/components/folk-timebank-app.ts +++ b/modules/rtime/components/folk-timebank-app.ts @@ -316,12 +316,19 @@ class FolkTimebankApp extends HTMLElement { this.fetchData(); } + /** Derive API base from the current pathname — works for both subdomain and path routing. */ + private getApiBase(): string { + const path = window.location.pathname; + const match = path.match(/^(\/[^/]+)?\/rtime/); + return match ? match[0] : '/rtime'; + } + disconnectedCallback() { if (this.animFrame) cancelAnimationFrame(this.animFrame); } private async fetchData() { - const base = `/${this.space}/rtime`; + const base = this.getApiBase(); try { const [cResp, tResp] = await Promise.all([ fetch(`${base}/api/commitments`), @@ -788,7 +795,7 @@ class FolkTimebankApp extends HTMLElement { // Try server-side persist try { - const resp = await fetch(`/${this.space}/rtime/api/commitments`, { + const resp = await fetch(`${this.getApiBase()}/api/commitments`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ memberName: name, skill, hours, desc }), @@ -1449,7 +1456,7 @@ class FolkTimebankApp extends HTMLElement { const description = (this.shadow.getElementById('intentDesc') as HTMLInputElement).value; try { - const resp = await fetch(`/${this.space}/rtime/api/intent`, { + const resp = await fetch(`${this.getApiBase()}/api/intent`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type, skill, hours, description }), @@ -1468,7 +1475,7 @@ class FolkTimebankApp extends HTMLElement { private async triggerSolver() { try { - await fetch(`/${this.space}/rtime/api/solver/run`, { method: 'POST' }); + await fetch(`${this.getApiBase()}/api/solver/run`, { method: 'POST' }); this.refreshCollaborate(); } catch { // ignore @@ -1476,7 +1483,7 @@ class FolkTimebankApp extends HTMLElement { } private async refreshCollaborate() { - const base = `/${this.space}/rtime`; + const base = this.getApiBase(); try { const [iResp, sResp, cResp] = await Promise.all([ fetch(`${base}/api/intents`), @@ -1600,7 +1607,7 @@ class FolkTimebankApp extends HTMLElement { btn.addEventListener('click', async () => { const resultId = (btn as HTMLElement).dataset.resultId; try { - await fetch(`/${this.space}/rtime/api/solver-results/${resultId}/accept`, { method: 'POST' }); + await fetch(`${this.getApiBase()}/api/solver-results/${resultId}/accept`, { method: 'POST' }); this.refreshCollaborate(); } catch { /* ignore */ } }); @@ -1610,7 +1617,7 @@ class FolkTimebankApp extends HTMLElement { btn.addEventListener('click', async () => { const resultId = (btn as HTMLElement).dataset.resultId; try { - await fetch(`/${this.space}/rtime/api/solver-results/${resultId}/reject`, { method: 'POST' }); + await fetch(`${this.getApiBase()}/api/solver-results/${resultId}/reject`, { method: 'POST' }); this.refreshCollaborate(); } catch { /* ignore */ } }); diff --git a/modules/rtime/mod.ts b/modules/rtime/mod.ts index 2aea90b..e49be90 100644 --- a/modules/rtime/mod.ts +++ b/modules/rtime/mod.ts @@ -427,6 +427,6 @@ export const timeModule: RSpaceModule = { { path: "collaborate", name: "Collaborate", icon: "🤝", description: "Intent-routed collaboration matching" }, ], onboardingActions: [ - { label: "Pledge Hours", icon: "⏳", description: "Add a commitment to the pool", type: 'create', href: '/{space}/rtime' }, + { label: "Pledge Hours", icon: "⏳", description: "Add a commitment to the pool", type: 'create', href: '/rtime' }, ], };