From 25dc4bb81323e12b7825cea21fe667f84f94783f Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:30:01 +0200 Subject: [PATCH 1/6] Update .env.example with backend URLs Added backend and health probe URLs for local development. --- frontend/.env.example | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/frontend/.env.example b/frontend/.env.example index a451b77..18f86a4 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -11,3 +11,21 @@ NEXT_PUBLIC_WORDPRESS_APP_URL=https://calorietoken.net/calorieapp/ # Optional: frontend-only post-login fallback route if you need custom UX. # Keep this app-local (starts with /) and do not put secrets here. # NEXT_PUBLIC_POST_LOGIN_FALLBACK=/ +# Preferred server-side URL used by the same-origin API proxy. +BACKEND_URL=http://localhost:8000 + +# Supported as a deployment-compatible fallback for existing environments. +NEXT_PUBLIC_BACKEND_URL=http://localhost:8000 + +# Optional public backend origin used only for the unauthenticated health +# probe that wakes a sleeping Render service. Login and private data requests +# continue through BACKEND_URL and the same-origin frontend proxy. +NEXT_PUBLIC_BACKEND_WAKE_URL=http://localhost:8000 + +# Same-browser WordPress launcher used only when the app is opened outside the +# [calorieapp_embed] page. Keep this on the canonical CalorieToken site. +NEXT_PUBLIC_WORDPRESS_APP_URL=https://calorietoken.net/calorieapp/ + +# Optional: frontend-only post-login fallback route if you need custom UX. +# Keep this app-local (starts with /) and do not put secrets here. +# NEXT_PUBLIC_POST_LOGIN_FALLBACK=/ From ee33d3ed8686f274a60b3b605a245b2ef5f03750 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:31:23 +0200 Subject: [PATCH 2/6] Clean up .env.example by removing unused variables Removed unnecessary environment variables for clarity. --- frontend/.env.example | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/frontend/.env.example b/frontend/.env.example index 18f86a4..9f61495 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -4,19 +4,6 @@ BACKEND_URL=http://localhost:8000 # Supported as a deployment-compatible fallback for existing environments. NEXT_PUBLIC_BACKEND_URL=http://localhost:8000 -# Same-browser WordPress launcher used only when the app is opened outside the -# [calorieapp_embed] page. Keep this on the canonical CalorieToken site. -NEXT_PUBLIC_WORDPRESS_APP_URL=https://calorietoken.net/calorieapp/ - -# Optional: frontend-only post-login fallback route if you need custom UX. -# Keep this app-local (starts with /) and do not put secrets here. -# NEXT_PUBLIC_POST_LOGIN_FALLBACK=/ -# Preferred server-side URL used by the same-origin API proxy. -BACKEND_URL=http://localhost:8000 - -# Supported as a deployment-compatible fallback for existing environments. -NEXT_PUBLIC_BACKEND_URL=http://localhost:8000 - # Optional public backend origin used only for the unauthenticated health # probe that wakes a sleeping Render service. Login and private data requests # continue through BACKEND_URL and the same-origin frontend proxy. From 3b7814762c5066d1aaf88d083495538e122d87e0 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:32:19 +0200 Subject: [PATCH 3/6] Update backend URL for waiting on backend readiness --- frontend/components/XamanLoginPanel.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/components/XamanLoginPanel.tsx b/frontend/components/XamanLoginPanel.tsx index a0e5ab7..24705e5 100644 --- a/frontend/components/XamanLoginPanel.tsx +++ b/frontend/components/XamanLoginPanel.tsx @@ -3,6 +3,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { announceAuthState } from "@/components/authEvents"; import { + BACKEND_WAKE_BASE_URL, backendRequest, backendUnavailableMessage, BackendRequestTimeoutError, @@ -332,7 +333,7 @@ export async function prepareEmbeddedLogin( throw signal.reason ?? new Error("Login cancelled"); } onProgress("waking-up"); - await waitForBackendReady(BACKEND_BASE_URL, signal); + await waitForBackendReady(BACKEND_WAKE_BASE_URL, signal); return startLoginWithRetry(signal, onProgress, retryWindowMs); } @@ -699,10 +700,10 @@ export function XamanLoginPanel() { } }, 8_000); - // Keep the mobile browser on the CalorieApp origin while Render wakes. - // A direct cross-origin health request can be blocked by browser privacy - // controls before the WordPress/Xaman navigation has even started. - await waitForBackendReady(BACKEND_BASE_URL, controller.signal); + // Wake Render directly from the browser. Requests relayed from the + // frontend Render service can be rate-limited without starting the + // sleeping backend; the health probe is public and sends no credentials. + await waitForBackendReady(BACKEND_WAKE_BASE_URL, controller.signal); window.clearTimeout(startupNoticeTimer); startupNoticeTimer = null; setLoginStatus("Service ready. Opening Xaman..."); From 240d46ae459bbac466544bd441f245590a1229c6 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:32:32 +0200 Subject: [PATCH 4/6] Update backend URL for waiting on backend readiness --- frontend/components/FoodSearchPlaceholder.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/components/FoodSearchPlaceholder.tsx b/frontend/components/FoodSearchPlaceholder.tsx index a4dbfce..2a9908e 100644 --- a/frontend/components/FoodSearchPlaceholder.tsx +++ b/frontend/components/FoodSearchPlaceholder.tsx @@ -14,6 +14,7 @@ import { } from "@/components/authEvents"; import type { AuthStateChangedDetail } from "@/components/authEvents"; import { + BACKEND_WAKE_BASE_URL, backendRequest, backendUnavailableMessage, waitForBackendReady, @@ -372,7 +373,7 @@ export function FoodSearchPlaceholder() { ); try { - await waitForBackendReady(BACKEND_BASE_URL, controller.signal); + await waitForBackendReady(BACKEND_WAKE_BASE_URL, controller.signal); setSearchStatus("Searching foods..."); const response = await backendRequest( From 2871a6b62a90a335358c56d67edbea0c4a291b1a Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:32:57 +0200 Subject: [PATCH 5/6] Define BACKEND_WAKE_BASE_URL for backend health checks Add BACKEND_WAKE_BASE_URL for health probe requests. --- frontend/lib/backendRequest.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frontend/lib/backendRequest.ts b/frontend/lib/backendRequest.ts index e91a4ec..384d48d 100644 --- a/frontend/lib/backendRequest.ts +++ b/frontend/lib/backendRequest.ts @@ -1,6 +1,13 @@ export const DEFAULT_BACKEND_TIMEOUT_MS = 20_000; export const DEFAULT_BACKEND_WARMUP_TIMEOUT_MS = 180_000; +// Render may not wake one free service from another free service's proxy +// request. In production this public URL lets the browser wake the backend +// directly with the unauthenticated health probe; all application requests +// continue to use the same-origin proxy. +export const BACKEND_WAKE_BASE_URL = + process.env.NEXT_PUBLIC_BACKEND_WAKE_URL?.trim() || "/api/backend"; + const BACKEND_WARMUP_ATTEMPT_TIMEOUT_MS = 70_000; const BACKEND_WARMUP_INITIAL_RETRY_DELAY_MS = 5_000; const BACKEND_WARMUP_MAX_RETRY_DELAY_MS = 30_000; From 0390ea4e215cac7f782bd6148baf738cc342cf54 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:33:11 +0200 Subject: [PATCH 6/6] Refactor backend request tests with URL logging Updated the backend wake base URL in tests and modified event logging to include the backend URL. --- tools/tests/xaman_login_start_retry.test.mjs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/tests/xaman_login_start_retry.test.mjs b/tools/tests/xaman_login_start_retry.test.mjs index 0073182..ecfbdb4 100644 --- a/tools/tests/xaman_login_start_retry.test.mjs +++ b/tools/tests/xaman_login_start_retry.test.mjs @@ -83,6 +83,7 @@ test("login start retries transport errors and transient responses", async () => } if (specifier === "@/lib/backendRequest") { return { + BACKEND_WAKE_BASE_URL: "https://backend.example", backendRequest, backendUnavailableMessage: (_error, fallback) => fallback, BackendRequestTimeoutError: TestBackendRequestTimeoutError, @@ -169,14 +170,15 @@ test("embedded login wakes the backend before creating login state", async () => } if (specifier === "@/lib/backendRequest") { return { + BACKEND_WAKE_BASE_URL: "https://backend.example", backendRequest: async () => { events.push("login-start"); return loginResponse; }, backendUnavailableMessage: (_error, fallback) => fallback, BackendRequestTimeoutError: TestBackendRequestTimeoutError, - waitForBackendReady: async () => { - events.push("backend-ready"); + waitForBackendReady: async (backendUrl) => { + events.push(`backend-ready:${backendUrl}`); }, }; } @@ -201,7 +203,10 @@ test("embedded login wakes the backend before creating login state", async () => 10_000 ); - assert.deepEqual(events, ["backend-ready", "login-start"]); + assert.deepEqual(events, [ + "backend-ready:https://backend.example", + "login-start", + ]); assert.deepEqual(phases, ["waking-up"]); assert.equal(result.state, "state-abcdefghijklmnopqrstuvwxyz-0123456789"); }); @@ -244,6 +249,7 @@ test("embedded login does not report progress after cancellation", async () => { } if (specifier === "@/lib/backendRequest") { return { + BACKEND_WAKE_BASE_URL: "https://backend.example", backendRequest: async () => { events.push("login-start"); },