diff --git a/config/demoAccount.ts b/config/demoAccount.ts index 32918f0..af97476 100644 --- a/config/demoAccount.ts +++ b/config/demoAccount.ts @@ -26,6 +26,21 @@ export const DEMO_PROVIDER = "google"; /** Marks a provider entry as demo-issued rather than user-supplied. */ export const DEMO_ENTRY_TYPE = "demo"; +/** + * Where the demo proxy lives when nothing overrides it. + * + * This string ends up compiled into every installed copy, and an installed + * copy is not something that can be corrected later — a user on an older + * version keeps asking the old host forever. It was `demo.woopcode.dev` + * before this, a domain that was never registered, so the only thing every + * install did was fail to resolve it. + * + * The escape hatch, if the proxy ever moves off Railway, is a CNAME on a + * domain that *is* owned, pointed wherever the service goes. Changing this + * constant again only helps people who upgrade. + */ +const DEFAULT_DEMO_ENDPOINT = "https://woopcode-demo-proxy-production.up.railway.app"; + /** * The proxy Woopcode's demo talks to. * @@ -36,7 +51,7 @@ export const DEMO_ENTRY_TYPE = "demo"; export function demoEndpoint( env: Record = process.env, ): string { - return (env.WOOPCODE_DEMO_URL?.trim() || "https://demo.woopcode.dev").replace( + return (env.WOOPCODE_DEMO_URL?.trim() || DEFAULT_DEMO_ENDPOINT).replace( /\/+$/, "", ); diff --git a/packages/tests/config/demoMode.test.ts b/packages/tests/config/demoMode.test.ts index 510a902..d6afb1e 100644 --- a/packages/tests/config/demoMode.test.ts +++ b/packages/tests/config/demoMode.test.ts @@ -47,6 +47,32 @@ beforeEach(async () => { ); }); +describe("the default endpoint", () => { + // The default is compiled into every installed copy and cannot be corrected + // for anyone who does not upgrade. It shipped once pointing at + // demo.woopcode.dev, a domain that was never registered, so every install + // reported the demo unreachable and fell through to the key prompt. + test("is not the unregistered host it used to be", () => { + expect(demoEndpoint({})).not.toContain("demo.woopcode.dev"); + }); + + test("is an absolute https URL with no trailing slash", () => { + const endpoint = demoEndpoint({}); + expect(endpoint).toStartWith("https://"); + expect(endpoint).not.toEndWith("/"); + }); + + test("an override wins and is normalised", () => { + expect(demoEndpoint({ WOOPCODE_DEMO_URL: "http://localhost:8787///" })).toBe( + "http://localhost:8787", + ); + }); + + test("a blank override falls back rather than producing an empty URL", () => { + expect(demoEndpoint({ WOOPCODE_DEMO_URL: " " })).toBe(demoEndpoint({})); + }); +}); + describe("a demo entry survives being stored", () => { // The regression this file exists for. normalizeConfig rebuilds every // provider entry field by field, so a field it does not name is dropped on