From 5863f4a861aeb6e8649e31088beb8b3e02b53c69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Oct 2026 15:00:11 +0000 Subject: [PATCH 1/2] [Docs Site] Bump @cloudflare/nimbus-docs from 0.17.0 to 0.18.1 Bumps [@cloudflare/nimbus-docs](https://github.com/cloudflare/nimbus/tree/HEAD/packages/nimbus-docs) from 0.17.0 to 0.18.1. - [Release notes](https://github.com/cloudflare/nimbus/releases) - [Changelog](https://github.com/cloudflare/nimbus/blob/main/packages/nimbus-docs/CHANGELOG.md) - [Commits](https://github.com/cloudflare/nimbus/commits/@cloudflare/nimbus-docs@0.18.1/packages/nimbus-docs) --- updated-dependencies: - dependency-name: "@cloudflare/nimbus-docs" dependency-version: 0.18.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package.json | 2 +- pnpm-lock.yaml | 140 ++++++++++++------------------------------------- 2 files changed, 35 insertions(+), 107 deletions(-) diff --git a/package.json b/package.json index dae44480f3b..94752b84911 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@base-ui/react": "1.9.0", "@cloudflare/ai-search-snippet": "0.0.43", "@cloudflare/config": "0.25.0", - "@cloudflare/nimbus-docs": "0.17.0", + "@cloudflare/nimbus-docs": "0.18.1", "@cloudflare/vitest-plugin": "1.4.3", "@cloudflare/workers-types": "5.20261013.1", "@eslint/js": "9.39.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3485cde223e..122bff154c4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,8 +54,8 @@ importers: specifier: 0.25.0 version: 0.25.0 '@cloudflare/nimbus-docs': - specifier: 0.17.0 - version: 0.17.0(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(astro@7.3.8(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))(esbuild@0.28.2)(jiti@2.7.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(supports-color@10.2.2)(tsx@4.23.15) + specifier: 0.18.1 + version: 0.18.1(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(astro@7.3.8(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))(esbuild@0.28.2)(jiti@2.7.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(supports-color@10.2.2)(tsx@4.23.15) '@cloudflare/vitest-plugin': specifier: 1.4.3 version: 1.4.3(@cloudflare/workers-types@5.20261013.1)(@types/node@26.6.5)(vitest@4.1.11(@types/node@26.6.5)(happy-dom@21.0.1)(vite@8.3.4(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))) @@ -686,99 +686,50 @@ packages: cpu: [arm64] os: [darwin] - '@bruits/satteri-darwin-arm64@0.9.5': - resolution: {integrity: sha512-iw4nZgx9v30lWo/MTngQqi1pI78KI0DnkSm+lVJGYdmPLgAyDNJigVhpG42/Iq55A6c1Ll8q66ljyyRiQUxwow==} - cpu: [arm64] - os: [darwin] - '@bruits/satteri-darwin-x64@0.10.5': resolution: {integrity: sha512-IjnLe3nKspq6qaeqGgjT7MT8VrTV74yWRlaag7ZdNsI8TDAYZ0iPxMCo+9KQZHUk5EyVB+reBI/PFWL5KuFw9Q==} cpu: [x64] os: [darwin] - '@bruits/satteri-darwin-x64@0.9.5': - resolution: {integrity: sha512-6T26Z5Kf3cFW2PSlk9p7zT7yVxvuBSiJvYyz9u8KjYwMTqZyIDOj2wDyNpxKV4+6yUVG7rddq2QwvG/8LJA2+Q==} - cpu: [x64] - os: [darwin] - '@bruits/satteri-linux-arm64-gnu@0.10.5': resolution: {integrity: sha512-glkYXZCJywjP13v67eAyAMSJdF+ncvEbYvgi/wOtffL9tQ27lr/zsyzUfgs+ovjJ9d8JNQKiXeiArJcX8PJL9w==} cpu: [arm64] os: [linux] libc: [glibc] - '@bruits/satteri-linux-arm64-gnu@0.9.5': - resolution: {integrity: sha512-u51id17uJwNEMK9nBlICsq6U31c+XVqQueVBkwRIzZG+gMpS8TOJctt5h5Wz33Z8xnMdTd+adtACVz0yHgGuOA==} - cpu: [arm64] - os: [linux] - libc: [glibc] - '@bruits/satteri-linux-arm64-musl@0.10.5': resolution: {integrity: sha512-yWdgG1g17Nh2QyGVlFUxGRa3FEFwiMcpZEyMNWkbM3deC94cmVc+/i9OuyFpdKuWo3GkgoCtYVOoxk1uCnCZIA==} cpu: [arm64] os: [linux] libc: [musl] - '@bruits/satteri-linux-arm64-musl@0.9.5': - resolution: {integrity: sha512-v39HxiwGC5Rqm01HksP6+5Y+xKLPlsuVFgIgpEAo+SiQ22c+mJVhS3u7Z6ePAKdhL5NJoK1xq70kLz3L13AhpQ==} - cpu: [arm64] - os: [linux] - libc: [musl] - '@bruits/satteri-linux-x64-gnu@0.10.5': resolution: {integrity: sha512-FVaLoPT1fBgGl0J+AYebyyXJYBachGl8Oyyrf1lye4RTqCB4S0Gwkj1uM9RJyThUOvx5VUmAT1CnNh1SFHA+kw==} cpu: [x64] os: [linux] libc: [glibc] - '@bruits/satteri-linux-x64-gnu@0.9.5': - resolution: {integrity: sha512-F3uO8uFp3pAP5ZGXttwvh57GS7s0lL953tnNdyI2gRyP4kOOkp6pyGojNJzCjkDvWI2Cvb9iNrKok3aqQPauAw==} - cpu: [x64] - os: [linux] - libc: [glibc] - '@bruits/satteri-linux-x64-musl@0.10.5': resolution: {integrity: sha512-EHpVAx2bqW3GINHTKkljtxVfQmVDGWIuwOYOP5YghTj+0PkBa2o8oKPRtQ9Kbsr1Fye8jtUcDjhwj2jMNugZKg==} cpu: [x64] os: [linux] libc: [musl] - '@bruits/satteri-linux-x64-musl@0.9.5': - resolution: {integrity: sha512-bicEqglLlz++mWyADaZoP0JY20s4vDfLjaPYgQqC+NI4zZLTOOg1T4GB8aqtc822Pqji8SQBmSrTb7CrP8i08Q==} - cpu: [x64] - os: [linux] - libc: [musl] - '@bruits/satteri-wasm32-wasi@0.10.5': resolution: {integrity: sha512-ypz8c/Zmipxp4IoeDa228Gstv6TLzVmNs3yC6wKCoNSOjx1iwpgzu87Y3hTkXFdwChVGU85qeUDuOIarGUZQLw==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@bruits/satteri-wasm32-wasi@0.9.5': - resolution: {integrity: sha512-zauAuMwfPnKPUkd4AFixRFpXdgKwP2mKgxrIIo2gJzW0/ZneF9dbHnLkojSpaBnCCp7VUL1hIi5WWZvB1CqmAQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - '@bruits/satteri-win32-arm64-msvc@0.10.5': resolution: {integrity: sha512-siTV88nb0LRqNpkL2gXboqCwVdq95sLtzMHS1/3eONV2gLbB3NAK46wmSMvCO/yquBvI2lvaFIfd8P12ecsxBw==} cpu: [arm64] os: [win32] - '@bruits/satteri-win32-arm64-msvc@0.9.5': - resolution: {integrity: sha512-SrfE7NEsgZjBvU3c+RR6oQRu0ToXY5uVJEbieXEF0YTctIV2zAVlbaMjWLts074QCgh3a+XHWkR/lWh2VH2LUg==} - cpu: [arm64] - os: [win32] - '@bruits/satteri-win32-x64-msvc@0.10.5': resolution: {integrity: sha512-C3IfPvfvMXmlzBxaMPKFS1XiuV9pu2mC7YqkPk7PSvTgPZ8gbdASIpHpztDLvTTQjqZ0z1Ol8tK5X+V6XXC0wQ==} cpu: [x64] os: [win32] - '@bruits/satteri-win32-x64-msvc@0.9.5': - resolution: {integrity: sha512-5Kw9ZAtTGS8WHizyn+CJhjjfIQrw+7jcZodpmpXJjefnO15M8UexIi6JR2E5thyvsmHyhL6ZDDMUNR4bKJPd4g==} - cpu: [x64] - os: [win32] - '@capsizecss/unpack@4.0.1': resolution: {integrity: sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==} engines: {node: '>=18'} @@ -817,8 +768,8 @@ packages: resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} engines: {node: '>=22.0.0'} - '@cloudflare/nimbus-docs@0.17.0': - resolution: {integrity: sha512-zV1Yr/rf1g7gRufIRUoiJlmEBdWHxcMkBi0fkvkgdvxgTGa8WY2QLAqT2ArSPtsXGAjCMW1e53EOeG8oHsA5EA==} + '@cloudflare/nimbus-docs@0.18.1': + resolution: {integrity: sha512-le4ZOV+r3RAYx+k3XjwpnLPpfoxwjnQbavVe+31/mg++23SgQMVVuTTHcJpNPgk1yiAW+Doj+HOP6Nc0PbpRUQ==} engines: {node: '>=22.12.0'} hasBin: true peerDependencies: @@ -1356,6 +1307,9 @@ packages: '@fontsource/inter@5.3.0': resolution: {integrity: sha512-RofMylZmjlJEfELXeNHFWBRcSs75rGU/6bV2S2jfnvv/3rPXPGe0LgUJTklcHZ9lM4OZmAVFhcJPnACfb91A3g==} + '@fontsource/stix-two-math@5.3.0': + resolution: {integrity: sha512-negoeozw6VSXjZMozwKRSm/dhCQT62csZcuea9I8KYqPaZq/8KbbBBrA02ZHF7AyuR5mVML/p+q0bwFuSIf2GQ==} + '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} @@ -4322,6 +4276,9 @@ packages: mdast-util-gfm@3.1.0: resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + mdast-util-math@3.0.0: + resolution: {integrity: sha512-Tl9GBNeG/AhJnQM221bJR2HPvLOSnLE/T9cJI9tlc6zwQk2nPk/4f0cHkOdEixQPC/j8UtKDdITswvLAy1OZ1w==} + mdast-util-mdx-expression@2.0.1: resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} @@ -5090,9 +5047,6 @@ packages: satteri@0.10.5: resolution: {integrity: sha512-Ao1LKpAEa9Wdg0otgbVKViZHEq9ebdXe4DMrp3s9vQAU0HNIuHnFEuMuOcm0ZIXyV0Yzxj91NvhLpvXZJO/5ZQ==} - satteri@0.9.5: - resolution: {integrity: sha512-ZuWVl+vnM64y+/TtX8Kosv2c00W+hLQiiwnEL6H0UKVVrxFqMw4D2CJHHQaouVd89OAhtBBfjWLqhKi3TVUV4w==} - sax@1.6.1: resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==} engines: {node: '>=11.0.0'} @@ -5326,6 +5280,10 @@ packages: resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} + temml@0.14.0: + resolution: {integrity: sha512-tz1LW/5IZpThK8c7ZpdTSH/n56eAj+ThirLieErtKxYC3EKCIiB4sKdRUehAgH+fQmvIKqMfP3gqTLBdLpy9zw==} + engines: {node: '>=18.13.0'} + tiny-inflate@1.0.3: resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} @@ -6462,39 +6420,21 @@ snapshots: '@bruits/satteri-darwin-arm64@0.10.5': optional: true - '@bruits/satteri-darwin-arm64@0.9.5': - optional: true - '@bruits/satteri-darwin-x64@0.10.5': optional: true - '@bruits/satteri-darwin-x64@0.9.5': - optional: true - '@bruits/satteri-linux-arm64-gnu@0.10.5': optional: true - '@bruits/satteri-linux-arm64-gnu@0.9.5': - optional: true - '@bruits/satteri-linux-arm64-musl@0.10.5': optional: true - '@bruits/satteri-linux-arm64-musl@0.9.5': - optional: true - '@bruits/satteri-linux-x64-gnu@0.10.5': optional: true - '@bruits/satteri-linux-x64-gnu@0.9.5': - optional: true - '@bruits/satteri-linux-x64-musl@0.10.5': optional: true - '@bruits/satteri-linux-x64-musl@0.9.5': - optional: true - '@bruits/satteri-wasm32-wasi@0.10.5': dependencies: '@emnapi/core': 1.11.1 @@ -6502,25 +6442,12 @@ snapshots: '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) optional: true - '@bruits/satteri-wasm32-wasi@0.9.5': - dependencies: - '@emnapi/core': 1.11.1 - '@emnapi/runtime': 1.11.1 - '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) - optional: true - '@bruits/satteri-win32-arm64-msvc@0.10.5': optional: true - '@bruits/satteri-win32-arm64-msvc@0.9.5': - optional: true - '@bruits/satteri-win32-x64-msvc@0.10.5': optional: true - '@bruits/satteri-win32-x64-msvc@0.9.5': - optional: true - '@capsizecss/unpack@4.0.1': dependencies: fontkitten: 1.0.3 @@ -6566,12 +6493,13 @@ snapshots: '@cloudflare/kv-asset-handler@0.5.0': {} - '@cloudflare/nimbus-docs@0.17.0(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(astro@7.3.8(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))(esbuild@0.28.2)(jiti@2.7.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(supports-color@10.2.2)(tsx@4.23.15)': + '@cloudflare/nimbus-docs@0.18.1(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(astro@7.3.8(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1))(esbuild@0.28.2)(jiti@2.7.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(supports-color@10.2.2)(tsx@4.23.15)': dependencies: '@astrojs/markdown-satteri': 0.4.3 '@astrojs/mdx': 8.0.3(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@astrojs/markdown-satteri@0.4.3)(astro@7.3.8(@astrojs/markdown-remark@7.3.2(supports-color@10.2.2))(@types/node@26.6.5)(esbuild@0.28.2)(jiti@2.7.0)(tsx@4.23.15)(yaml@2.9.1)) '@astrojs/sitemap': 3.7.2 '@clack/prompts': 0.9.1 + '@fontsource/stix-two-math': 5.3.0 '@iconify/tools': 5.0.14 '@iconify/types': 2.0.0 '@iconify/utils': 3.1.7 @@ -6589,6 +6517,7 @@ snapshots: hast-util-to-html: 9.0.5 jsonc-parser: 3.3.1 mdast-util-gfm: 3.1.0(supports-color@10.2.2) + mdast-util-math: 3.0.0(supports-color@10.2.2) mdast-util-mdx: 3.0.0(supports-color@10.2.2) mdast-util-to-markdown: 2.1.2 mri: 1.2.0 @@ -6602,10 +6531,10 @@ snapshots: remark-lint-no-multiple-toplevel-headings: 4.0.1(supports-color@10.2.2) remark-lint-unordered-list-marker-style: 4.0.1 satteri: 0.10.5 - satteri-source-parser: satteri@0.9.5 semver: 7.8.5 shiki: 4.4.3 tailwind-merge: 3.7.0 + temml: 0.14.0 typescript: 5.9.3 unified: 11.0.5 vfile: 6.0.3 @@ -7051,6 +6980,8 @@ snapshots: '@fontsource/inter@5.3.0': {} + '@fontsource/stix-two-math@5.3.0': {} + '@humanfs/core@0.19.2': dependencies: '@humanfs/types': 0.15.0 @@ -10299,6 +10230,18 @@ snapshots: transitivePeerDependencies: - supports-color + mdast-util-math@3.0.0(supports-color@10.2.2): + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + longest-streak: 3.1.0 + mdast-util-from-markdown: 2.1.0(supports-color@10.2.2) + mdast-util-to-markdown: 2.1.2 + unist-util-remove-position: 5.0.0 + transitivePeerDependencies: + - supports-color + mdast-util-mdx-expression@2.0.1(supports-color@10.2.2): dependencies: '@types/estree-jsx': 1.0.5 @@ -11484,23 +11427,6 @@ snapshots: '@bruits/satteri-win32-arm64-msvc': 0.10.5 '@bruits/satteri-win32-x64-msvc': 0.10.5 - satteri@0.9.5: - dependencies: - '@types/estree-jsx': 1.0.5 - '@types/hast': 3.0.5 - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - optionalDependencies: - '@bruits/satteri-darwin-arm64': 0.9.5 - '@bruits/satteri-darwin-x64': 0.9.5 - '@bruits/satteri-linux-arm64-gnu': 0.9.5 - '@bruits/satteri-linux-arm64-musl': 0.9.5 - '@bruits/satteri-linux-x64-gnu': 0.9.5 - '@bruits/satteri-linux-x64-musl': 0.9.5 - '@bruits/satteri-wasm32-wasi': 0.9.5 - '@bruits/satteri-win32-arm64-msvc': 0.9.5 - '@bruits/satteri-win32-x64-msvc': 0.9.5 - sax@1.6.1: {} scheduler@0.25.0: {} @@ -11809,6 +11735,8 @@ snapshots: tapable@2.3.3: {} + temml@0.14.0: {} + tiny-inflate@1.0.3: {} tinybench@2.9.0: {} From b5002d941bc1c3384a8cd8b8b3a4720dd9f3870e Mon Sep 17 00:00:00 2001 From: mvm Date: Mon, 19 Oct 2026 13:27:01 -0500 Subject: [PATCH 2/2] chore: use Nimbus sitemap lastmod instead of custom serializer --- astro.config.ts | 17 ++---- sitemap.serializer.ts | 131 ------------------------------------------ 2 files changed, 4 insertions(+), 144 deletions(-) delete mode 100644 sitemap.serializer.ts diff --git a/astro.config.ts b/astro.config.ts index 19754ab541a..329e7d9c978 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -9,7 +9,6 @@ import nimbus, { } from "@cloudflare/nimbus-docs"; import { satteri } from "@astrojs/markdown-satteri"; import { hastPlugins } from "./src/plugins/satteri"; -import { createSitemapLastmodSerializer } from "./sitemap.serializer"; import { isDisallowedByRobots } from "./src/util/robots"; // One sidebar section per top-level product directory, autogenerated from the @@ -54,12 +53,6 @@ async function getExternalLinkPaths(dir: string): Promise> { const sidebarItems = await autogenSections(); const externalLinkPaths = await getExternalLinkPaths("src/content/docs"); -// Previews build from a shallow clone, so git dates are wrong, and any -// per-build date forces every page to be re-uploaded. `astro:env` isn't -// available here; unset means preview, matching the env schema default. -const serializeSitemapLastmod = createSitemapLastmodSerializer({ - lastmod: process.env.DEPLOYMENT_ENV === "production", -}); // Mirrors production's sitemap `filter` (root astro.config.ts). function isExcludedFromSitemap(url: string): boolean { @@ -223,15 +216,13 @@ const integrations = [ }, }, validateMdx: false, - // Sitemap parity (T3): drop excluded URLs, stamp lastmod on the rest. + // Nimbus sets `lastmod` from frontmatter or git; here we drop excluded + // URLs and escape `@` in the rest. sitemap: { - serialize: async (item) => + serialize: (item) => isExcludedFromSitemap(item.url) ? undefined - : serializeSitemapLastmod( - // nominal-only gap between nimbus-docs and @astrojs/sitemap types - item as Parameters[0], - ), + : { ...item, url: item.url.replace(/@/g, "%40") }, }, rules: { "nimbus/frontmatter-shape": "error", diff --git a/sitemap.serializer.ts b/sitemap.serializer.ts deleted file mode 100644 index 3b5185273fd..00000000000 --- a/sitemap.serializer.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { spawn } from "node:child_process"; -import * as readline from "node:readline"; -import type { SitemapItem } from "@astrojs/sitemap"; -import { existsSync } from "fs"; -import { green, blue, dim } from "kleur/colors"; - -/** - * Meant to mimic how Astro prints duration during logging - * (i.e. build/util.ts from astro/core). - */ -export function readableMsDuration(duration: number) { - return duration < 1000 - ? `${Math.round(duration)}ms` - : `${(duration / 1000).toFixed(2)}s`; -} - -/** - * A helper function that uses git shell commands to get last modified dates. - * Note: it is important that this is only called once with all relevant paths as opposed to calling this separately for individual paths. - */ -async function getLastmodViaGitShell(...dirs: string[]) { - const gitArgs = [ - "log", - "--pretty=format:DATE: %cI", - "--diff-filter=AMR", - "--name-only", - ...dirs, - ]; - - return new Promise>((resolve, reject) => { - const git = spawn("git", gitArgs, { cwd: process.cwd() }); - // Use readline to process output to reduce memory usage since output will be large. - const rl = readline.createInterface({ - input: git.stdout!, - crlfDelay: Infinity, - }); - - const lastmodMetadata = new Map(); - let currentDate: Date; - - rl.on("line", (rawLine) => { - const line = rawLine.trim(); - if (!line) return; - if (line.startsWith("DATE: ")) { - // Cut off the 'DATE: ' prefix and use Date class to handle time zones - currentDate = new Date(line.slice(6)); - return; - } - const file = line; - if (!lastmodMetadata.has(file) && currentDate) { - lastmodMetadata.set(file, currentDate); - } - }); - - let stderr = ""; - git.stderr?.on("data", (chunk) => (stderr += chunk.toString())); - git.on("error", reject); - - git.on("close", (code) => { - rl.close(); - if (code !== 0) - return reject(new Error(`git exited with code ${code}: ${stderr}`)); - resolve(lastmodMetadata); - }); - }); -} - -/** - * Attempt to find corresponding source file path for a sitemap item. - * Looks for content in `src/content/docs` (MDX pages). - * @returns Relative file path or null if not found - */ -function getSourceFile(item: SitemapItem) { - const url = new URL(item.url); - // Remove trailing slash - const pathname = url.pathname.replace(/\/$/, ""); - - // Try different file extensions and paths - const possiblePaths = [ - `src/content/docs${pathname}.md`, - `src/content/docs${pathname}.mdx`, - `src/content/docs${pathname}/index.md`, - `src/content/docs${pathname}/index.mdx`, - ]; - - for (const path of possiblePaths) { - if (existsSync(path)) { - return path; - } - } - - return null; -} - -export function createSitemapLastmodSerializer({ - lastmod = true, -}: { lastmod?: boolean } = {}) { - let lastModMetadata: Map | undefined = undefined; - const currentDateString = new Date().toISOString(); - return async (item: SitemapItem) => { - item.url = item.url.replace(/@/g, "%40"); - // Skipping lastmod avoids a full `git log` and keeps the output stable - // between builds. - if (!lastmod) return item; - const filePath = getSourceFile(item); - // Only calculate metadata once - if (lastModMetadata === undefined) { - const startTime = performance.now(); - lastModMetadata = await getLastmodViaGitShell( - "src/content/docs", - "src/pages/**/*.astro", - ); - const endTime = performance.now(); - - // Mimic the Astro logger output - console.log( - dim(new Date().toLocaleTimeString("en-US", { hour12: false })), - blue("[@cloudflare/lastmod-serializer]"), - green( - `✓ Lastmod metadata calculated in ${readableMsDuration(endTime - startTime)}.`, - ), - ); - } - if (filePath && lastModMetadata.has(filePath)) { - item.lastmod = lastModMetadata.get(filePath)!.toISOString(); - } else { - item.lastmod = currentDateString; - } - return item; - }; -}