diff --git a/.github/workflows/ci-cd-production.yml b/.github/workflows/ci-cd-production.yml index 173066125360..3ca7c781c007 100644 --- a/.github/workflows/ci-cd-production.yml +++ b/.github/workflows/ci-cd-production.yml @@ -37,6 +37,7 @@ jobs: cache-to: type=inline build-args: | ENVIRONMENT=production + ORIGIN=https://thegraph.com tags: | ${{ env.BASE_IMAGE }}:${{ github.sha }} ${{ env.BASE_IMAGE }}:latest diff --git a/.github/workflows/ci-cd-pull-request.yml b/.github/workflows/ci-cd-pull-request.yml index b6bc12b206e0..8fb9209b7c26 100644 --- a/.github/workflows/ci-cd-pull-request.yml +++ b/.github/workflows/ci-cd-pull-request.yml @@ -107,4 +107,5 @@ jobs: cache-from: type=registry,ref=${{ env.BASE_IMAGE }}:latest build-args: | ENVIRONMENT=staging + ORIGIN=https://staging.thegraph.com push: false diff --git a/.github/workflows/ci-cd-staging.yml b/.github/workflows/ci-cd-staging.yml index 09740ae54b47..3fc8a8596875 100644 --- a/.github/workflows/ci-cd-staging.yml +++ b/.github/workflows/ci-cd-staging.yml @@ -38,6 +38,7 @@ jobs: cache-to: type=inline build-args: | ENVIRONMENT=staging + ORIGIN=https://staging.thegraph.com tags: | ${{ env.BASE_IMAGE }}:${{ github.sha }} ${{ env.BASE_IMAGE }}:latest diff --git a/Dockerfile b/Dockerfile index cc1a50314b14..c2138875e68c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,10 @@ FROM node:20-alpine as builder ARG ENVIRONMENT +ARG ORIGIN + ENV ENVIRONMENT=$ENVIRONMENT +ENV ORIGIN=$ORIGIN ENV PNPM_HOME="/usr/bin" diff --git a/package.json b/package.json index ed02f717e97a..2e929da5046c 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "turbo run dev --parallel", "build": "NODE_OPTIONS='--max_old_space_size=4096' turbo run build", - "docker:build": "source ./website/.env.local && DOCKER_BUILDKIT=1 docker build . -t docs --no-cache --build-arg ENVIRONMENT=$ENVIRONMENT", + "docker:build": "source ./website/.env.local && DOCKER_BUILDKIT=1 docker build . -t docs --no-cache --build-arg ENVIRONMENT=$ENVIRONMENT --build-arg ORIGIN=$ORIGIN", "docker:clean": "docker builder prune", "docker:up": "docker run --rm -it -p 3000:80 -v \"$(pwd)/nginx.conf:/etc/nginx/nginx.conf\" docs", "check": "pnpm typecheck && pnpm lint && pnpm prettier:check", diff --git a/website/.env b/website/.env index a8f62a06ecb9..a2ffa8e76e27 100644 --- a/website/.env +++ b/website/.env @@ -1,4 +1,5 @@ ENVIRONMENT=local +ORIGIN=http://localhost:3000 +BASE_PATH=/docs ALGOLIA_API_KEY=9a358df50b02a5b66efeecbc0a2cab3d ALGOLIA_APP_ID=WQ5FYJCL00 -SITE_URL=https://thegraph.com/docs diff --git a/website/next-sitemap.config.mjs b/website/next-sitemap.config.mjs index 69d72751cb5f..3afbf8cc684c 100644 --- a/website/next-sitemap.config.mjs +++ b/website/next-sitemap.config.mjs @@ -1,5 +1,5 @@ /** @type {import('next-sitemap').IConfig} */ export default { - siteUrl: process.env.SITE_URL, + siteUrl: '/', generateIndexSitemap: false, } diff --git a/website/next.config.js b/website/next.config.js index 29b90667d7c3..13d53dff06a7 100644 --- a/website/next.config.js +++ b/website/next.config.js @@ -2,7 +2,8 @@ import nextra from 'nextra' const env = { ENVIRONMENT: process.env.ENVIRONMENT, - BASE_PATH: process.env.NODE_ENV === 'production' ? '/docs' : '', + ORIGIN: process.env.ORIGIN, + BASE_PATH: process.env.BASE_PATH, ALGOLIA_API_KEY: process.env.ALGOLIA_API_KEY, ALGOLIA_APP_ID: process.env.ALGOLIA_APP_ID, MIXPANEL_TOKEN: diff --git a/website/route-lockfile.txt b/website/route-lockfile.txt index 72c9d304739c..955e6aabf6b3 100644 --- a/website/route-lockfile.txt +++ b/website/route-lockfile.txt @@ -36,6 +36,7 @@ /ar/subgraphs/cookbook/grafting/ /ar/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /ar/subgraphs/cookbook/near/ +/ar/subgraphs/cookbook/polymarket/ /ar/subgraphs/cookbook/pruning/ /ar/subgraphs/cookbook/secure-api-keys-nextjs/ /ar/subgraphs/cookbook/subgraph-debug-forking/ @@ -115,6 +116,7 @@ /cs/subgraphs/cookbook/grafting/ /cs/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /cs/subgraphs/cookbook/near/ +/cs/subgraphs/cookbook/polymarket/ /cs/subgraphs/cookbook/pruning/ /cs/subgraphs/cookbook/secure-api-keys-nextjs/ /cs/subgraphs/cookbook/subgraph-debug-forking/ @@ -192,6 +194,7 @@ /de/subgraphs/cookbook/grafting/ /de/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /de/subgraphs/cookbook/near/ +/de/subgraphs/cookbook/polymarket/ /de/subgraphs/cookbook/pruning/ /de/subgraphs/cookbook/secure-api-keys-nextjs/ /de/subgraphs/cookbook/subgraph-debug-forking/ @@ -271,6 +274,7 @@ /en/subgraphs/cookbook/grafting/ /en/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /en/subgraphs/cookbook/near/ +/en/subgraphs/cookbook/polymarket/ /en/subgraphs/cookbook/pruning/ /en/subgraphs/cookbook/secure-api-keys-nextjs/ /en/subgraphs/cookbook/subgraph-debug-forking/ @@ -355,6 +359,7 @@ /es/subgraphs/cookbook/grafting/ /es/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /es/subgraphs/cookbook/near/ +/es/subgraphs/cookbook/polymarket/ /es/subgraphs/cookbook/pruning/ /es/subgraphs/cookbook/secure-api-keys-nextjs/ /es/subgraphs/cookbook/subgraph-debug-forking/ @@ -434,6 +439,7 @@ /fr/subgraphs/cookbook/grafting/ /fr/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /fr/subgraphs/cookbook/near/ +/fr/subgraphs/cookbook/polymarket/ /fr/subgraphs/cookbook/pruning/ /fr/subgraphs/cookbook/secure-api-keys-nextjs/ /fr/subgraphs/cookbook/subgraph-debug-forking/ @@ -513,6 +519,7 @@ /hi/subgraphs/cookbook/grafting/ /hi/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /hi/subgraphs/cookbook/near/ +/hi/subgraphs/cookbook/polymarket/ /hi/subgraphs/cookbook/pruning/ /hi/subgraphs/cookbook/secure-api-keys-nextjs/ /hi/subgraphs/cookbook/subgraph-debug-forking/ @@ -592,6 +599,7 @@ /it/subgraphs/cookbook/grafting/ /it/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /it/subgraphs/cookbook/near/ +/it/subgraphs/cookbook/polymarket/ /it/subgraphs/cookbook/pruning/ /it/subgraphs/cookbook/secure-api-keys-nextjs/ /it/subgraphs/cookbook/subgraph-debug-forking/ @@ -671,6 +679,7 @@ /ja/subgraphs/cookbook/grafting/ /ja/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /ja/subgraphs/cookbook/near/ +/ja/subgraphs/cookbook/polymarket/ /ja/subgraphs/cookbook/pruning/ /ja/subgraphs/cookbook/secure-api-keys-nextjs/ /ja/subgraphs/cookbook/subgraph-debug-forking/ @@ -748,6 +757,7 @@ /ko/subgraphs/cookbook/grafting/ /ko/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /ko/subgraphs/cookbook/near/ +/ko/subgraphs/cookbook/polymarket/ /ko/subgraphs/cookbook/pruning/ /ko/subgraphs/cookbook/secure-api-keys-nextjs/ /ko/subgraphs/cookbook/subgraph-debug-forking/ @@ -827,6 +837,7 @@ /mr/subgraphs/cookbook/grafting/ /mr/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /mr/subgraphs/cookbook/near/ +/mr/subgraphs/cookbook/polymarket/ /mr/subgraphs/cookbook/pruning/ /mr/subgraphs/cookbook/secure-api-keys-nextjs/ /mr/subgraphs/cookbook/subgraph-debug-forking/ @@ -904,6 +915,7 @@ /nl/subgraphs/cookbook/grafting/ /nl/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /nl/subgraphs/cookbook/near/ +/nl/subgraphs/cookbook/polymarket/ /nl/subgraphs/cookbook/pruning/ /nl/subgraphs/cookbook/secure-api-keys-nextjs/ /nl/subgraphs/cookbook/subgraph-debug-forking/ @@ -981,6 +993,7 @@ /pl/subgraphs/cookbook/grafting/ /pl/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /pl/subgraphs/cookbook/near/ +/pl/subgraphs/cookbook/polymarket/ /pl/subgraphs/cookbook/pruning/ /pl/subgraphs/cookbook/secure-api-keys-nextjs/ /pl/subgraphs/cookbook/subgraph-debug-forking/ @@ -1060,6 +1073,7 @@ /pt/subgraphs/cookbook/grafting/ /pt/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /pt/subgraphs/cookbook/near/ +/pt/subgraphs/cookbook/polymarket/ /pt/subgraphs/cookbook/pruning/ /pt/subgraphs/cookbook/secure-api-keys-nextjs/ /pt/subgraphs/cookbook/subgraph-debug-forking/ @@ -1137,6 +1151,7 @@ /ro/subgraphs/cookbook/grafting/ /ro/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /ro/subgraphs/cookbook/near/ +/ro/subgraphs/cookbook/polymarket/ /ro/subgraphs/cookbook/pruning/ /ro/subgraphs/cookbook/secure-api-keys-nextjs/ /ro/subgraphs/cookbook/subgraph-debug-forking/ @@ -1216,6 +1231,7 @@ /ru/subgraphs/cookbook/grafting/ /ru/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /ru/subgraphs/cookbook/near/ +/ru/subgraphs/cookbook/polymarket/ /ru/subgraphs/cookbook/pruning/ /ru/subgraphs/cookbook/secure-api-keys-nextjs/ /ru/subgraphs/cookbook/subgraph-debug-forking/ @@ -1295,6 +1311,7 @@ /sv/subgraphs/cookbook/grafting/ /sv/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /sv/subgraphs/cookbook/near/ +/sv/subgraphs/cookbook/polymarket/ /sv/subgraphs/cookbook/pruning/ /sv/subgraphs/cookbook/secure-api-keys-nextjs/ /sv/subgraphs/cookbook/subgraph-debug-forking/ @@ -1372,6 +1389,7 @@ /sw/subgraphs/cookbook/grafting/ /sw/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /sw/subgraphs/cookbook/near/ +/sw/subgraphs/cookbook/polymarket/ /sw/subgraphs/cookbook/pruning/ /sw/subgraphs/cookbook/secure-api-keys-nextjs/ /sw/subgraphs/cookbook/subgraph-debug-forking/ @@ -1451,6 +1469,7 @@ /tr/subgraphs/cookbook/grafting/ /tr/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /tr/subgraphs/cookbook/near/ +/tr/subgraphs/cookbook/polymarket/ /tr/subgraphs/cookbook/pruning/ /tr/subgraphs/cookbook/secure-api-keys-nextjs/ /tr/subgraphs/cookbook/subgraph-debug-forking/ @@ -1528,6 +1547,7 @@ /uk/subgraphs/cookbook/grafting/ /uk/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /uk/subgraphs/cookbook/near/ +/uk/subgraphs/cookbook/polymarket/ /uk/subgraphs/cookbook/pruning/ /uk/subgraphs/cookbook/secure-api-keys-nextjs/ /uk/subgraphs/cookbook/subgraph-debug-forking/ @@ -1607,6 +1627,7 @@ /ur/subgraphs/cookbook/grafting/ /ur/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /ur/subgraphs/cookbook/near/ +/ur/subgraphs/cookbook/polymarket/ /ur/subgraphs/cookbook/pruning/ /ur/subgraphs/cookbook/secure-api-keys-nextjs/ /ur/subgraphs/cookbook/subgraph-debug-forking/ @@ -1684,6 +1705,7 @@ /vi/subgraphs/cookbook/grafting/ /vi/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /vi/subgraphs/cookbook/near/ +/vi/subgraphs/cookbook/polymarket/ /vi/subgraphs/cookbook/pruning/ /vi/subgraphs/cookbook/secure-api-keys-nextjs/ /vi/subgraphs/cookbook/subgraph-debug-forking/ @@ -1763,6 +1785,7 @@ /zh/subgraphs/cookbook/grafting/ /zh/subgraphs/cookbook/immutable-entities-bytes-as-ids/ /zh/subgraphs/cookbook/near/ +/zh/subgraphs/cookbook/polymarket/ /zh/subgraphs/cookbook/pruning/ /zh/subgraphs/cookbook/secure-api-keys-nextjs/ /zh/subgraphs/cookbook/subgraph-debug-forking/ diff --git a/website/scripts/sitemap-ci.js b/website/scripts/sitemap-ci.js index f0f17d520f4c..9c9d21ca59f2 100644 --- a/website/scripts/sitemap-ci.js +++ b/website/scripts/sitemap-ci.js @@ -15,8 +15,7 @@ async function main() { const d = parser.parse(await fs.readFile(sitemapPath, 'utf8')) - // TODO: `process.env.SITE_URL` never seems to be set here, so it always falls back to the default value - const routes = d.urlset.url.map((url) => url.loc.replace(process.env.SITE_URL || 'https://thegraph.com/docs', '')) + const routes = d.urlset.url.map((url) => url.loc.replace(/^\//, '')) const redirectsPointingToNonExistingStuff = [] diff --git a/website/src/_app.tsx b/website/src/_app.tsx index 4dd5b1662208..efc87cfa9a13 100644 --- a/website/src/_app.tsx +++ b/website/src/_app.tsx @@ -27,8 +27,14 @@ import { supportedLocales, translations, useI18n } from '@/i18n' import '@edgeandnode/gds/style.css' import '@docsearch/css' -const internalAbsoluteHrefRegex = /^(((https?:)?\/\/((www|staging)\.)?thegraph\.com)?\/docs\/|\/(?!\/))/i -const externalHrefRegex = /^(?!(https?:)?\/\/((www|staging)\.)?thegraph\.com)([a-zA-Z0-9+.-]+:)?\/\//i +// Match either: +// 1. URLs that start with `/` followed by an optional path or query (root-relative URLs) +// 2. URLs that start with `http(s)://(www.|staging.)thegraph.com`, followed by an optional path/query +const rootRelativeOrTheGraphUrlRegex = + /^(?:\/(?!\/)|(?:(?:https?:)?\/\/(?:(?:www|staging)\.)?thegraph\.com)(?:$|\/|\?))(.+)?/i + +// Match URLs that start with a protocol/scheme or `//` +const absoluteUrlRegex = /^(?:[a-zA-Z][a-zA-Z\d+.-]*:|\/\/)/ const removeBasePathFromUrl = (url: string) => url.substring((process.env.BASE_PATH ?? '').length) @@ -74,18 +80,24 @@ function MyApp({ Component, router, pageProps }: AppProps) { let { href, target } = props as ButtonOrLinkProps.ExternalLinkProps - // If the link is internal and absolute, ensure `href` is relative to the base path (i.e. starts with `/`, - // not `/docs/` or `https://...`) and includes a locale (by prepending the current locale if there is none) - const internalAbsoluteHrefMatches = internalAbsoluteHrefRegex.exec(href) - if (internalAbsoluteHrefMatches) { - href = href.substring(internalAbsoluteHrefMatches[0].length - 1) - const { locale: pathLocale, pathWithoutLocale } = extractLocaleFromPath(href, supportedLocales) - href = `/${pathLocale ?? locale ?? defaultLocale}${pathWithoutLocale}` - } - - // If the link is external, default the target to `_blank` - if (externalHrefRegex.test(href)) { - target = target ?? '_blank' + const matches = rootRelativeOrTheGraphUrlRegex.exec(href) + if (matches?.length) { + const path = matches[1] ? (matches[1].startsWith('/') ? matches[1] : `/${matches[1]}`) : '/' + const basePath = process.env.BASE_PATH ?? '' + const pathIncludesBasePath = path === basePath || path.startsWith(`${basePath}/`) + if (href.startsWith('/') || pathIncludesBasePath) { + // If the link is a root-relative URL or an absolute but internal URL, ensure it is relative to the base path + href = pathIncludesBasePath ? path.substring(basePath.length) : path + // Also ensure the link includes a locale + const { locale: pathLocale, pathWithoutLocale } = extractLocaleFromPath(href, supportedLocales) + href = `/${pathLocale ?? locale ?? defaultLocale}${pathWithoutLocale}` + } else if (process.env.ORIGIN && rootRelativeOrTheGraphUrlRegex.test(process.env.ORIGIN)) { + // If the link is an absolute URL under (staging.)thegraph.com, ensure we don't switch between staging and production + href = `${process.env.ORIGIN}${path}` + } + } else if (absoluteUrlRegex.test(href)) { + // If the link is an external URL, default the target to `_blank` + target ??= '_blank' } return { ...props, href, target }