From b424c26fd9ea5de1cc2ddd85bd72ef708539f7cf Mon Sep 17 00:00:00 2001 From: Raymond Carino Date: Tue, 9 Jun 2026 15:03:48 -0700 Subject: [PATCH 1/2] [NI] Consolidate playground into a single-origin server on $PORT Merge the static UI server (webserver.js, port 3000) and the auth-token proxy (server.js, port 8585) into one Express app listening on process.env.PORT (default 8080). It serves the built React app and the /generateAuthToken[+ anonymous] routes from the same origin. The two-port split was a Create React App dev-server artifact carried into the container unchanged. It only worked because CodeSandbox maps each port to its own subdomain, letting the client reach the proxy via a window.location.origin.replace("3000","8585") hack. On any single-origin host (Cloud Run behind the LB, the future gleansdk domain) that replace is a no-op, so the auth call hit the static server and 404'd. - server.js: serve static build + both auth routes on $PORT||8080, + healthz - webserver.js: deleted (folded into server.js) - useAuthProvider.ts: relative fetch('/generateAuthToken') instead of the port-swap hack; works on localhost, CodeSandbox, and Cloud Run alike - Dockerfile: single process, EXPOSE 8080 - .codesandbox/tasks.json: one task on port 8080 Co-authored-by: Cursor --- .codesandbox/tasks.json | 16 +++------- examples/browser-api-playground/Dockerfile | 6 ++-- examples/browser-api-playground/package.json | 3 +- examples/browser-api-playground/server.js | 31 ++++++++++++------- .../src/useAuthProvider.ts | 9 ++---- examples/browser-api-playground/webserver.js | 20 ------------ 6 files changed, 30 insertions(+), 55 deletions(-) delete mode 100644 examples/browser-api-playground/webserver.js diff --git a/.codesandbox/tasks.json b/.codesandbox/tasks.json index dd7dc00..171b16a 100644 --- a/.codesandbox/tasks.json +++ b/.codesandbox/tasks.json @@ -13,20 +13,12 @@ // These tasks can be run from CodeSandbox. Running one will open a log in the app. "tasks": { - "FE Server": { - "name": "FE Server", - "command": "cd examples/browser-api-playground && yarn && yarn start:client", + "App Server": { + "name": "App Server", + "command": "cd examples/browser-api-playground && yarn && yarn start", "runAtStart": true, "preview": { - "port": 3000 - } - }, - "BE Server": { - "name": "BE Server", - "command": "cd examples/browser-api-playground && yarn && yarn start:server", - "runAtStart": true, - "preview": { - "port": 8585 + "port": 8080 } } } diff --git a/examples/browser-api-playground/Dockerfile b/examples/browser-api-playground/Dockerfile index e66b634..d73855a 100644 --- a/examples/browser-api-playground/Dockerfile +++ b/examples/browser-api-playground/Dockerfile @@ -15,9 +15,9 @@ WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile --production -COPY server.js webserver.js ./ +COPY server.js ./ COPY --from=build /app/build ./build -EXPOSE 8585 8080 +EXPOSE 8080 -CMD node server.js & node webserver.js +CMD ["node", "server.js"] diff --git a/examples/browser-api-playground/package.json b/examples/browser-api-playground/package.json index ecad382..e772212 100644 --- a/examples/browser-api-playground/package.json +++ b/examples/browser-api-playground/package.json @@ -29,8 +29,7 @@ "typescript": "4.4.2" }, "scripts": { - "start:client": "yarn build && node webserver.js", - "start:server": "node server.js", + "start": "yarn build && node server.js", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject" diff --git a/examples/browser-api-playground/server.js b/examples/browser-api-playground/server.js index 6601ddf..a528922 100644 --- a/examples/browser-api-playground/server.js +++ b/examples/browser-api-playground/server.js @@ -1,21 +1,21 @@ const express = require("express"); -const cors = require("cors"); const axios = require("axios"); +const path = require("path"); const app = express(); -const port = 8585; +// Cloud Run injects PORT; default 8080 matches local/CodeSandbox and the +// frontend-service container-port convention so a single origin serves both +// the static UI and the auth-token routes (no cross-port hop, no CORS). +const port = process.env.PORT || 8080; app.use(express.json()); -app.use(cors()); app.post("/generateAuthToken", (req, res) => { - // Extract the backend and user from the request const { backend, actAs, apiKey } = req.body; const tokenApiPath = backend.endsWith("/") - ? `${backend}rest/api/v1/createauthtoken` - : `${backend}/rest/api/v1/createauthtoken`; + ? `${backend}rest/api/v1/createauthtoken` + : `${backend}/rest/api/v1/createauthtoken`; - // Call the Glean server's createauthtoken endpoint axios({ method: "POST", url: tokenApiPath, @@ -30,13 +30,11 @@ app.post("/generateAuthToken", (req, res) => { }); app.post("/generateAnonymousAuthToken", (req, res) => { - // Extract the backend and user from the request - const { backend, actAs } = req.body; + const { backend } = req.body; const tokenApiPath = backend.endsWith("/") - ? `${backend}rest/api/v1/createanonymoustoken` - : `${backend}/rest/api/v1/createanonymoustoken`; + ? `${backend}rest/api/v1/createanonymoustoken` + : `${backend}/rest/api/v1/createanonymoustoken`; - // Call the Glean server's createanonymoustoken endpoint axios({ method: "post", url: tokenApiPath, @@ -45,6 +43,15 @@ app.post("/generateAnonymousAuthToken", (req, res) => { .catch((error) => res.status(500).json({ error: error })); }); +const buildPath = path.join(__dirname, "build"); +app.use(express.static(buildPath)); + +app.get("/_/healthz", (req, res) => res.sendStatus(200)); + +app.get("/*", (req, res) => { + res.sendFile(path.join(buildPath, "index.html")); +}); + app.listen(port, () => { console.log(`Server is running on port ${port}`); }); diff --git a/examples/browser-api-playground/src/useAuthProvider.ts b/examples/browser-api-playground/src/useAuthProvider.ts index 8bfef7e..e34552b 100644 --- a/examples/browser-api-playground/src/useAuthProvider.ts +++ b/examples/browser-api-playground/src/useAuthProvider.ts @@ -9,11 +9,6 @@ interface AuthState { const defaultAuthState: AuthState = { }; -const serverBasePath = (() => { - const feBasePath = window.location.origin; - return feBasePath.replace("3000", "8585"); -})(); - const fetchTokenFromServer = async ( backend: string, authOptions: AuthOptions @@ -22,8 +17,10 @@ const fetchTokenFromServer = async ( authOptions.type == AuthType.Anonymous ? "generateAnonymousAuthToken" : "generateAuthToken"; + // Same-origin relative path: the auth routes are served by the same app as + // this UI, so this resolves correctly on localhost, CodeSandbox, and Cloud Run. return await new Promise((resolve, reject) => - fetch(`${serverBasePath}/${endpoint}`, { + fetch(`/${endpoint}`, { method: "POST", headers: { "Content-Type": "application/json", diff --git a/examples/browser-api-playground/webserver.js b/examples/browser-api-playground/webserver.js deleted file mode 100644 index f0c2c5b..0000000 --- a/examples/browser-api-playground/webserver.js +++ /dev/null @@ -1,20 +0,0 @@ - -const express = require('express'); -const path = require('path'); -const app = express(); - -const buildPath = path.join(__dirname, 'build'); -app.use(express.static(buildPath)); - -app.get('/_/healthz', (req, res) => { - res.sendStatus(200) -}); - -app.get('/*', (req, res) => { - res.sendFile(path.join(buildPath, 'index.html')); -}); - -// Needed for Codesandboxs, will map to 8080 on GCP -app.listen(3000, () => { - console.log('Web server is listening on port 3000'); -}); From 374ed7e397fe846a2dea83eb6ec57ee6694d6e06 Mon Sep 17 00:00:00 2001 From: Raymond Carino Date: Tue, 9 Jun 2026 21:46:25 -0700 Subject: [PATCH 2/2] Assume port 8080 directly (drop $PORT fallback) Co-authored-by: Cursor --- examples/browser-api-playground/server.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/browser-api-playground/server.js b/examples/browser-api-playground/server.js index a528922..aec4443 100644 --- a/examples/browser-api-playground/server.js +++ b/examples/browser-api-playground/server.js @@ -3,10 +3,7 @@ const axios = require("axios"); const path = require("path"); const app = express(); -// Cloud Run injects PORT; default 8080 matches local/CodeSandbox and the -// frontend-service container-port convention so a single origin serves both -// the static UI and the auth-token routes (no cross-port hop, no CORS). -const port = process.env.PORT || 8080; +const port = 8080; app.use(express.json());