Skip to content

Commit 98707c2

Browse files
yamcodesCopilotautofix-ci[bot]
authored
fix(www): use v1 docs URL in agent onboarding prompt during pre-release (#1816)
## Summary Resolves an issue where the "Copy prompt" button copied an onboarding prompt linking to `https://arkenv.js.org/llms.txt` (the v0 docs site) instead of `https://arkenv-v1.vercel.app/llms.txt` (the v1 site during pre-release). ### Root Causes 1. `FALLBACK_DOCS_URL` in `apps/www/lib/config/release.ts` was hardcoded to `https://arkenv.js.org`. 2. In Next.js client components (`InstallPanel` is `"use client"`), non-`NEXT_PUBLIC_*` variables (`VERCEL_PROJECT_PRODUCTION_URL` and `VERCEL_URL`) are omitted from client bundles and evaluate to `undefined`, always triggering the fallback. 3. On Vercel, `VERCEL_PROJECT_PRODUCTION_URL` is populated with `arkenv.js.org` (the primary domain of the v0 deployment) across all deployments. Because `getDocsUrl` checked `VERCEL_PROJECT_PRODUCTION_URL` before preview URLs, it resolved to the v0 domain. ### Changes - Updated `FALLBACK_DOCS_URL` to dynamically resolve based on `RELEASE_TAG`: - `https://arkenv-v1.vercel.app` during pre-release (`alpha` / `rc`). - `https://arkenv.js.org` when graduating to GA (empty `RELEASE_TAG`). - Added a guard in `getDocsUrl` to ignore `arkenv.js.org` from `VERCEL_PROJECT_PRODUCTION_URL` while `RELEASE_TAG` is set, preventing pre-release prompt copy from referencing v0 docs. - Checked `NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL` and `NEXT_PUBLIC_VERCEL_URL` alongside server environment variables. - Updated unit tests in `apps/www/lib/config/release.test.ts`. ## Test Plan - [x] `pnpm --filter=www test -- lib/config/release.test.ts components/page/install-panel.test.tsx --run` - [x] `pnpm typecheck` - [x] `pnpm biome check apps/www/lib/config/release.ts apps/www/lib/config/release.test.ts` --------- Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent 232446b commit 98707c2

2 files changed

Lines changed: 84 additions & 19 deletions

File tree

apps/www/lib/config/release.test.ts

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
describe("release config", () => {
1212
beforeEach(() => {
1313
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "");
14+
vi.stubEnv("NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL", "");
15+
vi.stubEnv("NEXT_PUBLIC_VERCEL_URL", "");
1416
vi.stubEnv("VERCEL_PROJECT_PRODUCTION_URL", "");
1517
vi.stubEnv("VERCEL_URL", "");
1618
});
@@ -72,7 +74,9 @@ describe("release config", () => {
7274
expect(RELEASE_CONFIG.agentPrompt).toContain(
7375
"npx arkenv@alpha init --agent",
7476
);
75-
expect(RELEASE_CONFIG.agentPrompt).toContain("/llms.txt");
77+
expect(RELEASE_CONFIG.agentPrompt).toContain(
78+
"https://arkenv-v1.vercel.app/llms.txt",
79+
);
7680
expect(RELEASE_CONFIG.agentPrompt).toContain(
7781
"suggest as a next step (do not install it yourself)",
7882
);
@@ -97,10 +101,24 @@ describe("release config", () => {
97101
});
98102

99103
it("resolves docs URL from VERCEL_PROJECT_PRODUCTION_URL next", () => {
104+
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "");
105+
vi.stubEnv("VERCEL_PROJECT_PRODUCTION_URL", "prod.example");
106+
vi.stubEnv("VERCEL_URL", "preview.example");
107+
expect(getDocsUrl()).toBe("https://prod.example");
108+
});
109+
110+
it("ignores arkenv.js.org from VERCEL_PROJECT_PRODUCTION_URL during pre-release", () => {
100111
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "");
101112
vi.stubEnv("VERCEL_PROJECT_PRODUCTION_URL", "arkenv.js.org");
102-
vi.stubEnv("VERCEL_URL", "arkenv-v1.vercel.app");
103-
expect(getDocsUrl()).toBe("https://arkenv.js.org");
113+
vi.stubEnv("VERCEL_URL", "preview.example");
114+
expect(getDocsUrl()).toBe("https://preview.example");
115+
});
116+
117+
it("ignores https://arkenv.js.org from VERCEL_PROJECT_PRODUCTION_URL during pre-release", () => {
118+
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "");
119+
vi.stubEnv("VERCEL_PROJECT_PRODUCTION_URL", "https://arkenv.js.org");
120+
vi.stubEnv("VERCEL_URL", "preview.example");
121+
expect(getDocsUrl()).toBe("https://preview.example");
104122
});
105123

106124
it("resolves docs URL from VERCEL_URL for preview deploys", () => {
@@ -110,11 +128,33 @@ describe("release config", () => {
110128
expect(getDocsUrl()).toBe("https://arkenv-v1.vercel.app");
111129
});
112130

113-
it("falls back to arkenv.js.org when env is unset", () => {
131+
it("resolves docs URL from NEXT_PUBLIC_VERCEL_URL on client side", () => {
132+
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "");
133+
vi.stubEnv("NEXT_PUBLIC_VERCEL_URL", "preview-client.example");
134+
expect(getDocsUrl()).toBe("https://preview-client.example");
135+
});
136+
137+
it("falls back to arkenv-v1.vercel.app when env is unset", () => {
114138
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "");
115139
vi.stubEnv("VERCEL_PROJECT_PRODUCTION_URL", "");
116140
vi.stubEnv("VERCEL_URL", "");
141+
expect(getDocsUrl()).toBe("https://arkenv-v1.vercel.app");
142+
});
143+
144+
it("uses the GA fallback and production host", async () => {
145+
vi.stubEnv("NEXT_PUBLIC_ARKENV_RELEASE_TAG", "");
146+
vi.stubEnv("ARKENV_RELEASE_TAG", "");
147+
vi.resetModules();
148+
149+
const { getDocsUrl } = await import("./release");
150+
117151
expect(getDocsUrl()).toBe("https://arkenv.js.org");
152+
expect(
153+
getDocsUrl({
154+
NODE_ENV: "test",
155+
VERCEL_PROJECT_PRODUCTION_URL: "arkenv.js.org",
156+
}),
157+
).toBe("https://arkenv.js.org");
118158
});
119159

120160
it("embeds the resolved docs URL in the agent prompt", () => {

apps/www/lib/config/release.ts

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,44 +10,69 @@ export const RELEASE_TAG = rawTag.trim();
1010

1111
export type PackageManager = "npm" | "pnpm" | "bun" | "yarn";
1212

13-
const FALLBACK_DOCS_URL = "https://arkenv.js.org";
13+
/**
14+
* Default/fallback docs origin:
15+
* During pre-release (alpha/rc), v1 docs are hosted at https://arkenv-v1.vercel.app
16+
* while https://arkenv.js.org remains the v0 docs site.
17+
* When graduating to GA (empty RELEASE_TAG), the default flips to https://arkenv.js.org.
18+
*/
19+
export const FALLBACK_DOCS_URL = RELEASE_TAG
20+
? "https://arkenv-v1.vercel.app"
21+
: "https://arkenv.js.org";
1422

1523
/**
1624
* Resolves the docs origin for the current deployment.
1725
*
1826
* Preference order:
1927
* 1. `NEXT_PUBLIC_SITE_URL` (trimmed, no trailing slash)
20-
* 2. `https://${VERCEL_PROJECT_PRODUCTION_URL}` (production domain; flips when DNS moves)
21-
* 3. `https://${VERCEL_URL}` (preview deployment host)
22-
* 4. Fallback `https://arkenv.js.org`
28+
* 2. `https://${NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL ?? VERCEL_PROJECT_PRODUCTION_URL}` (production domain; flips when DNS moves in GA)
29+
* 3. `https://${NEXT_PUBLIC_VERCEL_URL ?? VERCEL_URL}` (preview deployment host)
30+
* 4. Fallback docs URL (`https://arkenv-v1.vercel.app` during pre-release, `https://arkenv.js.org` for GA)
2331
*
2432
* Setting `NEXT_PUBLIC_SITE_URL` or the Vercel production URL makes the homepage
25-
* agent prompt auto-update when the site moves off a preview host (e.g.
26-
* arkenv-v1.vercel.app → arkenv.js.org) without hardcoding the preview forever.
33+
* agent prompt auto-update when the site moves off a preview host without hardcoding.
34+
* During pre-release (e.g. alpha), arkenv.js.org serves v0 docs, so it is ignored
35+
* in favor of the v1 deployment host or the pre-release fallback.
2736
*
2837
* @param env - Env bag to read (defaults to `process.env`; injectable for tests).
2938
* @returns Absolute docs origin with no trailing slash.
3039
*/
40+
function firstNonEmpty(
41+
...values: Array<string | undefined>
42+
): string | undefined {
43+
for (const value of values) {
44+
const trimmed = value?.trim();
45+
if (trimmed) {
46+
return trimmed.replace(/\/+$/, "");
47+
}
48+
}
49+
}
50+
3151
export function getDocsUrl(env: NodeJS.ProcessEnv = process.env): string {
32-
const siteUrl = env.NEXT_PUBLIC_SITE_URL?.trim().replace(/\/+$/, "");
52+
const siteUrl = firstNonEmpty(env.NEXT_PUBLIC_SITE_URL);
3353
if (siteUrl) {
3454
return siteUrl.startsWith("http://") || siteUrl.startsWith("https://")
3555
? siteUrl
3656
: `https://${siteUrl}`;
3757
}
3858

39-
const productionHost = env.VERCEL_PROJECT_PRODUCTION_URL?.trim().replace(
40-
/\/+$/,
41-
"",
59+
const productionHost = firstNonEmpty(
60+
env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL,
61+
env.VERCEL_PROJECT_PRODUCTION_URL,
4262
);
4363
if (productionHost) {
44-
return productionHost.startsWith("http://") ||
45-
productionHost.startsWith("https://")
46-
? productionHost
47-
: `https://${productionHost}`;
64+
const isV0DomainDuringPreRelease =
65+
Boolean(RELEASE_TAG) &&
66+
productionHost.replace(/^https?:\/\//, "") === "arkenv.js.org";
67+
if (!isV0DomainDuringPreRelease) {
68+
return productionHost.startsWith("http://") ||
69+
productionHost.startsWith("https://")
70+
? productionHost
71+
: `https://${productionHost}`;
72+
}
4873
}
4974

50-
const previewHost = env.VERCEL_URL?.trim().replace(/\/+$/, "");
75+
const previewHost = firstNonEmpty(env.NEXT_PUBLIC_VERCEL_URL, env.VERCEL_URL);
5176
if (previewHost) {
5277
return previewHost.startsWith("http://") ||
5378
previewHost.startsWith("https://")

0 commit comments

Comments
 (0)