Skip to content

Commit 3a6221a

Browse files
fix(landing-page): stop download function 404-shadowing localized catalog pages (#5770)
* fix(landing-page): emit localized plugins/templates/[kind] pages in production The `[locale]/plugins/templates/[kind]` route imported `getStaticPaths` from the sibling English `[kind]` page and re-invoked it. That cross-page `getStaticPaths` re-export resolved to zero paths in the CI (Linux) production build, so every `/<locale>/plugins/templates/<kind>/` URL (deck, prototype, image, video, audio, live-artifact, hyperframes) 404'd in production for all non-English locales — while the English routes and the localized category index built fine. The language switcher on the English category pages links straight into these 404s. Derive the locale x category paths directly from PLUGIN_CATEGORIES (the same source the English page's own getStaticPaths uses), mirroring the self-contained `[locale]/plugins/[slug]` wrapper, so the route no longer depends on the fragile cross-page getStaticPaths import. * fix(landing-page): stop download function shadowing localized catalog pages The attributed-download function `functions/[os]/[arch]/[token]/[asset].ts` has a file-path route (`/[os]/[arch]/[token]/[asset]`) that structurally matches ANY four-segment path. Pages Functions run before static-asset serving, so it was intercepting the localized plugin catalog pages — e.g. `/zh/plugins/templates/deck/` bound os=zh, arch=plugins, token=templates, asset=deck — and returning `{"error":"download_not_found"}` (404) instead of the real page. Every `/<locale>/plugins/templates/<kind>/` URL (the only four-segment paths on the site) 404'd for all non-English locales, and the language switcher on the English category pages links straight into them. Real download URLs are minted only as `/{windows|macos|linux}/{arch}/{token} /{asset}` (see `functions/api/attribution/mint.ts`), so gate the function on the platform segment: anything whose first segment isn't a download platform falls through to the static asset via `context.next()`. Download requests are unaffected. Adds `next` to the local `PagesFunctionContext` type. Paired with the localized `templates/[kind]` getStaticPaths fix in the same branch, which makes those static pages exist in the first place. --------- Co-authored-by: Joey <236967869+joeylee12629-star@users.noreply.github.com>
1 parent ad89fc6 commit 3a6221a

3 files changed

Lines changed: 44 additions & 12 deletions

File tree

apps/landing-page/app/pages/[locale]/plugins/templates/[kind]/index.astro

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,33 @@
11
---
2-
import KindPage, {
3-
getStaticPaths as getKindStaticPaths,
4-
} from '../../../../plugins/templates/[kind]/index.astro';
2+
/*
3+
* /<locale>/plugins/templates/<kind>/ — localized artifact-category grids.
4+
*
5+
* Re-uses the canonical English `[kind]` page for rendering and forwards
6+
* the same `categorySlug` prop. We compute the locale × category paths
7+
* HERE from `PLUGIN_CATEGORIES` directly, rather than importing the
8+
* English page's `getStaticPaths` and re-mapping it.
9+
*
10+
* Importing a sibling `.astro` PAGE's `getStaticPaths` and re-invoking it
11+
* is a fragile Astro pattern: `getStaticPaths` is hoisted/extracted by the
12+
* compiler, so the cross-page re-export resolved to zero paths in the CI
13+
* (Linux) production build even though it worked in local dev — leaving
14+
* every `/<locale>/plugins/templates/<kind>/` URL 404 in production while
15+
* the English routes were fine. Deriving the paths from the shared facet
16+
* const (the same source the English page's own `getStaticPaths` uses)
17+
* makes this route self-contained, mirroring the sibling `[locale]/plugins/
18+
* [slug]` wrapper. See PLUGIN_CATEGORIES in `_lib/plugin-facets`.
19+
*/
20+
import KindPage from '../../../../plugins/templates/[kind]/index.astro';
21+
import { PLUGIN_CATEGORIES } from '../../../../../_lib/plugin-facets';
522
import { DEFAULT_LOCALE, LANDING_LOCALES } from '../../../../../i18n';
623
7-
export async function getStaticPaths() {
8-
const basePaths = await getKindStaticPaths();
9-
return LANDING_LOCALES.filter((locale) => locale.code !== DEFAULT_LOCALE).flatMap(
10-
(locale) =>
11-
basePaths.map((p) => ({
12-
params: { ...p.params, locale: locale.code },
13-
props: p.props,
14-
})),
24+
export function getStaticPaths() {
25+
const locales = LANDING_LOCALES.filter((locale) => locale.code !== DEFAULT_LOCALE);
26+
return locales.flatMap((locale) =>
27+
PLUGIN_CATEGORIES.map((cat) => ({
28+
params: { locale: locale.code, kind: cat.slug },
29+
props: { categorySlug: cat.slug },
30+
})),
1531
);
1632
}
1733
---

apps/landing-page/functions/[os]/[arch]/[token]/[asset].ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,24 @@ import {
99
type PagesFunction,
1010
} from '../../../_lib/attribution';
1111

12+
// Download URLs are minted only as `/{windows|macos|linux}/{arch}/{token}/{asset}`
13+
// (see `functions/api/attribution/mint.ts`). This function's file-path route
14+
// `/[os]/[arch]/[token]/[asset]` structurally matches ANY four-segment path,
15+
// though — including localized static pages such as
16+
// `/zh/plugins/templates/deck/` (os=`zh`, arch=`plugins`, token=`templates`,
17+
// asset=`deck`). Because Pages Functions run before static-asset serving, an
18+
// unguarded function would shadow every four-segment page with a JSON 404
19+
// (`download_not_found`). Gate on the platform segment so anything that isn't a
20+
// real download request falls through to the static asset instead.
21+
const DOWNLOAD_PLATFORMS = new Set(['windows', 'macos', 'linux']);
22+
1223
export const onRequest: PagesFunction<AttributionEnv, {
1324
os: string;
1425
arch: string;
1526
token: string;
1627
asset: string;
17-
}> = async ({ request, env, params }) => {
28+
}> = async ({ request, env, params, next }) => {
29+
if (!DOWNLOAD_PLATFORMS.has(params.os)) return next();
1830
if (request.method !== 'GET' && request.method !== 'HEAD') {
1931
return json(405, { error: 'method_not_allowed' });
2032
}

apps/landing-page/functions/_lib/attribution.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ export interface PagesFunctionContext<Env, Params = Record<string, string>> {
22
request: Request;
33
env: Env;
44
params: Params;
5+
// Serves the next matching handler — for a Pages Function that owns a broad
6+
// route, this falls through to the static asset (or the 404 page) instead of
7+
// the function generating a response itself.
8+
next: (input?: Request | string, init?: RequestInit) => Promise<Response>;
59
}
610

711
export type PagesFunction<Env, Params = Record<string, string>> = (

0 commit comments

Comments
 (0)