Derive API path from frontend config URL

This commit is contained in:
2026-08-25 16:53:58 +00:00
parent f79415d2f6
commit f6fb033eb8
3 changed files with 63 additions and 2 deletions
+9
View File
@@ -17,6 +17,7 @@ COPY upstream/HubFrontend/ ./
COPY docker/hcaptcha-sitekey.patch /tmp/hcaptcha-sitekey.patch COPY docker/hcaptcha-sitekey.patch /tmp/hcaptcha-sitekey.patch
COPY docker/remove-analytics.mjs /tmp/remove-analytics.mjs COPY docker/remove-analytics.mjs /tmp/remove-analytics.mjs
COPY docker/replace-fallback-avatar.mjs /tmp/replace-fallback-avatar.mjs COPY docker/replace-fallback-avatar.mjs /tmp/replace-fallback-avatar.mjs
COPY docker/use-config-url-api-path.mjs /tmp/use-config-url-api-path.mjs
RUN if grep -q 'sitekey="1788882d-3695-4807-abac-7d7166ec6325"' src/routes/auth/login.js; then \ RUN if grep -q 'sitekey="1788882d-3695-4807-abac-7d7166ec6325"' src/routes/auth/login.js; then \
patch -p1 < /tmp/hcaptcha-sitekey.patch; \ patch -p1 < /tmp/hcaptcha-sitekey.patch; \
@@ -29,6 +30,7 @@ RUN if grep -q 'sitekey="1788882d-3695-4807-abac-7d7166ec6325"' src/routes/auth/
RUN node /tmp/remove-analytics.mjs RUN node /tmp/remove-analytics.mjs
RUN node /tmp/replace-fallback-avatar.mjs RUN node /tmp/replace-fallback-avatar.mjs
RUN node /tmp/use-config-url-api-path.mjs
ARG ASSETS_BASE="" ARG ASSETS_BASE=""
ARG VITE_USE_MULTIHUB=false ARG VITE_USE_MULTIHUB=false
@@ -45,6 +47,13 @@ ENV ASSETS_BASE=${ASSETS_BASE} \
RUN test -n "$VITE_HCAPTCHA_SITEKEY" \ RUN test -n "$VITE_HCAPTCHA_SITEKEY" \
|| (echo "VITE_HCAPTCHA_SITEKEY must be set." >&2; exit 1) || (echo "VITE_HCAPTCHA_SITEKEY must be set." >&2; exit 1)
RUN if [ "$VITE_USE_MULTIHUB" != "true" ]; then \
case "$VITE_CONFIG_URL" in \
*/client/config/global|*/client/config/global/) ;; \
*) echo "VITE_CONFIG_URL must end with /client/config/global." >&2; exit 1 ;; \
esac; \
fi
RUN npm run build RUN npm run build
# Electron entry points are not part of the web deployment. # Electron entry points are not part of the web deployment.
+4 -2
View File
@@ -40,8 +40,10 @@ as `VITE_HCAPTCHA_SITEKEY`. Set the related secret in the backend
not a secret. not a secret.
Enable the `client-config` external plugin in the backend configuration. The Enable the `client-config` external plugin in the backend configuration. The
backend `abbr` value must match the API prefix without its leading slash. For single-hub build derives the API base URL from `VITE_CONFIG_URL`. The backend
example, use `"abbr": "api"` with `"prefix": "/api"`. `abbr` can contain the VTC abbreviation and does not have to match the API
prefix. This deployment-specific behavior does not apply when
`VITE_USE_MULTIHUB` is `true`.
The frontend uses the Vite values during the image build. Rebuild the image after The frontend uses the Vite values during the image build. Rebuild the image after
you change `.env`, including the hCaptcha site key. you change `.env`, including the hCaptcha site key.
+50
View File
@@ -0,0 +1,50 @@
import { readFileSync, writeFileSync } from "node:fs";
const loaderPath = "src/components/loader.js";
let source = readFileSync(loaderPath, "utf8");
const upstreamApiPath = "`${webConfig.api_host}/${webConfig.abbr}`";
const deploymentApiPath = "getApiPath(webConfig)";
const helperMarker = "function getApiPath(webConfig) {";
const insertBefore = "function sleep(ms) {";
const occurrences = source.split(upstreamApiPath).length - 1;
if (occurrences === 3 && !source.includes(helperMarker)) {
const helper = `function getApiPath(webConfig) {
if (import.meta.env.VITE_USE_MULTIHUB == "true") {
return \`${upstreamApiPath.slice(1, -1)}\`;
}
const configUrl = new URL(import.meta.env.VITE_CONFIG_URL);
const endpoint = "/client/config/global";
const pathname = configUrl.pathname.replace(/\\/+$/, "");
if (!pathname.endsWith(endpoint)) {
throw new Error("VITE_CONFIG_URL must end with /client/config/global.");
}
configUrl.pathname = pathname.slice(0, -endpoint.length) || "/";
configUrl.search = "";
configUrl.hash = "";
return configUrl.toString().replace(/\\/$/, "");
}
`;
if (!source.includes(insertBefore)) {
throw new Error("Cannot locate the API path helper insertion point.");
}
source = source.replace(insertBefore, helper + insertBefore);
source = source.replaceAll(upstreamApiPath, deploymentApiPath);
console.log("Use VITE_CONFIG_URL as the single-hub API path source.");
} else if (occurrences === 0 && !/api_host[^;\n]{0,80}abbr/.test(source)) {
console.log("Upstream does not contain the known API path dependency; skip the patch.");
} else {
throw new Error(`Unsupported upstream API path implementation (${occurrences} known references).`);
}
if (source.includes(upstreamApiPath) && !source.includes("VITE_USE_MULTIHUB")) {
throw new Error("The upstream API path dependency remains without a multihub fallback.");
}
writeFileSync(loaderPath, source);