diff --git a/.gitignore b/.gitignore index 8763df8b47941..9b680e67ce257 100644 --- a/.gitignore +++ b/.gitignore @@ -108,3 +108,4 @@ yalc.lock .claude/settings.local.json mise.toml .yarn/install-state.gz +.pi/ diff --git a/docs/changelog.mdx b/docs/changelog.mdx index 0e511c1aa26ad..a69ffaef0378e 100644 --- a/docs/changelog.mdx +++ b/docs/changelog.mdx @@ -4,9 +4,6 @@ sidebar_order: 100 description: Track recent updates to Sentry docs --- -import {DocsChangelog} from 'sentry-docs/components/changelog/docsChangelog'; - - ## Recent Updates diff --git a/includes/quick-start-features-expandable-cloudflare-frameworks.mdx b/includes/quick-start-features-expandable-cloudflare-frameworks.mdx index fc54d571892c2..5ddb828a8f1de 100644 --- a/includes/quick-start-features-expandable-cloudflare-frameworks.mdx +++ b/includes/quick-start-features-expandable-cloudflare-frameworks.mdx @@ -1,4 +1,3 @@ -import { FeatureInfo } from "sentry-docs/components/featureInfo"; diff --git a/includes/quick-start-features-expandable.mdx b/includes/quick-start-features-expandable.mdx index d3be59cddbefe..aeb0f9bc440ef 100644 --- a/includes/quick-start-features-expandable.mdx +++ b/includes/quick-start-features-expandable.mdx @@ -1,4 +1,3 @@ -import { FeatureInfo } from "sentry-docs/components/featureInfo"; diff --git a/includes/quick-start-locate-data-expandable-cloudflare-frameworks.mdx b/includes/quick-start-locate-data-expandable-cloudflare-frameworks.mdx index 062f60ba3a67d..c5ec2ce5c7194 100644 --- a/includes/quick-start-locate-data-expandable-cloudflare-frameworks.mdx +++ b/includes/quick-start-locate-data-expandable-cloudflare-frameworks.mdx @@ -1,4 +1,3 @@ -import { FeatureInfo } from "sentry-docs/components/featureInfo"; diff --git a/includes/quick-start-locate-data-expandable.mdx b/includes/quick-start-locate-data-expandable.mdx index 466a8883a61d8..609db94b2680e 100644 --- a/includes/quick-start-locate-data-expandable.mdx +++ b/includes/quick-start-locate-data-expandable.mdx @@ -1,4 +1,3 @@ -import { FeatureInfo } from "sentry-docs/components/featureInfo"; diff --git a/next.config.ts b/next.config.ts index 9b53988f208e8..9e0f90b206d75 100644 --- a/next.config.ts +++ b/next.config.ts @@ -6,30 +6,25 @@ import {redirects} from './redirects.js'; // Exclude build-time-only dependencies from serverless function bundles to stay under // Vercel's 250MB limit. These packages are only needed during build to compile MDX and -// optimize assets. We use a local getMDXComponent (src/getMDXComponent.ts) instead of -// mdx-bundler/client to avoid CJS/ESM compatibility issues at runtime. +// optimize assets. const sharedExcludes = [ '**/*.map', './.git/**/*', './apps/**/*', - './.next/cache/mdx-bundler/**/*', + './.next/cache/mdx-compile/**/*', './.next/cache/md-exports/**/*', - // Heavy build dependencies - 'node_modules/@esbuild/**/*', - 'node_modules/esbuild/**/*', + // Heavy build/script-only dependencies (not needed at runtime) 'node_modules/@aws-sdk/**/*', 'node_modules/@google-cloud/**/*', 'node_modules/prettier/**/*', 'node_modules/@prettier/**/*', 'node_modules/sharp/**/*', 'node_modules/mermaid/**/*', - // MDX processing dependencies (local getMDXComponent replaces mdx-bundler/client) - 'node_modules/mdx-bundler/**/*', + // MDX processing dependencies (only needed at build time for SSG) 'node_modules/rehype-preset-minify/**/*', 'node_modules/rehype-prism-plus/**/*', 'node_modules/rehype-prism-diff/**/*', 'node_modules/remark-gfm/**/*', - 'node_modules/remark-mdx-images/**/*', 'node_modules/unified/**/*', 'node_modules/rollup/**/*', ]; @@ -50,6 +45,9 @@ const outputFileTracingExcludes = process.env.NEXT_PUBLIC_DEVELOPER_DOCS 'node_modules/prettier/plugins', 'node_modules/rollup/dist', 'public/og-images/**/*', + 'public/mdx-images/**/*', + 'public/md-exports/**/*', + '**/*.pdf', ], 'sitemap.xml': [ 'public/mdx-images/**/*', @@ -103,19 +101,10 @@ const nextConfig = { trailingSlash: true, serverExternalPackages: [ 'rehype-preset-minify', - 'esbuild', - '@esbuild/darwin-arm64', - '@esbuild/darwin-x64', - '@esbuild/linux-arm64', - '@esbuild/linux-x64', - '@esbuild/win32-x64', - // mdx-bundler fully excluded via outputFileTracingExcludes 'sharp', '@aws-sdk/client-s3', - '@google-cloud/storage', 'prettier', '@prettier/plugin-xml', - 'mermaid', ], outputFileTracingExcludes, outputFileTracingIncludes, diff --git a/package.json b/package.json index 65fcd57e1dfd9..710d5e94f0723 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "build": "pnpm enforce-redirects && pnpm generate-og-images && pnpm generate-doctree && next build && pnpm generate-md-exports", "generate-md-exports": "node scripts/generate-md-exports.mjs", "generate-og-images": "ts-node scripts/add-og-images.ts", - "generate-doctree": "esbuild scripts/generate-doctree.ts --bundle --platform=node --packages=external --outfile=.next/generate-doctree.mjs --format=esm && node .next/generate-doctree.mjs", + "generate-doctree": "ts-node --transpile-only scripts/generate-doctree.ts", "vercel:build:developer-docs": "pnpm enforce-redirects && git submodule init && git submodule update && NEXT_PUBLIC_DEVELOPER_DOCS=1 pnpm build", "start:dev": "NODE_ENV=development pnpm build && pnpm start", "start": "next start", @@ -67,7 +67,6 @@ "algoliasearch": "^4.23.3", "classnames": "^2.5.1", "dompurify": "3.2.4", - "esbuild": "^0.25.0", "framer-motion": "^10.12.16", "github-slugger": "^2.0.0", "gray-matter": "^4.0.3", @@ -83,10 +82,9 @@ "mdast-util-from-markdown": "^2.0.2", "mdast-util-to-markdown": "^2.1.2", "mdast-util-to-string": "^4.0.0", - "mdx-bundler": "^10.0.1", "mermaid": "^11.11.0", "micromark": "^4.0.0", - "next": "^15.5.12", + "next": "15.5.12", "next-plausible": "^3.12.4", "next-themes": "^0.3.0", "nextjs-toploader": "^1.6.6", @@ -109,7 +107,6 @@ "rehype-stringify": "^10.0.0", "remark-gfm": "^4.0.1", "remark-link-rewrite": "^1.0.7", - "remark-mdx-images": "^3.0.0", "remark-parse": "^11.0.0", "remark-prism": "^1.3.6", "remark-rehype": "^11.1.2", @@ -171,13 +168,10 @@ "onlyBuiltDependencies": [ "@parcel/watcher", "@sentry/cli", - "esbuild", "sharp", "unrs-resolver" ], - "patchedDependencies": { - "remark-mdx-images@3.0.0": "patches/remark-mdx-images@3.0.0.patch" - } + "patchedDependencies": {} }, "packageManager": "pnpm@10.30.0", "volta": { diff --git a/patches/remark-mdx-images@3.0.0.patch b/patches/remark-mdx-images@3.0.0.patch deleted file mode 100644 index 3632067d7ae4c..0000000000000 --- a/patches/remark-mdx-images@3.0.0.patch +++ /dev/null @@ -1,14 +0,0 @@ -diff --git a/index.ts b/index.ts -index e502738bb0929a42b4c44241b495d79b97d90eaf..b163928ac090a4e38c18ac03b7734e912d2a009c 100644 ---- a/index.ts -+++ b/index.ts -@@ -50,7 +50,8 @@ const remarkMdxImages: Plugin<[RemarkMdxImagesOptions?], Root> = - type: 'ImportDefaultSpecifier', - local: { type: 'Identifier', name } - } -- ] -+ ], -+ attributes: [] - }) - imported.set(url, name) - } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c3f8b0f61f462..ebc7589ce8a69 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -9,11 +9,6 @@ overrides: '@types/dompurify': 3.0.5 '@types/node': ^22 -patchedDependencies: - remark-mdx-images@3.0.0: - hash: 073a4a4ae6cea36e784e927fdde45ca4ca67ad05afe07d93684620ef5fa9b07c - path: patches/remark-mdx-images@3.0.0.patch - importers: .: @@ -38,7 +33,7 @@ importers: version: 7.19.0 '@mdx-js/loader': specifier: ^3.0.0 - version: 3.1.1(webpack@5.105.2(esbuild@0.25.12)) + version: 3.1.1(webpack@5.105.2) '@mdx-js/mdx': specifier: ^3.0.0 version: 3.1.1 @@ -95,7 +90,7 @@ importers: version: 10.39.0 '@sentry/nextjs': specifier: ^10.27.0 - version: 10.39.0(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(webpack@5.105.2(esbuild@0.25.12)) + version: 10.39.0(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(webpack@5.105.2) '@types/mdx': specifier: ^2.0.9 version: 2.0.13 @@ -108,9 +103,6 @@ importers: dompurify: specifier: 3.2.4 version: 3.2.4 - esbuild: - specifier: ^0.25.0 - version: 0.25.12 framer-motion: specifier: ^10.12.16 version: 10.18.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -156,9 +148,6 @@ importers: mdast-util-to-string: specifier: ^4.0.0 version: 4.0.0 - mdx-bundler: - specifier: ^10.0.1 - version: 10.1.1(esbuild@0.25.12) mermaid: specifier: ^11.11.0 version: 11.12.3 @@ -166,7 +155,7 @@ importers: specifier: ^4.0.0 version: 4.0.2 next: - specifier: ^15.5.12 + specifier: 15.5.12 version: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) next-plausible: specifier: ^3.12.4 @@ -234,9 +223,6 @@ importers: remark-link-rewrite: specifier: ^1.0.7 version: 1.0.7 - remark-mdx-images: - specifier: ^3.0.0 - version: 3.0.0(patch_hash=073a4a4ae6cea36e784e927fdde45ca4ca67ad05afe07d93684620ef5fa9b07c) remark-parse: specifier: ^11.0.0 version: 11.0.0 @@ -291,7 +277,7 @@ importers: version: 7.28.5(@babel/core@7.29.0) '@codecov/nextjs-webpack-plugin': specifier: ^1.9.0 - version: 1.9.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(webpack@5.105.2(esbuild@0.25.12)) + version: 1.9.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(webpack@5.105.2) '@spotlightjs/spotlight': specifier: ^2.5.0 version: 2.13.3 @@ -975,317 +961,156 @@ packages: '@emotion/weak-memoize@0.4.0': resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==} - '@esbuild-plugins/node-resolve@0.2.2': - resolution: {integrity: sha512-+t5FdX3ATQlb53UFDBRb4nqjYBz492bIrnVWvpQHpzZlu9BQL5HasMZhqc409ygUwOWCXZhrWr6NyZ6T6Y+cxw==} - peerDependencies: - esbuild: '*' - - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.27.3': resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.27.3': resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.27.3': resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.27.3': resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.27.3': resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.27.3': resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.27.3': resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.27.3': resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.27.3': resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.27.3': resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.27.3': resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.27.3': resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.27.3': resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.27.3': resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.27.3': resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.27.3': resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.27.3': resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.27.3': resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - '@esbuild/openharmony-arm64@0.27.3': resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.27.3': resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.27.3': resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.27.3': resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.27.3': resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} engines: {node: '>=18'} @@ -1310,9 +1135,6 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@fal-works/esbuild-plugin-global-externals@2.1.2': - resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==} - '@fastify/busboy@2.1.1': resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} engines: {node: '>=14'} @@ -1737,11 +1559,6 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@mdx-js/esbuild@3.1.1': - resolution: {integrity: sha512-NS35VhTdvKNj5/B1JSD5W3kN1R0WDHgk+zCWq+tSChQw5L2Bgeiz7yyZPFrc5LWuPVOxE1xMbJr82bO9VVzmfQ==} - peerDependencies: - esbuild: '>=0.14.0' - '@mdx-js/loader@3.1.1': resolution: {integrity: sha512-0TTacJyZ9mDmY+VefuthVshaNIyCGZHJG2fMnGaDttCt8HmjUF7SizlHJpaCDoGnN635nK1wpzfpx/Xx5S4WnQ==} peerDependencies: @@ -3957,9 +3774,6 @@ packages: '@types/request@2.48.13': resolution: {integrity: sha512-FGJ6udDNUCjd19pp0Q3iTiDkwhYup7J8hpMW9c4k53NrccQFFWKRho6hvtPPEhnXWKvukfwAlB6DbDz4yhH5Gg==} - '@types/resolve@1.20.6': - resolution: {integrity: sha512-A4STmOXPhMUtHH+S6ymgE2GiBSMqf4oTvcQZMcHzokuTLVYzXTB8ttjcgxOVaAp2lGwEdzZ0J+cRbbeevQj1UQ==} - '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} @@ -5297,11 +5111,6 @@ packages: esast-util-from-js@2.0.1: resolution: {integrity: sha512-8Ja+rNJ0Lt56Pcf3TAmpBZjmx8ZcK5Ts4cAzIOjsjevg9oSXJnl6SUQ2EevU8tv3h6ZLWmoKL5H4fgWvdvfETw==} - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.27.3: resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} engines: {node: '>=18'} @@ -5538,9 +5347,6 @@ packages: estree-util-to-js@2.0.0: resolution: {integrity: sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==} - estree-util-value-to-estree@3.5.0: - resolution: {integrity: sha512-aMV56R27Gv3QmfmF1MY12GWkGzzeAezAX+UplqHVASfjc9wNzI/X6hC0S9oxq61WT4aQesLGslWP9tKk6ghRZQ==} - estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} @@ -5616,9 +5422,6 @@ packages: fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - fault@2.0.1: - resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} - fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -5677,10 +5480,6 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} - format@0.2.2: - resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} - engines: {node: '>=0.4.x'} - forwarded-parse@2.1.2: resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} @@ -6630,9 +6429,6 @@ packages: mdast-util-from-markdown@2.0.2: resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} - mdast-util-frontmatter@2.0.1: - resolution: {integrity: sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==} - mdast-util-gfm-autolink-literal@2.0.1: resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} @@ -6675,12 +6471,6 @@ packages: mdast-util-to-string@4.0.0: resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} - mdx-bundler@10.1.1: - resolution: {integrity: sha512-87FtxC7miUPznwqEaAlJARinHJ6Qin9kDuG2E2BCCNEOszr62kHpqivI/IF/CmwObVSpvApVFFxN1ftM/Gykvw==} - engines: {node: '>=18', npm: '>=6'} - peerDependencies: - esbuild: 0.* - memoize-one@6.0.0: resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} @@ -6697,9 +6487,6 @@ packages: micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} - micromark-extension-frontmatter@2.0.0: - resolution: {integrity: sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==} - micromark-extension-gfm-autolink-literal@2.1.0: resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} @@ -7519,9 +7306,6 @@ packages: rehype-stringify@10.0.1: resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} - remark-frontmatter@5.0.0: - resolution: {integrity: sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==} - remark-gfm@4.0.1: resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} @@ -7529,13 +7313,6 @@ packages: resolution: {integrity: sha512-jfmXL8VL3O7Ca4g+Ya0A0S9LIpVhCUSqMHiei4N8Z8Mx9z/oEI1HDoa1ZcF9/tS0I7NwydGsPkw2zT4eeoD6+Q==} engines: {node: '>=12.20'} - remark-mdx-frontmatter@4.0.0: - resolution: {integrity: sha512-PZzAiDGOEfv1Ua7exQ8S5kKxkD8CDaSb4nM+1Mprs6u8dyvQifakh+kCj6NovfGXW+bTvrhjaR3srzjS2qJHKg==} - - remark-mdx-images@3.0.0: - resolution: {integrity: sha512-EKpqw11XUprx/kFQPEkH3GdPEqI63Wcq5GT120N2hGlKCSwOM09NtL1i3G9HQ4TBIR2aF471HF5YStME5ukbJw==} - deprecated: Use rehype-mdx-import-media instead - remark-mdx@3.1.1: resolution: {integrity: sha512-Pjj2IYlUY3+D8x00UJsIOg5BEvfMyeI+2uLPn9VO9Wg4MEtN/VTIq2NEJQfde9PnX15KgtHyl9S0BcTnWrIuWg==} @@ -8054,9 +7831,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toml@3.0.0: - resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} - tough-cookie@4.1.4: resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==} engines: {node: '>=6'} @@ -9624,19 +9398,19 @@ snapshots: unplugin: 1.16.1 zod: 3.25.76 - '@codecov/nextjs-webpack-plugin@1.9.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(webpack@5.105.2(esbuild@0.25.12))': + '@codecov/nextjs-webpack-plugin@1.9.1(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(webpack@5.105.2)': dependencies: '@codecov/bundler-plugin-core': 1.9.1 - '@codecov/webpack-plugin': 1.9.1(webpack@5.105.2(esbuild@0.25.12)) + '@codecov/webpack-plugin': 1.9.1(webpack@5.105.2) next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) unplugin: 1.16.1 - webpack: 5.105.2(esbuild@0.25.12) + webpack: 5.105.2 - '@codecov/webpack-plugin@1.9.1(webpack@5.105.2(esbuild@0.25.12))': + '@codecov/webpack-plugin@1.9.1(webpack@5.105.2)': dependencies: '@codecov/bundler-plugin-core': 1.9.1 unplugin: 1.16.1 - webpack: 5.105.2(esbuild@0.25.12) + webpack: 5.105.2 '@cspotcode/source-map-support@0.8.1': dependencies: @@ -9759,169 +9533,81 @@ snapshots: '@emotion/weak-memoize@0.4.0': {} - '@esbuild-plugins/node-resolve@0.2.2(esbuild@0.25.12)': - dependencies: - '@types/resolve': 1.20.6 - debug: 4.4.3 - esbuild: 0.25.12 - escape-string-regexp: 4.0.0 - resolve: 1.22.11 - transitivePeerDependencies: - - supports-color - - '@esbuild/aix-ppc64@0.25.12': - optional: true - '@esbuild/aix-ppc64@0.27.3': optional: true - '@esbuild/android-arm64@0.25.12': - optional: true - '@esbuild/android-arm64@0.27.3': optional: true - '@esbuild/android-arm@0.25.12': - optional: true - '@esbuild/android-arm@0.27.3': optional: true - '@esbuild/android-x64@0.25.12': - optional: true - '@esbuild/android-x64@0.27.3': optional: true - '@esbuild/darwin-arm64@0.25.12': - optional: true - '@esbuild/darwin-arm64@0.27.3': optional: true - '@esbuild/darwin-x64@0.25.12': - optional: true - '@esbuild/darwin-x64@0.27.3': optional: true - '@esbuild/freebsd-arm64@0.25.12': - optional: true - '@esbuild/freebsd-arm64@0.27.3': optional: true - '@esbuild/freebsd-x64@0.25.12': - optional: true - '@esbuild/freebsd-x64@0.27.3': optional: true - '@esbuild/linux-arm64@0.25.12': - optional: true - '@esbuild/linux-arm64@0.27.3': optional: true - '@esbuild/linux-arm@0.25.12': - optional: true - '@esbuild/linux-arm@0.27.3': optional: true - '@esbuild/linux-ia32@0.25.12': - optional: true - '@esbuild/linux-ia32@0.27.3': optional: true - '@esbuild/linux-loong64@0.25.12': - optional: true - '@esbuild/linux-loong64@0.27.3': optional: true - '@esbuild/linux-mips64el@0.25.12': - optional: true - '@esbuild/linux-mips64el@0.27.3': optional: true - '@esbuild/linux-ppc64@0.25.12': - optional: true - '@esbuild/linux-ppc64@0.27.3': optional: true - '@esbuild/linux-riscv64@0.25.12': - optional: true - '@esbuild/linux-riscv64@0.27.3': optional: true - '@esbuild/linux-s390x@0.25.12': - optional: true - '@esbuild/linux-s390x@0.27.3': optional: true - '@esbuild/linux-x64@0.25.12': - optional: true - '@esbuild/linux-x64@0.27.3': optional: true - '@esbuild/netbsd-arm64@0.25.12': - optional: true - '@esbuild/netbsd-arm64@0.27.3': optional: true - '@esbuild/netbsd-x64@0.25.12': - optional: true - '@esbuild/netbsd-x64@0.27.3': optional: true - '@esbuild/openbsd-arm64@0.25.12': - optional: true - '@esbuild/openbsd-arm64@0.27.3': optional: true - '@esbuild/openbsd-x64@0.25.12': - optional: true - '@esbuild/openbsd-x64@0.27.3': optional: true - '@esbuild/openharmony-arm64@0.25.12': - optional: true - '@esbuild/openharmony-arm64@0.27.3': optional: true - '@esbuild/sunos-x64@0.25.12': - optional: true - '@esbuild/sunos-x64@0.27.3': optional: true - '@esbuild/win32-arm64@0.25.12': - optional: true - '@esbuild/win32-arm64@0.27.3': optional: true - '@esbuild/win32-ia32@0.25.12': - optional: true - '@esbuild/win32-ia32@0.27.3': optional: true - '@esbuild/win32-x64@0.25.12': - optional: true - '@esbuild/win32-x64@0.27.3': optional: true @@ -9948,8 +9634,6 @@ snapshots: '@eslint/js@8.57.1': {} - '@fal-works/esbuild-plugin-global-externals@2.1.2': {} - '@fastify/busboy@2.1.1': {} '@floating-ui/core@1.7.4': @@ -10401,23 +10085,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@mdx-js/esbuild@3.1.1(esbuild@0.25.12)': - dependencies: - '@mdx-js/mdx': 3.1.1 - '@types/unist': 3.0.3 - esbuild: 0.25.12 - source-map: 0.7.6 - vfile: 6.0.3 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color - - '@mdx-js/loader@3.1.1(webpack@5.105.2(esbuild@0.25.12))': + '@mdx-js/loader@3.1.1(webpack@5.105.2)': dependencies: '@mdx-js/mdx': 3.1.1 source-map: 0.7.6 optionalDependencies: - webpack: 5.105.2(esbuild@0.25.12) + webpack: 5.105.2 transitivePeerDependencies: - supports-color @@ -12171,7 +11844,7 @@ snapshots: '@sentry/core@8.55.0': {} - '@sentry/nextjs@10.39.0(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(webpack@5.105.2(esbuild@0.25.12))': + '@sentry/nextjs@10.39.0(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(next@15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3))(react@19.2.4)(webpack@5.105.2)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.39.0 @@ -12183,7 +11856,7 @@ snapshots: '@sentry/opentelemetry': 10.39.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.5.1(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.39.0) '@sentry/react': 10.39.0(react@19.2.4) '@sentry/vercel-edge': 10.39.0 - '@sentry/webpack-plugin': 4.9.1(webpack@5.105.2(esbuild@0.25.12)) + '@sentry/webpack-plugin': 4.9.1(webpack@5.105.2) next: 15.5.12(@babel/core@7.29.0)(@opentelemetry/api@1.9.0)(babel-plugin-macros@3.1.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(sass@1.97.3) rollup: 4.57.1 stacktrace-parser: 0.1.11 @@ -12324,12 +11997,12 @@ snapshots: '@opentelemetry/resources': 2.5.1(@opentelemetry/api@1.9.0) '@sentry/core': 10.39.0 - '@sentry/webpack-plugin@4.9.1(webpack@5.105.2(esbuild@0.25.12))': + '@sentry/webpack-plugin@4.9.1(webpack@5.105.2)': dependencies: '@sentry/bundler-plugin-core': 4.9.1 unplugin: 1.0.1 uuid: 9.0.1 - webpack: 5.105.2(esbuild@0.25.12) + webpack: 5.105.2 transitivePeerDependencies: - encoding - supports-color @@ -13016,8 +12689,6 @@ snapshots: '@types/tough-cookie': 4.0.5 form-data: 2.5.5 - '@types/resolve@1.20.6': {} - '@types/semver@7.7.1': {} '@types/shimmer@1.2.0': {} @@ -14555,35 +14226,6 @@ snapshots: esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - esbuild@0.27.3: optionalDependencies: '@esbuild/aix-ppc64': 0.27.3 @@ -14993,10 +14635,6 @@ snapshots: astring: 1.9.0 source-map: 0.7.6 - estree-util-value-to-estree@3.5.0: - dependencies: - '@types/estree': 1.0.8 - estree-util-visit@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -15080,10 +14718,6 @@ snapshots: dependencies: reusify: 1.1.0 - fault@2.0.1: - dependencies: - format: 0.2.2 - fb-watchman@2.0.2: dependencies: bser: 2.1.1 @@ -15154,8 +14788,6 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 - format@0.2.2: {} - forwarded-parse@2.1.2: {} fraction.js@5.3.4: {} @@ -16522,17 +16154,6 @@ snapshots: transitivePeerDependencies: - supports-color - mdast-util-frontmatter@2.0.1: - dependencies: - '@types/mdast': 4.0.4 - devlop: 1.1.0 - escape-string-regexp: 5.0.0 - mdast-util-from-markdown: 2.0.2 - mdast-util-to-markdown: 2.1.2 - micromark-extension-frontmatter: 2.0.0 - transitivePeerDependencies: - - supports-color - mdast-util-gfm-autolink-literal@2.0.1: dependencies: '@types/mdast': 4.0.4 @@ -16672,21 +16293,6 @@ snapshots: dependencies: '@types/mdast': 4.0.4 - mdx-bundler@10.1.1(esbuild@0.25.12): - dependencies: - '@babel/runtime': 7.28.6 - '@esbuild-plugins/node-resolve': 0.2.2(esbuild@0.25.12) - '@fal-works/esbuild-plugin-global-externals': 2.1.2 - '@mdx-js/esbuild': 3.1.1(esbuild@0.25.12) - esbuild: 0.25.12 - gray-matter: 4.0.3 - remark-frontmatter: 5.0.0 - remark-mdx-frontmatter: 4.0.0 - uuid: 9.0.1 - vfile: 6.0.3 - transitivePeerDependencies: - - supports-color - memoize-one@6.0.0: {} merge-stream@2.0.0: {} @@ -16735,13 +16341,6 @@ snapshots: micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - micromark-extension-frontmatter@2.0.0: - dependencies: - fault: 2.0.1 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - micromark-extension-gfm-autolink-literal@2.1.0: dependencies: micromark-util-character: 2.1.1 @@ -17901,15 +17500,6 @@ snapshots: hast-util-to-html: 9.0.5 unified: 11.0.5 - remark-frontmatter@5.0.0: - dependencies: - '@types/mdast': 4.0.4 - mdast-util-frontmatter: 2.0.1 - micromark-extension-frontmatter: 2.0.0 - unified: 11.0.5 - transitivePeerDependencies: - - supports-color - remark-gfm@4.0.1: dependencies: '@types/mdast': 4.0.4 @@ -17925,21 +17515,6 @@ snapshots: dependencies: unist-util-visit: 4.1.2 - remark-mdx-frontmatter@4.0.0: - dependencies: - '@types/mdast': 4.0.4 - estree-util-is-identifier-name: 3.0.0 - estree-util-value-to-estree: 3.5.0 - toml: 3.0.0 - unified: 11.0.5 - yaml: 2.8.2 - - remark-mdx-images@3.0.0(patch_hash=073a4a4ae6cea36e784e927fdde45ca4ca67ad05afe07d93684620ef5fa9b07c): - dependencies: - '@types/mdast': 4.0.4 - unified: 11.0.5 - unist-util-visit: 5.1.0 - remark-mdx@3.1.1: dependencies: mdast-util-mdx: 3.0.0 @@ -18547,16 +18122,14 @@ snapshots: - encoding - supports-color - terser-webpack-plugin@5.3.16(esbuild@0.25.12)(webpack@5.105.2(esbuild@0.25.12)): + terser-webpack-plugin@5.3.16(webpack@5.105.2): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 serialize-javascript: 6.0.2 terser: 5.46.0 - webpack: 5.105.2(esbuild@0.25.12) - optionalDependencies: - esbuild: 0.25.12 + webpack: 5.105.2 terser@5.46.0: dependencies: @@ -18614,8 +18187,6 @@ snapshots: dependencies: is-number: 7.0.0 - toml@3.0.0: {} - tough-cookie@4.1.4: dependencies: psl: 1.15.0 @@ -19145,7 +18716,7 @@ snapshots: webpack-virtual-modules@0.6.2: {} - webpack@5.105.2(esbuild@0.25.12): + webpack@5.105.2: dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.8 @@ -19169,7 +18740,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(esbuild@0.25.12)(webpack@5.105.2(esbuild@0.25.12)) + terser-webpack-plugin: 5.3.16(webpack@5.105.2) watchpack: 2.5.1 webpack-sources: 3.3.4 transitivePeerDependencies: @@ -19296,7 +18867,8 @@ snapshots: yaml@1.10.2: {} - yaml@2.8.2: {} + yaml@2.8.2: + optional: true yargs-parser@21.1.1: {} diff --git a/src/components/apiPage/index.tsx b/src/components/apiPage/index.tsx index fbe52d2c8ffd0..ac8d7c8b285d9 100644 --- a/src/components/apiPage/index.tsx +++ b/src/components/apiPage/index.tsx @@ -1,5 +1,5 @@ import {Fragment, ReactElement, useMemo} from 'react'; -import {bundleMDX} from 'mdx-bundler'; +import {compile} from '@mdx-js/mdx'; import {type API} from 'sentry-docs/build/resolveOpenAPI'; import {getMDXComponent} from 'sentry-docs/getMDXComponent'; @@ -95,21 +95,11 @@ async function parseMarkdown(source: string): Promise { source = source.replace(/style="([^"]+)"/g, (_, style) => { return `style={${JSON.stringify(cssToObj(style))}}`; }); - const {code} = await bundleMDX({ - source, - cwd: process.cwd(), - mdxOptions(options) { - options.remarkPlugins = [remarkCodeTitles, remarkCodeTabs]; - return options; - }, - esbuildOptions: options => { - options.loader = { - ...options.loader, - '.js': 'jsx', - }; - return options; - }, + const compiled = await compile(source, { + outputFormat: 'function-body', + remarkPlugins: [remarkCodeTitles, remarkCodeTabs], }); + const code = String(compiled); function MDXLayoutRenderer({mdxSource, ...rest}) { const MDXLayout = useMemo(() => getMDXComponent(mdxSource), [mdxSource]); return ; diff --git a/src/components/changelog/docsChangelog.tsx b/src/components/changelog/docsChangelog.tsx index 6c8f3c6a2a9b0..159bfd97ce2bd 100644 --- a/src/components/changelog/docsChangelog.tsx +++ b/src/components/changelog/docsChangelog.tsx @@ -1,3 +1,7 @@ +'use client'; + +import {useEffect, useState} from 'react'; + interface ChangelogEntry { author: string; description: string; @@ -12,27 +16,29 @@ interface ChangelogEntry { }; } -async function getChangelogEntries(): Promise { - try { - const res = await fetch('https://sentry-content-dashboard.sentry.dev/api/docs', { - next: {revalidate: 3600}, // Cache for 1 hour - }); +export function DocsChangelog() { + const [entries, setEntries] = useState([]); + const [loading, setLoading] = useState(true); - if (!res.ok) { - throw new Error(`Failed to fetch changelog: ${res.status} ${res.statusText}`); - } + useEffect(() => { + fetch('https://sentry-content-dashboard.sentry.dev/api/docs') + .then(res => (res.ok ? res.json() : [])) + .then(data => { + setEntries(data); + setLoading(false); + }) + .catch(() => setLoading(false)); + }, []); - return res.json(); - } catch (error) { - // eslint-disable-next-line no-console - console.error('Error fetching changelog:', error); - // Error fetching changelog - return empty array - return []; + if (loading) { + return ( +
+ {[...Array(3)].map((_, i) => ( +
+ ))} +
+ ); } -} - -export async function DocsChangelog() { - const entries = await getChangelogEntries(); if (entries.length === 0) { return ( @@ -43,7 +49,6 @@ export async function DocsChangelog() { ); } - // Show only the 20 most recent entries const recentEntries = entries.slice(0, 20); return ( @@ -84,18 +89,16 @@ export async function DocsChangelog() { )}
-

{entry.description}

- {entry.filesChanged && totalFiles > 0 && (
View changed files
- {entry.filesChanged.added && entry.filesChanged.added.length > 0 && ( + {entry.filesChanged.added?.length > 0 && (
Added: @@ -109,67 +112,40 @@ export async function DocsChangelog() {
)} - {entry.filesChanged.modified && - entry.filesChanged.modified.length > 0 && ( -
- - Modified: - -
    - {entry.filesChanged.modified.map(file => ( -
  • - {file} -
  • - ))} -
-
- )} - {entry.filesChanged.removed && - entry.filesChanged.removed.length > 0 && ( -
- - Removed: - -
    - {entry.filesChanged.removed.map(file => ( -
  • - {file} -
  • - ))} -
-
- )} + {entry.filesChanged.modified?.length > 0 && ( +
+ + Modified: + +
    + {entry.filesChanged.modified.map(file => ( +
  • + {file} +
  • + ))} +
+
+ )} + {entry.filesChanged.removed?.length > 0 && ( +
+ + Removed: + +
    + {entry.filesChanged.removed.map(file => ( +
  • + {file} +
  • + ))} +
+
+ )}
)} ); })} - {entries.length > 20 && ( -
-

- Showing the 20 most recent updates. View the{' '} - - full content dashboard - {' '} - or subscribe to the{' '} - - RSS feed - - . -

-
- )} ); } diff --git a/src/components/featureInfo.tsx b/src/components/featureInfo.tsx index efb752616b2ab..c3e22da4c79ae 100644 --- a/src/components/featureInfo.tsx +++ b/src/components/featureInfo.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @next/next/no-html-link-for-pages */ import type {ReactNode} from 'react'; import {Fragment} from 'react'; diff --git a/src/getMDXComponent.ts b/src/getMDXComponent.ts index ab5ead661ed29..84b8e88814db7 100644 --- a/src/getMDXComponent.ts +++ b/src/getMDXComponent.ts @@ -1,9 +1,11 @@ /** - * Local implementation of getMDXComponent replacing mdx-bundler/client. + * Evaluates compiled MDX code and returns a React component. * - * Eliminates the runtime dependency on mdx-bundler/client which has CJS/ESM - * compatibility issues in Vercel serverless functions. Since getMDXComponent - * only needs React at runtime, we can safely inline this implementation. + * Supports both output formats: + * - @mdx-js/mdx compile() with outputFormat: 'function-body' + * → uses arguments[0] for jsx runtime + * - Legacy mdx-bundler output (IIFE accessing named scope variables) + * → uses named params: React, ReactDOM, _jsx_runtime */ import type {ComponentType, FunctionComponent} from 'react'; // Namespace imports required - MDX runtime expects React, ReactDOM, jsx_runtime in scope @@ -19,7 +21,7 @@ export interface MDXContentProps { } /** - * Takes compiled MDX code from bundleMDX and returns a React component. + * Takes compiled MDX code and returns a React component. */ export function getMDXComponent( code: string, @@ -29,13 +31,17 @@ export function getMDXComponent( } /** - * Takes compiled MDX code from bundleMDX and returns all exports. + * Takes compiled MDX code and returns all exports. + * + * @mdx-js/mdx function-body output destructures jsx runtime from arguments[0]: + * const {Fragment, jsx, jsxs} = arguments[0]; + * + * We pass jsxRuntime as the sole argument to new Function(code). */ export function getMDXExport< ExportedObject = {default: FunctionComponent}, >(code: string, globals?: Record): ExportedObject { - const scope = {React, ReactDOM, _jsx_runtime: jsxRuntime, ...globals}; // eslint-disable-next-line @typescript-eslint/no-implied-eval, no-new-func - const fn = new Function(...Object.keys(scope), code); - return fn(...Object.values(scope)); + const fn = new Function(code); + return fn({...jsxRuntime, React, ReactDOM, ...globals}); } diff --git a/src/mdx.ts b/src/mdx.ts index 4116815d570eb..5402e72446a32 100644 --- a/src/mdx.ts +++ b/src/mdx.ts @@ -1,10 +1,10 @@ +import {compile} from '@mdx-js/mdx'; import matter from 'gray-matter'; import {s} from 'hastscript'; import yaml from 'js-yaml'; -import {bundleMDX} from 'mdx-bundler'; import {BinaryLike, createHash} from 'node:crypto'; import {createReadStream, createWriteStream, mkdirSync} from 'node:fs'; -import {access, cp, mkdir, opendir, readFile} from 'node:fs/promises'; +import {access, mkdir, opendir, readFile} from 'node:fs/promises'; import path from 'node:path'; // @ts-expect-error ts(2305) -- For some reason "compose" is not recognized in the types import {compose, Readable} from 'node:stream'; @@ -21,7 +21,6 @@ import rehypePresetMinify from 'rehype-preset-minify'; import rehypePrismDiff from 'rehype-prism-diff'; import rehypePrismPlus from 'rehype-prism-plus'; import remarkGfm from 'remark-gfm'; -import remarkMdxImages from 'remark-mdx-images'; import getAppRegistry from './build/appRegistry'; import getPackageRegistry from './build/packageRegistry'; @@ -34,7 +33,8 @@ import rehypeSlug from './rehype-slug.js'; import remarkCodeTabs from './remark-code-tabs'; import remarkCodeTitles from './remark-code-title'; import remarkComponentSpacing from './remark-component-spacing'; -import remarkExtractFrontmatter from './remark-extract-frontmatter'; +import remarkCopyImages, {copyImagesFromSource} from './remark-copy-images'; +// remarkExtractFrontmatter removed — gray-matter strips frontmatter before compile() import remarkFormatCodeBlocks from './remark-format-code'; import remarkImageProcessing from './remark-image-processing'; import remarkImageResize from './remark-image-resize'; @@ -62,7 +62,7 @@ const root = process.cwd(); // so many files at once. const FILE_CONCURRENCY_LIMIT = 200; const CACHE_COMPRESS_LEVEL = 4; -const CACHE_DIR = path.join(root, '.next', 'cache', 'mdx-bundler'); +const CACHE_DIR = path.join(root, '.next', 'cache', 'mdx-compile'); if (process.env.CI) { mkdirSync(CACHE_DIR, {recursive: true}); } @@ -637,7 +637,6 @@ export async function getFileBySlug(slug: string): Promise { let cacheKey: string | null = null; let cacheFile: string | null = null; - let assetsCacheDir: string | null = null; // Always use public/mdx-images during build // During runtime (Lambda), this directory is read-only but images are already there from build @@ -650,6 +649,11 @@ export async function getFileBySlug(slug: string): Promise { // continue anyway - images should already exist from build time } + // Copy images referenced in the source to public/mdx-images/ BEFORE the cache check. + // This ensures images exist even when MDX compilation is served from cache. + const cwd = path.dirname(sourcePath); + copyImagesFromSource(source, cwd, outdir); + // Detect if file contains content that depends on the Release Registry // If it does, we include the registry hash in the cache key so the cache // is invalidated when the registry changes. @@ -687,10 +691,9 @@ export async function getFileBySlug(slug: string): Promise { if (cacheKey) { cacheFile = path.join(CACHE_DIR, `${cacheKey}.br`); - assetsCacheDir = path.join(CACHE_DIR, cacheKey); try { - // Time only the cache read operation, not the asset copy + // Time only the cache read operation const cacheStartTime = Date.now(); const cached = await readCacheFile(cacheFile); const cacheReadDuration = Date.now() - cacheStartTime; @@ -713,9 +716,6 @@ export async function getFileBySlug(slug: string): Promise { }); } - // Copy assets (wait for completion before returning) - await cp(assetsCacheDir, outdir, {recursive: true}); - return cached; } catch (err) { if ( @@ -731,128 +731,88 @@ export async function getFileBySlug(slug: string): Promise { } } - process.env.ESBUILD_BINARY_PATH = path.join( - root, - 'node_modules', - 'esbuild', - 'bin', - 'esbuild' - ); - const toc: TocNode[] = []; - // cwd is how mdx-bundler knows how to resolve relative paths - const cwd = path.dirname(sourcePath); + // Extract frontmatter via gray-matter before compilation. + // Must strip frontmatter before passing to @mdx-js/mdx because + // frontmatter content (e.g. `<=` in descriptions) can be incorrectly parsed as JSX. + const matterResult = matter(source); + const frontmatter = matterResult.data as Platform; // Track MDX compilation timing const compilationStart = Date.now(); - const result = await bundleMDX({ - source, - cwd, - mdxOptions(options) { - // this is the recommended way to add custom remark/rehype plugins: - // The syntax might look weird, but it protects you in case we add/remove - // plugins in the future. - options.remarkPlugins = [ - ...(options.remarkPlugins ?? []), - remarkExtractFrontmatter, - [remarkTocHeadings, {exportRef: toc}], - remarkGfm, - remarkDefList, - remarkFormatCodeBlocks, - [ - remarkImageProcessing, - {sourceFolder: cwd, publicFolder: path.join(root, 'public')}, - ], - remarkMdxImages, - remarkImageResize, - remarkCodeTitles, - remarkCodeTabs, - remarkComponentSpacing, - [ - remarkVariables, - { - resolveScopeData: async () => { - const [apps, packages] = await Promise.all([ - getAppRegistry(), - getPackageRegistry(), - ]); - - return {apps, packages}; - }, + const compiled = await compile(matterResult.content, { + outputFormat: 'function-body', + remarkPlugins: [ + [remarkTocHeadings, {exportRef: toc}], + remarkGfm, + remarkDefList, + remarkFormatCodeBlocks, + [ + remarkImageProcessing, + {sourceFolder: cwd, publicFolder: path.join(root, 'public')}, + ], + [remarkCopyImages, {sourceFolder: cwd, outdir}], + remarkImageResize, + remarkCodeTitles, + remarkCodeTabs, + remarkComponentSpacing, + [ + remarkVariables, + { + resolveScopeData: async () => { + const [apps, packages] = await Promise.all([ + getAppRegistry(), + getPackageRegistry(), + ]); + + return {apps, packages}; }, - ], - ]; - options.rehypePlugins = [ - ...(options.rehypePlugins ?? []), - rehypeSlug, - [ - rehypeAutolinkHeadings, - { - behavior: 'wrap', - properties: { - ariaHidden: true, - tabIndex: -1, - className: 'autolink-heading', - }, - content: [ - s( - 'svg.anchorlink.before', - { - xmlns: 'http://www.w3.org/2000/svg', - width: 16, - height: 16, - fill: 'currentColor', - viewBox: '0 0 24 24', - }, - s('path', { - d: 'M9.199 13.599a5.99 5.99 0 0 0 3.949 2.345 5.987 5.987 0 0 0 5.105-1.702l2.995-2.994a5.992 5.992 0 0 0 1.695-4.285 5.976 5.976 0 0 0-1.831-4.211 5.99 5.99 0 0 0-6.431-1.242 6.003 6.003 0 0 0-1.905 1.24l-1.731 1.721a.999.999 0 1 0 1.41 1.418l1.709-1.699a3.985 3.985 0 0 1 2.761-1.123 3.975 3.975 0 0 1 2.799 1.122 3.997 3.997 0 0 1 .111 5.644l-3.005 3.006a3.982 3.982 0 0 1-3.395 1.126 3.987 3.987 0 0 1-2.632-1.563A1 1 0 0 0 9.201 13.6zm5.602-3.198a5.99 5.99 0 0 0-3.949-2.345 5.987 5.987 0 0 0-5.105 1.702l-2.995 2.994a5.992 5.992 0 0 0-1.695 4.285 5.976 5.976 0 0 0 1.831 4.211 5.99 5.99 0 0 0 6.431 1.242 6.003 6.003 0 0 0 1.905-1.24l1.723-1.723a.999.999 0 1 0-1.414-1.414L9.836 19.81a3.985 3.985 0 0 1-2.761 1.123 3.975 3.975 0 0 1-2.799-1.122 3.997 3.997 0 0 1-.111-5.644l3.005-3.006a3.982 3.982 0 0 1 3.395-1.126 3.987 3.987 0 0 1 2.632 1.563 1 1 0 0 0 1.602-1.198z', - }) - ), - ], + }, + ], + ], + rehypePlugins: [ + rehypeSlug, + [ + rehypeAutolinkHeadings, + { + behavior: 'wrap', + properties: { + ariaHidden: true, + tabIndex: -1, + className: 'autolink-heading', }, - ], - [rehypePrismPlus, {ignoreMissing: true}] as any, - rehypeOnboardingLines, - [rehypePrismDiff, {remove: true}] as any, - rehypePresetMinify, - ]; - return options; - }, - esbuildOptions: options => { - options.loader = { - ...options.loader, - '.js': 'jsx', - '.png': 'file', - '.gif': 'file', - '.jpg': 'file', - '.jpeg': 'file', - // inline svgs - '.svg': 'dataurl', - }; - // Set the `outdir` to a public location for this bundle. - // this is where these images will be copied - // the reason we use the cache folder when it's - // enabled is because mdx-images is a dumping ground - // for all images, so we cannot filter it out only - // for this specific slug easily - options.outdir = assetsCacheDir || outdir; - - // Set write to false to prevent esbuild from writing files automatically. - // We'll handle writing manually to gracefully handle read-only filesystems (e.g., Lambda runtime) - // In local dev, we need write=true to avoid images being embedded as binary data - options.write = - process.env.NODE_ENV === 'development' || !!process.env.CI || !process.env.VERCEL; - - return options; - }, + content: [ + s( + 'svg.anchorlink.before', + { + xmlns: 'http://www.w3.org/2000/svg', + width: 16, + height: 16, + fill: 'currentColor', + viewBox: '0 0 24 24', + }, + s('path', { + d: 'M9.199 13.599a5.99 5.99 0 0 0 3.949 2.345 5.987 5.987 0 0 0 5.105-1.702l2.995-2.994a5.992 5.992 0 0 0 1.695-4.285 5.976 5.976 0 0 0-1.831-4.211 5.99 5.99 0 0 0-6.431-1.242 6.003 6.003 0 0 0-1.905 1.24l-1.731 1.721a.999.999 0 1 0 1.41 1.418l1.709-1.699a3.985 3.985 0 0 1 2.761-1.123 3.975 3.975 0 0 1 2.799 1.122 3.997 3.997 0 0 1 .111 5.644l-3.005 3.006a3.982 3.982 0 0 1-3.395 1.126 3.987 3.987 0 0 1-2.632-1.563A1 1 0 0 0 9.201 13.6zm5.602-3.198a5.99 5.99 0 0 0-3.949-2.345 5.987 5.987 0 0 0-5.105 1.702l-2.995 2.994a5.992 5.992 0 0 0-1.695 4.285 5.976 5.976 0 0 0 1.831 4.211 5.99 5.99 0 0 0 6.431 1.242 6.003 6.003 0 0 0 1.905-1.24l1.723-1.723a.999.999 0 1 0-1.414-1.414L9.836 19.81a3.985 3.985 0 0 1-2.761 1.123 3.975 3.975 0 0 1-2.799-1.122 3.997 3.997 0 0 1-.111-5.644l3.005-3.006a3.982 3.982 0 0 1 3.395-1.126 3.987 3.987 0 0 1 2.632 1.563 1 1 0 0 0 1.602-1.198z', + }) + ), + ], + }, + ], + [rehypePrismPlus, {ignoreMissing: true}] as any, + rehypeOnboardingLines, + [rehypePrismDiff, {remove: true}] as any, + rehypePresetMinify, + ], }).catch(e => { // eslint-disable-next-line no-console - console.error('Error occurred during MDX compilation:', e.errors); + console.error('Error occurred during MDX compilation:', e); throw e; }); + const code = String(compiled); + // Track MDX compilation metrics for cache miss (server-side only) const compilationDuration = Date.now() - compilationStart; if (typeof window === 'undefined') { @@ -872,19 +832,13 @@ export async function getFileBySlug(slug: string): Promise { }); } - // Manually write output files from esbuild when available - // This only happens during build time (when filesystem is writable) - // At runtime (Lambda), files already exist from build time - - const {code, frontmatter} = result; - let mergedFrontmatter = frontmatter; if (configFrontmatter) { mergedFrontmatter = {...frontmatter, ...configFrontmatter}; } const resultObj: SlugFile = { - matter: result.matter, + matter: matterResult as SlugFile['matter'], mdxSource: code, toc, frontMatter: { @@ -893,13 +847,7 @@ export async function getFileBySlug(slug: string): Promise { }, }; - if (assetsCacheDir && cacheFile && cacheKey) { - try { - await cp(assetsCacheDir, outdir, {recursive: true}); - } catch (e) { - // If copy fails (e.g., on read-only filesystem), continue anyway - // Images should already exist from build time - } + if (cacheFile && cacheKey) { writeCacheFile(cacheFile, JSON.stringify(resultObj)).catch(e => { // eslint-disable-next-line no-console console.warn(`Failed to write MDX cache: ${cacheFile}`, e); diff --git a/src/mdxComponents.ts b/src/mdxComponents.ts index b0cc414fec2c1..b085a805ab788 100644 --- a/src/mdxComponents.ts +++ b/src/mdxComponents.ts @@ -4,6 +4,7 @@ import {Arcade} from './components/arcade'; import {AvailableSince} from './components/availableSince'; import {Break} from './components/break'; import {Card} from './components/card'; +import {DocsChangelog} from './components/changelog/docsChangelog'; import {CliChecksumTable} from './components/cliChecksumTable'; import {CodeBlock} from './components/codeBlock'; import {CodeTabs} from './components/codeTabs'; @@ -18,6 +19,7 @@ import {DevDocsCardGrid} from './components/devDocsCardGrid'; import DocImage from './components/docImage'; import {Expandable} from './components/expandable'; import {FeatureBadge} from './components/featureBadge'; +import {FeatureInfo} from './components/featureInfo'; import {GitHubCodePreview} from './components/githubCodePreview'; import {GitHubDomainChecker} from './components/githubDomainChecker'; import {GradleFeatureConfig} from './components/gradleFeatureConfig'; @@ -98,8 +100,10 @@ export function mdxComponents( GradleUploadInstructions, ConfigValue, DefinitionList, + DocsChangelog, Expandable, FeatureBadge, + FeatureInfo, GuideGrid, IntegrationListItem, JsBundleList, diff --git a/src/remark-copy-images.js b/src/remark-copy-images.js new file mode 100644 index 0000000000000..63d2bbcba20db --- /dev/null +++ b/src/remark-copy-images.js @@ -0,0 +1,119 @@ +import {createHash} from 'node:crypto'; +import {copyFileSync, existsSync, mkdirSync, readFileSync} from 'node:fs'; +import path from 'node:path'; +import {visit} from 'unist-util-visit'; + +/** + * Copy all relative images referenced in an MDX source string to outdir. + * This runs BEFORE the MDX cache check so images exist even on cache hits. + * + * @param {string} source - Raw MDX source content + * @param {string} sourceFolder - Directory containing the MDX file + * @param {string} outdir - Output directory (e.g. public/mdx-images) + */ +export function copyImagesFromSource(source, sourceFolder, outdir) { + mkdirSync(outdir, {recursive: true}); + + // Match markdown image syntax: ![...](path.ext) — both ./relative and bare relative + // Match any image extension to stay in sync with the remark plugin + const imageRegex = + /!\[[^\]]*\]\(([^)\s:]+\.(png|jpe?g|gif|svg|webp|avif|ico|bmp|tiff?)[^)]*)\)/gi; + for (const match of source.matchAll(imageRegex)) { + const rawUrl = match[1]; + const cleanUrl = rawUrl.split('?')[0].split('#')[0]; + + // Skip absolute URLs and data URIs + if ( + cleanUrl.startsWith('http') || + cleanUrl.startsWith('//') || + cleanUrl.startsWith('data:') || + cleanUrl.startsWith('/') + ) { + continue; + } + + const srcPath = path.resolve(sourceFolder, cleanUrl); + if (!existsSync(srcPath)) { + continue; + } + + const content = readFileSync(srcPath); + const hash = createHash('md5').update(content).digest('hex').slice(0, 8); + const ext = path.extname(cleanUrl); + const basename = path.basename(cleanUrl, ext); + const destPath = path.join(outdir, `${basename}-${hash.toUpperCase()}${ext}`); + + if (!existsSync(destPath)) { + copyFileSync(srcPath, destPath); + } + } +} + +/** + * Remark plugin that rewrites relative image URLs to content-hashed filenames + * in public/mdx-images/. Also copies images (idempotent — skips if exists). + * + * Images stay as regular markdown `image` AST nodes (no import conversion). + * The DocImage component handles `./` prefix → `/mdx-images/` resolution. + * + * @param {Object} options + * @param {string} options.sourceFolder - Directory containing the MDX file + * @param {string} options.outdir - Output directory for copied images + */ +export default function remarkCopyImages({sourceFolder, outdir}) { + mkdirSync(outdir, {recursive: true}); + + return tree => { + visit(tree, 'image', node => { + const {url} = node; + + // Skip external URLs and absolute paths + if ( + url.startsWith('http') || + url.startsWith('//') || + url.startsWith('/') || + url.startsWith('data:') + ) { + return; + } + + // Strip query params and hash to get the actual file path + const cleanUrl = url.split('?')[0].split('#')[0]; + // Normalize bare relative paths (e.g. "img/foo.png" → "./img/foo.png") + const normalizedUrl = + cleanUrl.startsWith('./') || cleanUrl.startsWith('../') + ? cleanUrl + : `./${cleanUrl}`; + const srcPath = path.resolve(sourceFolder, normalizedUrl); + + if (!existsSync(srcPath)) { + return; + } + + const content = readFileSync(srcPath); + const hash = createHash('md5').update(content).digest('hex').slice(0, 8); + const ext = path.extname(cleanUrl); + const basename = path.basename(cleanUrl, ext); + const hashedName = `${basename}-${hash.toUpperCase()}${ext}`; + + // Copy (idempotent) + const destPath = path.join(outdir, hashedName); + if (!existsSync(destPath)) { + copyFileSync(srcPath, destPath); + } + + // Preserve query params and hash from the original URL + const queryStart = url.indexOf('?'); + const hashStart = url.indexOf('#'); + let suffix = ''; + if (queryStart !== -1) { + suffix = url.slice(queryStart); + } else if (hashStart !== -1) { + suffix = url.slice(hashStart); + } + + // Rewrite URL — DocImage resolves ./ → /mdx-images/ + node.url = `./${hashedName}${suffix}`; + }); + }; +} diff --git a/src/remark-image-resize.js b/src/remark-image-resize.js index d32f1d073b9f1..a00b8fd3edb86 100644 --- a/src/remark-image-resize.js +++ b/src/remark-image-resize.js @@ -4,23 +4,59 @@ const SIZE_FROM_ALT_RE = /\s*=\s*(?:(\d+)\s*x\s*(\d+)|(\d+)\s*x|x\s*(\d+))\s*$/; /** * remark plugin to parse width/height hints from the image ALT text. * - * This plugin is intended to run AFTER `remark-mdx-images`, so it processes - * mdxJsxTextElement nodes named `img` (i.e., in MDX). - * * Supported ALT suffixes (trailing in ALT text): * ![Alt text =300x200](./image.png) * ![Alt text =300x](./image.png) * ![Alt text =x200](./image.png) * - * Behavior: - * - Extracts the trailing "=WxH" (width-only/height-only also supported). - * - Cleans the ALT text by removing the size suffix. - * - Adds numeric `width`/`height` attributes to the element. + * Handles both: + * - Regular `image` AST nodes (standard markdown images) — converts to + * mdxJsxTextElement with width/height attributes when size suffix is found + * - `mdxJsxTextElement` nodes named `img` (legacy, from remark-mdx-images) */ export default function remarkImageResize() { - return tree => + return tree => { + // Handle regular markdown image nodes — convert to JSX with attributes + visit(tree, 'image', (node, index, parent) => { + if (!node.alt || !parent) { + return; + } + const sizeMatch = node.alt.match(SIZE_FROM_ALT_RE); + if (!sizeMatch) { + return; + } + const [, wBoth, hBoth, wOnlyWithX, hOnlyWithX] = sizeMatch; + const w = wBoth || wOnlyWithX || undefined; + const h = hBoth || hOnlyWithX || undefined; + const cleanedAlt = node.alt.replace(SIZE_FROM_ALT_RE, '').trim(); + + // Convert to mdxJsxTextElement so we can set width/height attributes + const attributes = [ + {type: 'mdxJsxAttribute', name: 'alt', value: cleanedAlt}, + {type: 'mdxJsxAttribute', name: 'src', value: node.url}, + ]; + if (node.title) { + attributes.push({type: 'mdxJsxAttribute', name: 'title', value: node.title}); + } + if (w) { + attributes.push({type: 'mdxJsxAttribute', name: 'width', value: w}); + } + if (h) { + attributes.push({type: 'mdxJsxAttribute', name: 'height', value: h}); + } + + const jsxElement = { + type: 'mdxJsxTextElement', + name: 'img', + children: [], + attributes, + }; + + parent.children.splice(index, 1, jsxElement); + }); + + // Handle MDX JSX produced by remark-mdx-images (backwards compat) visit(tree, {type: 'mdxJsxTextElement', name: 'img'}, node => { - // Handle MDX JSX produced by remark-mdx-images const altIndex = node.attributes.findIndex(a => a && a.name === 'alt'); const altValue = altIndex !== -1 && typeof node.attributes[altIndex].value === 'string' @@ -33,7 +69,6 @@ export default function remarkImageResize() { const wStr = wBoth || wOnlyWithX || undefined; const hStr = hBoth || hOnlyWithX || undefined; const cleanedAlt = altValue.replace(SIZE_FROM_ALT_RE, '').trim(); - // set cleaned alt node.attributes[altIndex] = { type: 'mdxJsxAttribute', name: 'alt', @@ -47,4 +82,5 @@ export default function remarkImageResize() { } } }); + }; } diff --git a/tsconfig.json b/tsconfig.json index 29aa1222c67e1..8e06cc878f2af 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -79,6 +79,7 @@ "**/*.ts", "**/*.tsx", "next-env.d.ts", - ".next/types/**/*.ts" + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" ] }