Files
Sylvain Duchesne 5e3e821e2a Run locally like the sibling apps: fixed ports, the pod provider in Docker, the app outside
Festipod now follows the local convention of welcometomyplace, mutual-aid.app
and portejunes: one fixed port pair per app (Festipod defaults: backend 3005,
app 4005; pod provider 3000/5000), overridable in backend/.env and .env.
`make start` runs docker-compose-dev.yml (the local pod provider from images,
Fuseki, Redis, mailcatcher, Arena); the backend and the app run outside Docker
with `cd backend && pnpm dev` and `pnpm dev`. pnpm stays the package manager.

The old docker-compose.yml, which containerized Festipod's own frontend and
backend and could not reach the host's Fuseki and Redis, is gone; portless is
dropped from the dev script, since the backend declares a single OIDC redirect
URI. The local backend runs without a Redis cache, as the sibling apps do. The
e2e suites and validate read the app, backend and pod provider URLs from the
env files instead of hardcoding them.

The deployment and local cookbook leaves record the traps met while resetting
datasets: a dataset re-created under the same name needs a Fuseki restart
(ClosedException otherwise), the anonymous WebACL probe at boot is expected,
and a change of the backend's URL leaves persistent accounts with a
participations collection the new app identity cannot control.
2026-11-01 11:40:27 +01:00

36 lines
1.9 KiB
JavaScript

// The path the backend is served under, read from its base URL (SEMAPPS_HOME_URL): `/` when the
// backend owns its origin (http://localhost:3005 locally), `/api/` when it shares the front end's
// origin (https://<host>/api/, the Coolify layout, where one base URL per environment keeps pull
// request previews on a single host). The proxy in front passes the path through unchanged; SemApps
// mounts every route it adds under the base path, except the `/.well-known` ones, which stay at the
// origin root. Festipod's own routes and its public-surface allow-list follow the same split.
const urlJoin = require('url-join');
/** basePathOf(baseUrl) → the base URL's path, always ending with `/` (`/` when it has none or is unset). */
function basePathOf(baseUrl) {
if (!baseUrl) return '/';
const { pathname } = new URL(baseUrl);
return pathname.endsWith('/') ? pathname : `${pathname}/`;
}
/** underBasePath(basePath, path) → the absolute `path` (e.g. `/catalog`) as mounted under `basePath`. */
function underBasePath(basePath, path) {
return basePath + path.replace(/^\/+/, '');
}
/**
* requestUri(baseUrl, requestPath) → the absolute URI a request was made to. `requestPath` is the raw
* path the gateway received (moleculer-web's `originalUrl`), base path included: the base path is
* taken off before joining it to the base URL, which would otherwise repeat it. Joining (rather than
* resolving with `new URL`) keeps the base URL exactly as written — host case, explicit port — so the
* result matches the URIs the backend mints from the same base URL, its actor's first.
*/
function requestUri(baseUrl, requestPath) {
const basePath = basePathOf(baseUrl);
const relative = requestPath.startsWith(basePath) ? requestPath.slice(basePath.length - 1) : requestPath;
return urlJoin(baseUrl, relative);
}
module.exports = { basePathOf, underBasePath, requestUri };