diff --git a/astro.config.ts b/astro.config.ts index 721a58f543f..7b75b2ac083 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -12,14 +12,8 @@ import { readdir, readFile } from "fs/promises"; import { join } from "path"; import { fileURLToPath } from "url"; -import remarkValidateImages from "./src/plugins/remark/validate-images"; - -import rehypeTitleFigure from "rehype-title-figure"; -import rehypeMermaid from "./src/plugins/rehype/mermaid.ts"; -import rehypeAutolinkHeadings from "./src/plugins/rehype/autolink-headings.ts"; -import rehypeExternalLinks from "./src/plugins/rehype/external-links.ts"; -import rehypeHeadingSlugs from "./src/plugins/rehype/heading-slugs.ts"; -import rehypeShiftHeadings from "./src/plugins/rehype/shift-headings.ts"; +import { satteri } from "@astrojs/markdown-satteri"; +import { mdastPlugins, hastPlugins } from "./src/plugins/satteri/index.ts"; import { createSitemapLastmodSerializer } from "./sitemap.serializer.ts"; import skills from "astro-skills"; @@ -93,26 +87,19 @@ const sidebar = await autogenSections(); const customCss = await autogenStyles(); const externalLinkPaths = await getExternalLinkPaths("src/content/docs"); -const RUN_LINK_CHECK = - process.env.RUN_LINK_CHECK?.toLowerCase() === "true" || false; +// Temporarily disabled during the satteri migration; re-enable once link validation is green. +const RUN_LINK_CHECK = false; // https://astro.build/config export default defineConfig({ site: "https://developers.cloudflare.com", cacheDir: ".astro-cache", markdown: { - gfm: true, - smartypants: false, - remarkPlugins: [remarkValidateImages], - rehypePlugins: [ - rehypeMermaid, - rehypeExternalLinks, - rehypeHeadingSlugs, - rehypeAutolinkHeadings, - // @ts-expect-error plugins types are outdated but functional - rehypeTitleFigure, - rehypeShiftHeadings, - ], + processor: satteri({ + mdastPlugins, + hastPlugins, + features: { gfm: true, smartPunctuation: false }, + }), }, image: { service: { diff --git a/package.json b/package.json index 64c42f90704..066bf21285a 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@apidevtools/swagger-parser": "12.1.0", "@astrojs/check": "0.9.9", "@astrojs/markdown-remark": "7.2.0", + "@astrojs/markdown-satteri": "0.3.0", "@astrojs/mdx": "6.0.3", "@astrojs/react": "5.0.7", "@astrojs/rss": "4.0.18", @@ -114,6 +115,7 @@ "mdast-util-from-markdown": "2.0.3", "mdast-util-mdx": "3.0.0", "mdast-util-mdx-expression": "2.0.1", + "mdast-util-to-string": "4.0.0", "mermaid": "11.15.0", "micromark-extension-mdxjs": "3.0.0", "nanostores": "1.3.0", @@ -141,6 +143,7 @@ "remark": "15.0.1", "remark-gfm": "4.0.1", "remark-stringify": "11.0.0", + "satteri": "0.8.1", "sharp": "0.35.1", "solarflare-theme": "0.0.6", "space-separated-tokens": "2.0.2", @@ -178,5 +181,12 @@ "version": ">=24.0.0", "onFail": "error" } + }, + "pnpm": { + "peerDependencyRules": { + "allowedVersions": { + "@astrojs/starlight>@astrojs/markdown-satteri": "0.3.0" + } + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7b1d080e2bd..af71edcdd86 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -23,9 +23,12 @@ importers: '@astrojs/markdown-remark': specifier: 7.2.0 version: 7.2.0 + '@astrojs/markdown-satteri': + specifier: 0.3.0 + version: 0.3.0 '@astrojs/mdx': specifier: 6.0.3 - version: 6.0.3(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 6.0.3(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)) '@astrojs/react': specifier: 5.0.7 version: 5.0.7(@types/node@25.9.3)(@types/react-dom@19.0.4(@types/react@19.0.7))(@types/react@19.0.7)(jiti@2.7.0)(lightningcss@1.32.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(tsx@4.22.4)(yaml@2.9.0) @@ -37,13 +40,13 @@ importers: version: 3.7.3 '@astrojs/starlight': specifier: 0.40.0 - version: 0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + version: 0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) '@astrojs/starlight-docsearch': specifier: 0.7.0 - version: 0.7.0(@algolia/client-search@5.54.1)(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3) + version: 0.7.0(@algolia/client-search@5.54.1)(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3) '@astrojs/starlight-tailwind': specifier: 5.0.0 - version: 5.0.0(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(tailwindcss@4.1.4) + version: 5.0.0(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(tailwindcss@4.1.4) '@base-ui/react': specifier: 1.5.0 version: 1.5.0(@types/react@19.0.7)(date-fns@4.4.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -133,19 +136,19 @@ importers: version: 5.54.1 astro: specifier: 6.4.7 - version: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0) + version: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0) astro-breadcrumbs: specifier: 3.4.0 - version: 3.4.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 3.4.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)) astro-expressive-code: specifier: 0.43.1 - version: 0.43.1(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 0.43.1(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)) astro-icon: specifier: 1.1.5 version: 1.1.5 astro-skills: specifier: 0.1.0 - version: 0.1.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + version: 0.1.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) cidr-tools: specifier: 12.0.3 version: 12.0.3 @@ -236,6 +239,9 @@ importers: mdast-util-mdx-expression: specifier: 2.0.1 version: 2.0.1 + mdast-util-to-string: + specifier: 4.0.0 + version: 4.0.0 mermaid: specifier: 11.15.0 version: 11.15.0 @@ -317,6 +323,9 @@ importers: remark-stringify: specifier: 11.0.0 version: 11.0.0 + satteri: + specifier: 0.8.1 + version: 0.8.1 sharp: specifier: 0.35.1 version: 0.35.1 @@ -328,19 +337,19 @@ importers: version: 2.0.2 starlight-image-zoom: specifier: 0.14.2 - version: 0.14.2(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)) + version: 0.14.2(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)) starlight-links-validator: specifier: 0.24.1 - version: 0.24.1(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)) + version: 0.24.1(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)) starlight-package-managers: specifier: 0.12.0 - version: 0.12.0(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)) + version: 0.12.0(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)) starlight-scroll-to-top: specifier: 1.0.1 - version: 1.0.1(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)) + version: 1.0.1(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)) starlight-showcases: specifier: 0.3.2 - version: 0.3.2(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)) + version: 0.3.2(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)) strip-markdown: specifier: 6.0.0 version: 6.0.0 @@ -563,6 +572,9 @@ packages: '@astrojs/markdown-remark@7.2.0': resolution: {integrity: sha512-+YxmVQu1Bd+MFfSzjq1rOJvD9+nIOJzz5YIIhdIH01RrxRkKbyKoEgyIqP3yv51MhzMDgd79QaPv+kCVPT8vHw==} + '@astrojs/markdown-satteri@0.3.0': + resolution: {integrity: sha512-dJ3boRA7LyPTF13aOFUtZlY8XgnjMNXNL8Hc7FuUsT5IRtMKTl8DKjcV4JvLLKKc0kxHMsVoVnnH99e+aJRkjA==} + '@astrojs/mdx@6.0.3': resolution: {integrity: sha512-+4P3ZvwsRAqAbBgY+uZMewFo3ficlIBPZfu/Luk+v4ia/ZOuFhpsw7r+7672uT2Fc1UPdp7yW0eU5egvSq0wbw==} engines: {node: '>=22.12.0'} @@ -739,6 +751,32 @@ packages: '@braintree/sanitize-url@7.1.2': resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} + '@bruits/satteri-darwin-arm64@0.8.1': + resolution: {integrity: sha512-9R8icJLGP8e3LOh8qLTZP1wdSGti6+OzGu3RCuSinMHUdPhTEDU3kbPV35vTGxUHghDGKYXPZBP+jDsbvKdf6A==} + cpu: [arm64] + os: [darwin] + + '@bruits/satteri-darwin-x64@0.8.1': + resolution: {integrity: sha512-UY5qDOoPXFsSnmfU6Qwi7h0hrtwlU8brwDrgZ4C1GSjcBVV01kQ96iXX+JIDoyO1Lnps0Wola0ar+iwkL2sAtg==} + cpu: [x64] + os: [darwin] + + '@bruits/satteri-linux-x64-gnu@0.8.1': + resolution: {integrity: sha512-OnOyNWEgUVFiDlaVuzd56GSucKY2F+1GMUT9lBqHb4TI0OQgZRP4fCfwxfz+2Rb1hQXuEGSTRJjyhPGQ5ft6kQ==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@bruits/satteri-wasm32-wasi@0.8.1': + resolution: {integrity: sha512-FKgKMIplotnCobQwfVd81YSakgiUBSn+truqElYFX9O+sinePlJXmLuDECNS1Utj8/59t0ryOZ2Sv1ThfAfaNA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@bruits/satteri-win32-x64-msvc@0.8.1': + resolution: {integrity: sha512-YgNvyaW5MLsrcnlwLdjk7/wSdER15+8cGdCHVkJY3KuaBdEW6XnfA35Svf88Ar+gBG+QsHEb8JE42DEJUiw22g==} + cpu: [x64] + os: [win32] + '@capsizecss/unpack@4.0.1': resolution: {integrity: sha512-CuNiSqg7+e1cO/GjffyMOm5Tt2jUF9CWHHnvQ/UkqvtkGfHdgwEC0wpmq7fkN3gxwpRnrAN0WzO3vREKmNolMQ==} engines: {node: '>=18'} @@ -755,11 +793,11 @@ packages: engines: {node: '>= 20.12.0'} '@cloudflare/kv-asset-handler@0.5.0': - resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==, tarball: https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz} + resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} engines: {node: '>=22.0.0'} '@cloudflare/unenv-preset@2.16.1': - resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==, tarball: https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz} + resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} peerDependencies: unenv: 2.0.0-rc.24 workerd: '>1.20260305.0 <2.0.0-0' @@ -768,7 +806,7 @@ packages: optional: true '@cloudflare/vitest-pool-workers@0.16.15': - resolution: {integrity: sha512-R0kZhIm4uSxOeTWPHY9xYIFPGRBEHPzl/n9BbHZSY/gk0n16uDU7T1JZe372oTF+diXG1uVBWqiiRc7Hxstdow==, tarball: https://registry.npmjs.org/@cloudflare/vitest-pool-workers/-/vitest-pool-workers-0.16.15.tgz} + resolution: {integrity: sha512-R0kZhIm4uSxOeTWPHY9xYIFPGRBEHPzl/n9BbHZSY/gk0n16uDU7T1JZe372oTF+diXG1uVBWqiiRc7Hxstdow==} peerDependencies: '@vitest/runner': ^4.1.0 '@vitest/snapshot': ^4.1.0 @@ -805,7 +843,7 @@ packages: os: [win32] '@cloudflare/workers-types@4.20260615.1': - resolution: {integrity: sha512-fGOiTwoLj/8bU8mj3VAfa1EULx4ceZhDwnjvY+afDBlSXI9pvY7PE9t62rGEhJjbAOGd7i5WUDun0eZCWBDrzg==, tarball: https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20260615.1.tgz} + resolution: {integrity: sha512-fGOiTwoLj/8bU8mj3VAfa1EULx4ceZhDwnjvY+afDBlSXI9pvY7PE9t62rGEhJjbAOGd7i5WUDun0eZCWBDrzg==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} @@ -859,9 +897,21 @@ packages: '@emmetio/stream-reader@2.2.0': resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + '@emnapi/core@1.9.1': + resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@emnapi/runtime@1.11.1': resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + '@emnapi/runtime@1.9.1': + resolution: {integrity: sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA==} + + '@emnapi/wasi-threads@1.2.0': + resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} + '@emotion/babel-plugin@11.13.5': resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==} @@ -915,8 +965,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/aix-ppc64@0.28.1': - resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + '@esbuild/aix-ppc64@0.28.0': + resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -933,8 +983,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.28.1': - resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + '@esbuild/android-arm64@0.28.0': + resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -957,8 +1007,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.28.1': - resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + '@esbuild/android-arm@0.28.0': + resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -975,8 +1025,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.28.1': - resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + '@esbuild/android-x64@0.28.0': + resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -993,8 +1043,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.28.1': - resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + '@esbuild/darwin-arm64@0.28.0': + resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1011,8 +1061,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.28.1': - resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + '@esbuild/darwin-x64@0.28.0': + resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1029,8 +1079,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.28.1': - resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + '@esbuild/freebsd-arm64@0.28.0': + resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1047,8 +1097,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.28.1': - resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + '@esbuild/freebsd-x64@0.28.0': + resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1065,8 +1115,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.28.1': - resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + '@esbuild/linux-arm64@0.28.0': + resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1083,8 +1133,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.28.1': - resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + '@esbuild/linux-arm@0.28.0': + resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1101,8 +1151,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.28.1': - resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + '@esbuild/linux-ia32@0.28.0': + resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1125,8 +1175,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.28.1': - resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + '@esbuild/linux-loong64@0.28.0': + resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1143,8 +1193,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.28.1': - resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + '@esbuild/linux-mips64el@0.28.0': + resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1161,8 +1211,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.28.1': - resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + '@esbuild/linux-ppc64@0.28.0': + resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1179,8 +1229,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.28.1': - resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + '@esbuild/linux-riscv64@0.28.0': + resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1197,8 +1247,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.28.1': - resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + '@esbuild/linux-s390x@0.28.0': + resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1215,8 +1265,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.28.1': - resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + '@esbuild/linux-x64@0.28.0': + resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -1233,8 +1283,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-arm64@0.28.1': - resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + '@esbuild/netbsd-arm64@0.28.0': + resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -1251,8 +1301,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.28.1': - resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + '@esbuild/netbsd-x64@0.28.0': + resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1269,8 +1319,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-arm64@0.28.1': - resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + '@esbuild/openbsd-arm64@0.28.0': + resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -1287,8 +1337,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.28.1': - resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + '@esbuild/openbsd-x64@0.28.0': + resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -1305,8 +1355,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/openharmony-arm64@0.28.1': - resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + '@esbuild/openharmony-arm64@0.28.0': + resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -1323,8 +1373,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.28.1': - resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + '@esbuild/sunos-x64@0.28.0': + resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1341,8 +1391,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.28.1': - resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + '@esbuild/win32-arm64@0.28.0': + resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1359,8 +1409,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.28.1': - resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + '@esbuild/win32-ia32@0.28.0': + resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1377,8 +1427,8 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.28.1': - resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + '@esbuild/win32-x64@0.28.0': + resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1874,8 +1924,14 @@ packages: nanostores: ^1.2.0 react: '>=18.0.0' - '@nodable/entities@2.2.0': - resolution: {integrity: sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==} + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@nodable/entities@2.1.1': + resolution: {integrity: sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -2030,141 +2086,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.62.0': - resolution: {integrity: sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==} + '@rollup/rollup-android-arm-eabi@4.61.0': + resolution: {integrity: sha512-dnxczajOqt0gesZlN5pGQ1s1imQVrsmCw5G2Ci4oM+0WvNz3pyRnlWrT7McoZIb8VlFwCawdmbWRmxRn7HI+VQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.62.0': - resolution: {integrity: sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==} + '@rollup/rollup-android-arm64@4.61.0': + resolution: {integrity: sha512-Bp3JpGP00Vu3f238ivRrjf7z3xSzVPXqCmaJYA9t2c+c8vKYvOzmXF7LkkeUalTEGd6cZcSWe+PFIP3Vy48fRg==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.62.0': - resolution: {integrity: sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==} + '@rollup/rollup-darwin-arm64@4.61.0': + resolution: {integrity: sha512-zaYIpr670mUmmZ1tVzUFplbQbG7h3Gugx3L5FoqhsC2m/YnLlR1a7zVLmXNPy+iY1tFPEbNG+HHBXZGyId0G5w==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.62.0': - resolution: {integrity: sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==} + '@rollup/rollup-darwin-x64@4.61.0': + resolution: {integrity: sha512-+P49fvkv2dSoeevUW+lgZ/I2JHSsJCK1Lyjj7Cu6E4UHG4tS9XIefzIjo5qhgELjAclnen1rLzK2PMKJdo+Dyg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.62.0': - resolution: {integrity: sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==} + '@rollup/rollup-freebsd-arm64@4.61.0': + resolution: {integrity: sha512-l3FAAOyKJXH2ea6KNFN+MMgC/rnE94YGLXs2ehYqDcCoHt1DpvgWX75BhUJxN38XojP7Ul+4H8PRn7EdyqSDrw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.62.0': - resolution: {integrity: sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==} + '@rollup/rollup-freebsd-x64@4.61.0': + resolution: {integrity: sha512-VokPN3TSctKj65cyCNPaUh4vMFA8awxOot/0sp+4J7ZlNRKQEhXhawqPwajoi8H5ZFt61i0ugZJuTKXBjGJ17Q==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.62.0': - resolution: {integrity: sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==} + '@rollup/rollup-linux-arm-gnueabihf@4.61.0': + resolution: {integrity: sha512-DxH0P3wxm+Yzs/p3zrk9dw1rURu8p0Nv5+MRK/L7OtnLNg5rLZraSBFZ8iUXOd9f2BlhJyEpIZUH/emjq4UJ4g==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.62.0': - resolution: {integrity: sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==} + '@rollup/rollup-linux-arm-musleabihf@4.61.0': + resolution: {integrity: sha512-T6ZvMNe84kAz6TBWHC7hGAoEtzP1LWYw/AqayGWEF6uISt3Abk/st06LqRD9THd7Xz3NxzurUpzAuEAUbZf+nw==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.62.0': - resolution: {integrity: sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==} + '@rollup/rollup-linux-arm64-gnu@4.61.0': + resolution: {integrity: sha512-q/4hzvQkDs8b4jIBab1pnLiiM0ayTZsN2amBFPDzuyZxjEd4wDwx0UJFYM3cOZzSf5Kw8fnWSprJzIBMkcR44Q==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.62.0': - resolution: {integrity: sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==} + '@rollup/rollup-linux-arm64-musl@4.61.0': + resolution: {integrity: sha512-vvYWX3akdEAY6km+9wAqFDnk6pQsbJKVnj7xawcvs/+fdlYBGp+U+Qq/lLfpIxYIZvZLHMAKD9HLdacSx/r3dw==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.62.0': - resolution: {integrity: sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==} + '@rollup/rollup-linux-loong64-gnu@4.61.0': + resolution: {integrity: sha512-DePa5cqOxDP/Zp0VOXpeWaGew5iIv5DXp9NYbzkX5PFQyWVX9184WCTh3hvr/7lhXo8ZVlbFLkz8+o/q1dU6gA==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.62.0': - resolution: {integrity: sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==} + '@rollup/rollup-linux-loong64-musl@4.61.0': + resolution: {integrity: sha512-LV8aWMB8UChglMCEzs7RkN0GsH29RJaLLqwm9fCIjlqwxQTiWAqNcc7wjBkH31hV0PU/yVxGYvrYsgfea2qw6g==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.62.0': - resolution: {integrity: sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==} + '@rollup/rollup-linux-ppc64-gnu@4.61.0': + resolution: {integrity: sha512-QoNSnwQtaeNu5grdBbsL0tt1uyl5EnS8DA8Mr3nluMXbhdQNyhN+G4tBax7VCdxLKj8YJ0/4OO9Ho84jMnJtKA==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.62.0': - resolution: {integrity: sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==} + '@rollup/rollup-linux-ppc64-musl@4.61.0': + resolution: {integrity: sha512-/zZp5MKapIIApE8trN8qLGNSiRN9TUoaUZ1cmVu4XnVdd5LQLOXTtyi+vtfUbNnT3iyjzpPqYeKXmvJ+gJGYWw==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.62.0': - resolution: {integrity: sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==} + '@rollup/rollup-linux-riscv64-gnu@4.61.0': + resolution: {integrity: sha512-RbrzcD3aJ1k3UbtMRRBNwojdVVyXjuVAFTfn/xPa6EEl6GE9Sm/akPgFTb9aAC9pMKGJ6CtWxaGrqWcabH+ySg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.62.0': - resolution: {integrity: sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==} + '@rollup/rollup-linux-riscv64-musl@4.61.0': + resolution: {integrity: sha512-ZF+onDsBso8PJf1XaG9lB+O9RnBpKGnY6OrzC4CSHrtC1jb6jWLTKK4bRqdoCXHd22gyr2hiYmEAm8Wns/BOCw==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.62.0': - resolution: {integrity: sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==} + '@rollup/rollup-linux-s390x-gnu@4.61.0': + resolution: {integrity: sha512-Atk0aSIk5Zx2Wuh9dgRQgLP0Koc8hOeYpbWryMXyk8G8/HmPkwPPkMqIIDhrXHHYqfUzSJA/I7IWSBv8xSmRBA==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.62.0': - resolution: {integrity: sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==} + '@rollup/rollup-linux-x64-gnu@4.61.0': + resolution: {integrity: sha512-0uMOcf3eZ5K+K4cYHkdxShFMPlPXCOdfDFEFn9dNYAEEd2cVvmOfH7zFgRVoDgmtQ1m9k5q7qfrHzyMAubKYUA==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.62.0': - resolution: {integrity: sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==} + '@rollup/rollup-linux-x64-musl@4.61.0': + resolution: {integrity: sha512-mvFtE4A/t/7hRJ7X8Ozmu8FsIkAUat2nzl12pgU337BRmq87AQUJztwHz2Zv5/tjo9/C95E66CK03SI/ToEDJw==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.62.0': - resolution: {integrity: sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==} + '@rollup/rollup-openbsd-x64@4.61.0': + resolution: {integrity: sha512-z9b9+aTxvt8n2rNltMPvyaUfB8NJ+CVyOrGK/MdIKHx7B+lXmZpm/XbRsU7Rpf3fRqJ2uS6mBJiJveCtq8LHDg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.62.0': - resolution: {integrity: sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==} + '@rollup/rollup-openharmony-arm64@4.61.0': + resolution: {integrity: sha512-jXaXFqKMehsOc+g8R6oo33RRC6w07G9jDBxAE5eAKX7mOcCbZloYIPNhfG9Wl+P9O9IWHFO4OJgPi1Ml2qkt7w==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.62.0': - resolution: {integrity: sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==} + '@rollup/rollup-win32-arm64-msvc@4.61.0': + resolution: {integrity: sha512-OXNWVFocS2IA4+QplhTZZ2a+8hPZR7T8KuozsNmJKK8y7cp83StHvGksfHzPG3wczWTczyWHVQuqeiTUbjiyBg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.62.0': - resolution: {integrity: sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==} + '@rollup/rollup-win32-ia32-msvc@4.61.0': + resolution: {integrity: sha512-AlAbNtBO637LxSldqV43z0FfXoGfl2TW1DgAg/bs7aQswFbDewz2SJm3BUhiGfbOVtW571xbc9p+REdxhyN/Eg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.62.0': - resolution: {integrity: sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==} + '@rollup/rollup-win32-x64-gnu@4.61.0': + resolution: {integrity: sha512-QRSrQXyJ1M4tjNXdR0/G/IgV6lzfQQJYBjlWIEYkY2Xs86DRl/iEpQ4blMDjJxSl7n19eDKKXMg0AmuBVYy8pQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.62.0': - resolution: {integrity: sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==} + '@rollup/rollup-win32-x64-msvc@4.61.0': + resolution: {integrity: sha512-tkuFxhvKO/HlGd0VsINF6vHSYH8AF8W0TcNxKDK6JZmrehngFj78pToc8iemtnvwilDjs2G/qSzYFhe9U8q+fw==} cpu: [x64] os: [win32] @@ -2343,6 +2399,9 @@ packages: '@tokenizer/token@0.3.0': resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -2580,6 +2639,10 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/types@8.60.1': + resolution: {integrity: sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.61.1': resolution: {integrity: sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2676,6 +2739,11 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + acorn@8.17.0: resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} @@ -2727,9 +2795,6 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - anynum@1.0.0: - resolution: {integrity: sha512-xjR9/zBVnUOP6ztMIIgShjsxui80nQUQH+5xJnvrYLs+90bF25/KJqaAi8mk+B4RDtX1Nspi6fmp4YTEts8SfA==} - arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -2830,8 +2895,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axe-core@4.12.1: - resolution: {integrity: sha512-s7iGf5GaVMxEG0ENN9x+xTr7GFZCb1ZP/1uATUpCEK2X78nDB3RwbtFCo9pGAf9ru+VwoQ464DkaLEeRM08wJA==} + axe-core@4.12.0: + resolution: {integrity: sha512-FTavr/7Ba0IptwGOPxnQvdyW2tAsdLBMTBXz7rKH6xJ2skpyxpBxyHkDdBs4lf69yRqYpkqCdfhnwS8YULGOmg==} engines: {node: '>=4'} axobject-query@4.1.0: @@ -2855,8 +2920,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.10.37: - resolution: {integrity: sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==} + baseline-browser-mapping@2.10.33: + resolution: {integrity: sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==} engines: {node: '>=6.0.0'} hasBin: true @@ -2923,8 +2988,8 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - caniuse-lite@1.0.30001799: - resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} @@ -3391,8 +3456,8 @@ packages: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} - dompurify@3.4.10: - resolution: {integrity: sha512-0xzNv0e7oYC6yyuOGZIABPM4qtg3QxLFniDNPP4ZP90wR8Yq3zgwpRbrNiT4N3IKqDbbYFEJLV+JWEs19aZ//w==} + dompurify@3.4.8: + resolution: {integrity: sha512-yb1cEmaOum7wFvOCSQxyfgVlv5D47Rc30iZWoMpbDIWTnJ6grDDQyu2KFJzB2k7u0pMuJcQ1zphH//fFnw2tjQ==} domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} @@ -3468,8 +3533,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.3.3: - resolution: {integrity: sha512-0PuBxFi+4uPanB97iDxCLWuHeYud2FALrw5HFZGtAF38UpJDbDC8frwp2cnDyae692CQ0dou60UwWfhgsa4U/g==} + es-iterator-helpers@1.3.2: + resolution: {integrity: sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==} engines: {node: '>= 0.4'} es-module-lexer@2.1.0: @@ -3491,8 +3556,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.47.1: - resolution: {integrity: sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q==} + es-toolkit@1.47.0: + resolution: {integrity: sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==} esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -3635,8 +3700,8 @@ packages: engines: {node: '>=18'} hasBin: true - esbuild@0.28.1: - resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + esbuild@0.28.0: + resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} engines: {node: '>=18'} hasBin: true @@ -3812,8 +3877,8 @@ packages: fast-xml-builder@1.2.0: resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} - fast-xml-parser@5.9.0: - resolution: {integrity: sha512-duBuXbyIhEeNO4GjFuVqr0nF047oNwr18aum+zJyqo0MUG/n7Afgs3Qv3D6VN3ONedUKxiuFlPiMGIa0Z11chA==} + fast-xml-parser@5.8.0: + resolution: {integrity: sha512-6bIM7fsJxeo3uXv7OncQYsBAMPJ7V16Slahl/6M98C/i2q+vB1+4a0MtrvYwDFEUrwDSbAmeLDRXsOBwrL7yAg==} hasBin: true fastq@1.20.1: @@ -3894,8 +3959,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.2.0: - resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} functions-have-names@1.2.3: @@ -4260,10 +4325,6 @@ packages: engines: {node: '>=20'} hasBin: true - is-document.all@1.0.0: - resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} - engines: {node: '>= 0.4'} - is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -4344,9 +4405,6 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} - is-unsafe@1.0.1: - resolution: {integrity: sha512-CLK2+VdgERgD96EYm5lUQssZYlRg2tkZnbsxZoacmSiRxiFJ4Nk4SzjCl+Ur+v3kXIY9dTIdb3IH22y1mZ56LA==} - is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -5174,8 +5232,8 @@ packages: resolution: {integrity: sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==} engines: {node: '>=4'} - postcss-selector-parser@7.1.4: - resolution: {integrity: sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==} + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} postcss@8.5.15: @@ -5519,8 +5577,8 @@ packages: robust-predicates@3.0.3: resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} - rollup@4.62.0: - resolution: {integrity: sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==} + rollup@4.61.0: + resolution: {integrity: sha512-T9mWdbWfQtp0B5lv/HX+wrhYsmXRlcWnXXmJbXqKJhlRaoS6KMhq0gpyzW4UJfclcxrEdLnTgjT2NjruLONu0g==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -5560,6 +5618,9 @@ packages: sass-formatter@0.7.9: resolution: {integrity: sha512-CWZ8XiSim+fJVG0cFLStwDvft1VI7uvXdCNJYXhDvowiv+DsbD1nXLiQ4zrE5UBvj5DWZJ93cwN0NX5PMsr1Pw==} + satteri@0.8.1: + resolution: {integrity: sha512-B3dPc3RsWN+CIrwJHk6KnPQjdN7cg9mnSgfs7AUEXITlIYRnSMleOZQPgpmm759pGZ/vpnsXciNfJKXKME2rrg==} + sax@1.6.0: resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} @@ -5582,6 +5643,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.8.1: + resolution: {integrity: sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==} + engines: {node: '>=10'} + hasBin: true + semver@7.8.4: resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} engines: {node: '>=10'} @@ -5631,8 +5697,8 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.1.1: - resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} engines: {node: '>= 0.4'} siginfo@2.0.0: @@ -5774,12 +5840,12 @@ packages: string.prototype.repeat@1.0.0: resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - string.prototype.trim@1.2.11: - resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} - string.prototype.trimend@1.0.10: - resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} engines: {node: '>= 0.4'} string.prototype.trimstart@1.0.8: @@ -5815,8 +5881,8 @@ packages: strip-markdown@6.0.0: resolution: {integrity: sha512-mSa8FtUoX3ExJYDkjPUTC14xaBAn4Ik5GPQD45G5E2egAmeV3kHgVSTfIoSDggbF6Pk9stahVgqsLCNExv6jHw==} - strnum@2.4.0: - resolution: {integrity: sha512-sHrVyWWdq28RbhjuJdZsA1SnGRJV6NiXbk6AXBxDOsgAcA+lmpUZCYjOdLBxkXMwis6RRe7dlZt4VlIWFVzkmg==} + strnum@2.3.0: + resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==} strtok3@10.3.5: resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} @@ -5955,8 +6021,8 @@ packages: resolution: {integrity: sha512-TU6coIZm6RxGgAjroRKmi6aCQ7Pq7cT+1I+bTKBepD6joOuWqUCOptVlz+eurqTnatnQOimlR8XB5sQZ6ULwbw==} engines: {node: '>=18.0.0'} - ts-dedent@2.3.0: - resolution: {integrity: sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==} + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} engines: {node: '>=6.10'} tsconfck@3.1.6: @@ -6059,8 +6125,8 @@ packages: undici-types@7.24.6: resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - undici@6.27.0: - resolution: {integrity: sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==} + undici@6.26.0: + resolution: {integrity: sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==} engines: {node: '>=18.17'} undici@7.24.8: @@ -6485,8 +6551,8 @@ packages: resolution: {integrity: sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==} engines: {node: '>=4'} - which-typed-array@1.1.22: - resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} + which-typed-array@1.1.21: + resolution: {integrity: sha512-zbRA8cVm6io/d5W8uIe2hblzN76/Wm3v/yiythQvr+dpBWeqhPSWIDNj4zOyHi4zKbMK6DN34Xsr9jPHJERAEw==} engines: {node: '>= 0.4'} which@2.0.2: @@ -6657,17 +6723,17 @@ snapshots: '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) '@octokit/request': 10.0.10 '@octokit/request-error': 7.1.0 - undici: 6.27.0 + undici: 6.26.0 '@actions/http-client@3.0.2': dependencies: tunnel: 0.0.6 - undici: 6.27.0 + undici: 6.26.0 '@actions/http-client@4.0.1': dependencies: tunnel: 0.0.6 - undici: 6.27.0 + undici: 6.26.0 '@actions/io@3.0.2': {} @@ -6897,13 +6963,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/mdx@6.0.3(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))': + '@astrojs/markdown-satteri@0.3.0': + dependencies: + '@astrojs/internal-helpers': 0.10.0 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + satteri: 0.8.1 + + '@astrojs/mdx@6.0.3(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))': dependencies: '@astrojs/internal-helpers': 0.10.0 '@astrojs/markdown-remark': 7.2.0 '@mdx-js/mdx': 3.1.1 acorn: 8.17.0 - astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0) + astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0) es-module-lexer: 2.1.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -6914,6 +6987,8 @@ snapshots: source-map: 0.7.6 unist-util-visit: 5.1.0 vfile: 6.0.3 + optionalDependencies: + '@astrojs/markdown-satteri': 0.3.0 transitivePeerDependencies: - supports-color @@ -6948,7 +7023,7 @@ snapshots: '@astrojs/rss@4.0.18': dependencies: - fast-xml-parser: 5.9.0 + fast-xml-parser: 5.8.0 piccolore: 0.1.3 zod: 4.4.3 @@ -6958,9 +7033,9 @@ snapshots: stream-replace-string: 2.0.0 zod: 4.4.3 - '@astrojs/starlight-docsearch@0.7.0(@algolia/client-search@5.54.1)(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)': + '@astrojs/starlight-docsearch@0.7.0(@algolia/client-search@5.54.1)(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3)': dependencies: - '@astrojs/starlight': 0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + '@astrojs/starlight': 0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) '@docsearch/css': 3.9.0 '@docsearch/js': 3.9.0(@algolia/client-search@5.54.1)(@types/react@19.0.7)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(search-insights@2.17.3) transitivePeerDependencies: @@ -6970,22 +7045,22 @@ snapshots: - react-dom - search-insights - '@astrojs/starlight-tailwind@5.0.0(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(tailwindcss@4.1.4)': + '@astrojs/starlight-tailwind@5.0.0(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(tailwindcss@4.1.4)': dependencies: - '@astrojs/starlight': 0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + '@astrojs/starlight': 0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) tailwindcss: 4.1.4 - '@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)': + '@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)': dependencies: '@astrojs/markdown-remark': 7.2.0 - '@astrojs/mdx': 6.0.3(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)) + '@astrojs/mdx': 6.0.3(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)) '@astrojs/sitemap': 3.7.3 '@pagefind/default-ui': 1.5.2 '@types/hast': 3.0.4 '@types/js-yaml': 4.0.9 '@types/mdast': 4.0.4 - astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0) - astro-expressive-code: 0.43.1(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)) + astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0) + astro-expressive-code: 0.43.1(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)) bcp-47: 2.1.0 hast-util-from-html: 2.0.3 hast-util-select: 6.0.4 @@ -7006,6 +7081,8 @@ snapshots: unified: 11.0.5 unist-util-visit: 5.1.0 vfile: 6.0.3 + optionalDependencies: + '@astrojs/markdown-satteri': 0.3.0 transitivePeerDependencies: - supports-color - typescript @@ -7164,6 +7241,25 @@ snapshots: '@braintree/sanitize-url@7.1.2': {} + '@bruits/satteri-darwin-arm64@0.8.1': + optional: true + + '@bruits/satteri-darwin-x64@0.8.1': + optional: true + + '@bruits/satteri-linux-x64-gnu@0.8.1': + optional: true + + '@bruits/satteri-wasm32-wasi@0.8.1': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) + optional: true + + '@bruits/satteri-win32-x64-msvc@0.8.1': + optional: true + '@capsizecss/unpack@4.0.1': dependencies: fontkitten: 1.0.3 @@ -7278,11 +7374,32 @@ snapshots: '@emmetio/stream-reader@2.2.0': {} + '@emnapi/core@1.9.1': + dependencies: + '@emnapi/wasi-threads': 1.2.0 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emnapi/runtime@1.11.1': dependencies: tslib: 2.8.1 optional: true + '@emnapi/runtime@1.9.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.0': + dependencies: + tslib: 2.8.1 + optional: true + '@emotion/babel-plugin@11.13.5': dependencies: '@babel/helper-module-imports': 7.29.7 @@ -7353,7 +7470,7 @@ snapshots: '@esbuild/aix-ppc64@0.27.7': optional: true - '@esbuild/aix-ppc64@0.28.1': + '@esbuild/aix-ppc64@0.28.0': optional: true '@esbuild/android-arm64@0.27.3': @@ -7362,7 +7479,7 @@ snapshots: '@esbuild/android-arm64@0.27.7': optional: true - '@esbuild/android-arm64@0.28.1': + '@esbuild/android-arm64@0.28.0': optional: true '@esbuild/android-arm@0.15.18': @@ -7374,7 +7491,7 @@ snapshots: '@esbuild/android-arm@0.27.7': optional: true - '@esbuild/android-arm@0.28.1': + '@esbuild/android-arm@0.28.0': optional: true '@esbuild/android-x64@0.27.3': @@ -7383,7 +7500,7 @@ snapshots: '@esbuild/android-x64@0.27.7': optional: true - '@esbuild/android-x64@0.28.1': + '@esbuild/android-x64@0.28.0': optional: true '@esbuild/darwin-arm64@0.27.3': @@ -7392,7 +7509,7 @@ snapshots: '@esbuild/darwin-arm64@0.27.7': optional: true - '@esbuild/darwin-arm64@0.28.1': + '@esbuild/darwin-arm64@0.28.0': optional: true '@esbuild/darwin-x64@0.27.3': @@ -7401,7 +7518,7 @@ snapshots: '@esbuild/darwin-x64@0.27.7': optional: true - '@esbuild/darwin-x64@0.28.1': + '@esbuild/darwin-x64@0.28.0': optional: true '@esbuild/freebsd-arm64@0.27.3': @@ -7410,7 +7527,7 @@ snapshots: '@esbuild/freebsd-arm64@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.28.1': + '@esbuild/freebsd-arm64@0.28.0': optional: true '@esbuild/freebsd-x64@0.27.3': @@ -7419,7 +7536,7 @@ snapshots: '@esbuild/freebsd-x64@0.27.7': optional: true - '@esbuild/freebsd-x64@0.28.1': + '@esbuild/freebsd-x64@0.28.0': optional: true '@esbuild/linux-arm64@0.27.3': @@ -7428,7 +7545,7 @@ snapshots: '@esbuild/linux-arm64@0.27.7': optional: true - '@esbuild/linux-arm64@0.28.1': + '@esbuild/linux-arm64@0.28.0': optional: true '@esbuild/linux-arm@0.27.3': @@ -7437,7 +7554,7 @@ snapshots: '@esbuild/linux-arm@0.27.7': optional: true - '@esbuild/linux-arm@0.28.1': + '@esbuild/linux-arm@0.28.0': optional: true '@esbuild/linux-ia32@0.27.3': @@ -7446,7 +7563,7 @@ snapshots: '@esbuild/linux-ia32@0.27.7': optional: true - '@esbuild/linux-ia32@0.28.1': + '@esbuild/linux-ia32@0.28.0': optional: true '@esbuild/linux-loong64@0.15.18': @@ -7458,7 +7575,7 @@ snapshots: '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/linux-loong64@0.28.1': + '@esbuild/linux-loong64@0.28.0': optional: true '@esbuild/linux-mips64el@0.27.3': @@ -7467,7 +7584,7 @@ snapshots: '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/linux-mips64el@0.28.1': + '@esbuild/linux-mips64el@0.28.0': optional: true '@esbuild/linux-ppc64@0.27.3': @@ -7476,7 +7593,7 @@ snapshots: '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/linux-ppc64@0.28.1': + '@esbuild/linux-ppc64@0.28.0': optional: true '@esbuild/linux-riscv64@0.27.3': @@ -7485,7 +7602,7 @@ snapshots: '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/linux-riscv64@0.28.1': + '@esbuild/linux-riscv64@0.28.0': optional: true '@esbuild/linux-s390x@0.27.3': @@ -7494,7 +7611,7 @@ snapshots: '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/linux-s390x@0.28.1': + '@esbuild/linux-s390x@0.28.0': optional: true '@esbuild/linux-x64@0.27.3': @@ -7503,7 +7620,7 @@ snapshots: '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/linux-x64@0.28.1': + '@esbuild/linux-x64@0.28.0': optional: true '@esbuild/netbsd-arm64@0.27.3': @@ -7512,7 +7629,7 @@ snapshots: '@esbuild/netbsd-arm64@0.27.7': optional: true - '@esbuild/netbsd-arm64@0.28.1': + '@esbuild/netbsd-arm64@0.28.0': optional: true '@esbuild/netbsd-x64@0.27.3': @@ -7521,7 +7638,7 @@ snapshots: '@esbuild/netbsd-x64@0.27.7': optional: true - '@esbuild/netbsd-x64@0.28.1': + '@esbuild/netbsd-x64@0.28.0': optional: true '@esbuild/openbsd-arm64@0.27.3': @@ -7530,7 +7647,7 @@ snapshots: '@esbuild/openbsd-arm64@0.27.7': optional: true - '@esbuild/openbsd-arm64@0.28.1': + '@esbuild/openbsd-arm64@0.28.0': optional: true '@esbuild/openbsd-x64@0.27.3': @@ -7539,7 +7656,7 @@ snapshots: '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.28.1': + '@esbuild/openbsd-x64@0.28.0': optional: true '@esbuild/openharmony-arm64@0.27.3': @@ -7548,7 +7665,7 @@ snapshots: '@esbuild/openharmony-arm64@0.27.7': optional: true - '@esbuild/openharmony-arm64@0.28.1': + '@esbuild/openharmony-arm64@0.28.0': optional: true '@esbuild/sunos-x64@0.27.3': @@ -7557,7 +7674,7 @@ snapshots: '@esbuild/sunos-x64@0.27.7': optional: true - '@esbuild/sunos-x64@0.28.1': + '@esbuild/sunos-x64@0.28.0': optional: true '@esbuild/win32-arm64@0.27.3': @@ -7566,7 +7683,7 @@ snapshots: '@esbuild/win32-arm64@0.27.7': optional: true - '@esbuild/win32-arm64@0.28.1': + '@esbuild/win32-arm64@0.28.0': optional: true '@esbuild/win32-ia32@0.27.3': @@ -7575,7 +7692,7 @@ snapshots: '@esbuild/win32-ia32@0.27.7': optional: true - '@esbuild/win32-ia32@0.28.1': + '@esbuild/win32-ia32@0.28.0': optional: true '@esbuild/win32-x64@0.27.3': @@ -7584,7 +7701,7 @@ snapshots: '@esbuild/win32-x64@0.27.7': optional: true - '@esbuild/win32-x64@0.28.1': + '@esbuild/win32-x64@0.28.0': optional: true '@eslint-community/eslint-utils@4.9.1(eslint@9.35.0(jiti@2.7.0))': @@ -7913,7 +8030,7 @@ snapshots: '@img/sharp-wasm32@0.34.5': dependencies: - '@emnapi/runtime': 1.11.1 + '@emnapi/runtime': 1.10.0 optional: true '@img/sharp-wasm32@0.35.1': @@ -8042,7 +8159,14 @@ snapshots: nanostores: 1.3.0 react: 19.0.0 - '@nodable/entities@2.2.0': {} + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)': + dependencies: + '@emnapi/core': 1.9.1 + '@emnapi/runtime': 1.9.1 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@nodable/entities@2.1.1': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -8198,87 +8322,87 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.3': {} - '@rollup/pluginutils@5.4.0(rollup@4.62.0)': + '@rollup/pluginutils@5.4.0(rollup@4.61.0)': dependencies: '@types/estree': 1.0.9 estree-walker: 2.0.2 picomatch: 4.0.4 optionalDependencies: - rollup: 4.62.0 + rollup: 4.61.0 - '@rollup/rollup-android-arm-eabi@4.62.0': + '@rollup/rollup-android-arm-eabi@4.61.0': optional: true - '@rollup/rollup-android-arm64@4.62.0': + '@rollup/rollup-android-arm64@4.61.0': optional: true - '@rollup/rollup-darwin-arm64@4.62.0': + '@rollup/rollup-darwin-arm64@4.61.0': optional: true - '@rollup/rollup-darwin-x64@4.62.0': + '@rollup/rollup-darwin-x64@4.61.0': optional: true - '@rollup/rollup-freebsd-arm64@4.62.0': + '@rollup/rollup-freebsd-arm64@4.61.0': optional: true - '@rollup/rollup-freebsd-x64@4.62.0': + '@rollup/rollup-freebsd-x64@4.61.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.62.0': + '@rollup/rollup-linux-arm-gnueabihf@4.61.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.62.0': + '@rollup/rollup-linux-arm-musleabihf@4.61.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.62.0': + '@rollup/rollup-linux-arm64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.62.0': + '@rollup/rollup-linux-arm64-musl@4.61.0': optional: true - '@rollup/rollup-linux-loong64-gnu@4.62.0': + '@rollup/rollup-linux-loong64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-loong64-musl@4.62.0': + '@rollup/rollup-linux-loong64-musl@4.61.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.62.0': + '@rollup/rollup-linux-ppc64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-ppc64-musl@4.62.0': + '@rollup/rollup-linux-ppc64-musl@4.61.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.62.0': + '@rollup/rollup-linux-riscv64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.62.0': + '@rollup/rollup-linux-riscv64-musl@4.61.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.62.0': + '@rollup/rollup-linux-s390x-gnu@4.61.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.62.0': + '@rollup/rollup-linux-x64-gnu@4.61.0': optional: true - '@rollup/rollup-linux-x64-musl@4.62.0': + '@rollup/rollup-linux-x64-musl@4.61.0': optional: true - '@rollup/rollup-openbsd-x64@4.62.0': + '@rollup/rollup-openbsd-x64@4.61.0': optional: true - '@rollup/rollup-openharmony-arm64@4.62.0': + '@rollup/rollup-openharmony-arm64@4.61.0': optional: true - '@rollup/rollup-win32-arm64-msvc@4.62.0': + '@rollup/rollup-win32-arm64-msvc@4.61.0': optional: true - '@rollup/rollup-win32-ia32-msvc@4.62.0': + '@rollup/rollup-win32-ia32-msvc@4.61.0': optional: true - '@rollup/rollup-win32-x64-gnu@4.62.0': + '@rollup/rollup-win32-x64-gnu@4.61.0': optional: true - '@rollup/rollup-win32-x64-msvc@4.62.0': + '@rollup/rollup-win32-x64-msvc@4.61.0': optional: true '@shikijs/core@4.2.0': @@ -8458,6 +8582,11 @@ snapshots: '@tokenizer/token@0.3.0': {} + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -8747,6 +8876,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/types@8.60.1': {} + '@typescript-eslint/types@8.61.1': {} '@typescript-eslint/typescript-estree@8.61.1(typescript@5.9.3)': @@ -8892,10 +9023,16 @@ snapshots: '@yarnpkg/lockfile@1.1.0': {} + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + acorn-jsx@5.3.2(acorn@8.17.0): dependencies: acorn: 8.17.0 + acorn@8.16.0: {} + acorn@8.17.0: {} ajv-draft-04@1.0.0(ajv@8.20.0): @@ -8954,8 +9091,6 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.2 - anynum@1.0.0: {} - arg@5.0.2: {} argparse@1.0.10: @@ -9035,15 +9170,15 @@ snapshots: astring@1.9.0: {} - astro-breadcrumbs@3.4.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)): + astro-breadcrumbs@3.4.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)): dependencies: - astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0) + astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0) astro-eslint-parser@1.4.0: dependencies: '@astrojs/compiler': 3.0.1 '@typescript-eslint/scope-manager': 8.61.1 - '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/types': 8.60.1 astrojs-compiler-sync: 1.1.1(@astrojs/compiler@3.0.1) debug: 4.4.3 entities: 7.0.1 @@ -9056,9 +9191,9 @@ snapshots: transitivePeerDependencies: - supports-color - astro-expressive-code@0.43.1(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)): + astro-expressive-code@0.43.1(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)): dependencies: - astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0) + astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0) rehype-expressive-code: 0.43.1 astro-icon@1.1.5: @@ -9069,9 +9204,9 @@ snapshots: transitivePeerDependencies: - supports-color - astro-skills@0.1.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3): + astro-skills@0.1.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3): dependencies: - astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0) + astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0) gray-matter: 4.0.3 p-limit: 6.2.0 picomatch: 4.0.4 @@ -9079,7 +9214,7 @@ snapshots: tinyglobby: 0.2.17 typescript: 5.9.3 - astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0): + astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0): dependencies: '@astrojs/compiler': 4.0.0 '@astrojs/internal-helpers': 0.10.0 @@ -9088,7 +9223,7 @@ snapshots: '@capsizecss/unpack': 4.0.1 '@clack/prompts': 1.5.1 '@oslojs/encoding': 1.1.0 - '@rollup/pluginutils': 5.4.0(rollup@4.62.0) + '@rollup/pluginutils': 5.4.0(rollup@4.61.0) aria-query: 5.3.2 axobject-query: 4.1.0 ci-info: 4.4.0 @@ -9183,7 +9318,7 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axe-core@4.12.1: {} + axe-core@4.12.0: {} axobject-query@4.1.0: {} @@ -9202,7 +9337,7 @@ snapshots: base64-js@1.5.1: optional: true - baseline-browser-mapping@2.10.37: {} + baseline-browser-mapping@2.10.33: {} bcp-47-match@2.0.3: {} @@ -9240,8 +9375,8 @@ snapshots: browserslist@4.28.2: dependencies: - baseline-browser-mapping: 2.10.37 - caniuse-lite: 1.0.30001799 + baseline-browser-mapping: 2.10.33 + caniuse-lite: 1.0.30001793 electron-to-chromium: 1.5.367 node-releases: 2.0.47 update-browserslist-db: 1.2.3(browserslist@4.28.2) @@ -9279,7 +9414,7 @@ snapshots: callsites@3.1.0: {} - caniuse-lite@1.0.30001799: {} + caniuse-lite@1.0.30001793: {} ccount@2.0.1: {} @@ -9767,7 +9902,7 @@ snapshots: dependencies: domelementtype: 2.3.0 - dompurify@3.4.10: + dompurify@3.4.8: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -9845,7 +9980,7 @@ snapshots: es-object-atoms: 1.1.2 es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 - function.prototype.name: 1.2.0 + function.prototype.name: 1.1.8 get-intrinsic: 1.3.0 get-proto: 1.0.1 get-symbol-description: 1.1.0 @@ -9877,21 +10012,21 @@ snapshots: safe-regex-test: 1.1.0 set-proto: 1.0.0 stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.11 - string.prototype.trimend: 1.0.10 + string.prototype.trim: 1.2.10 + string.prototype.trimend: 1.0.9 string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.3 typed-array-byte-length: 1.0.3 typed-array-byte-offset: 1.0.4 typed-array-length: 1.0.8 unbox-primitive: 1.1.0 - which-typed-array: 1.1.22 + which-typed-array: 1.1.21 es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-iterator-helpers@1.3.3: + es-iterator-helpers@1.3.2: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 @@ -9933,7 +10068,7 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.47.1: {} + es-toolkit@1.47.0: {} esast-util-from-estree@2.0.0: dependencies: @@ -10092,34 +10227,34 @@ snapshots: '@esbuild/win32-ia32': 0.27.7 '@esbuild/win32-x64': 0.27.7 - esbuild@0.28.1: + esbuild@0.28.0: optionalDependencies: - '@esbuild/aix-ppc64': 0.28.1 - '@esbuild/android-arm': 0.28.1 - '@esbuild/android-arm64': 0.28.1 - '@esbuild/android-x64': 0.28.1 - '@esbuild/darwin-arm64': 0.28.1 - '@esbuild/darwin-x64': 0.28.1 - '@esbuild/freebsd-arm64': 0.28.1 - '@esbuild/freebsd-x64': 0.28.1 - '@esbuild/linux-arm': 0.28.1 - '@esbuild/linux-arm64': 0.28.1 - '@esbuild/linux-ia32': 0.28.1 - '@esbuild/linux-loong64': 0.28.1 - '@esbuild/linux-mips64el': 0.28.1 - '@esbuild/linux-ppc64': 0.28.1 - '@esbuild/linux-riscv64': 0.28.1 - '@esbuild/linux-s390x': 0.28.1 - '@esbuild/linux-x64': 0.28.1 - '@esbuild/netbsd-arm64': 0.28.1 - '@esbuild/netbsd-x64': 0.28.1 - '@esbuild/openbsd-arm64': 0.28.1 - '@esbuild/openbsd-x64': 0.28.1 - '@esbuild/openharmony-arm64': 0.28.1 - '@esbuild/sunos-x64': 0.28.1 - '@esbuild/win32-arm64': 0.28.1 - '@esbuild/win32-ia32': 0.28.1 - '@esbuild/win32-x64': 0.28.1 + '@esbuild/aix-ppc64': 0.28.0 + '@esbuild/android-arm': 0.28.0 + '@esbuild/android-arm64': 0.28.0 + '@esbuild/android-x64': 0.28.0 + '@esbuild/darwin-arm64': 0.28.0 + '@esbuild/darwin-x64': 0.28.0 + '@esbuild/freebsd-arm64': 0.28.0 + '@esbuild/freebsd-x64': 0.28.0 + '@esbuild/linux-arm': 0.28.0 + '@esbuild/linux-arm64': 0.28.0 + '@esbuild/linux-ia32': 0.28.0 + '@esbuild/linux-loong64': 0.28.0 + '@esbuild/linux-mips64el': 0.28.0 + '@esbuild/linux-ppc64': 0.28.0 + '@esbuild/linux-riscv64': 0.28.0 + '@esbuild/linux-s390x': 0.28.0 + '@esbuild/linux-x64': 0.28.0 + '@esbuild/netbsd-arm64': 0.28.0 + '@esbuild/netbsd-x64': 0.28.0 + '@esbuild/openbsd-arm64': 0.28.0 + '@esbuild/openbsd-x64': 0.28.0 + '@esbuild/openharmony-arm64': 0.28.0 + '@esbuild/sunos-x64': 0.28.0 + '@esbuild/win32-arm64': 0.28.0 + '@esbuild/win32-ia32': 0.28.0 + '@esbuild/win32-x64': 0.28.0 escalade@3.2.0: {} @@ -10138,13 +10273,13 @@ snapshots: dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.35.0(jiti@2.7.0)) '@jridgewell/sourcemap-codec': 1.5.5 - '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/types': 8.60.1 astro-eslint-parser: 1.4.0 eslint: 9.35.0(jiti@2.7.0) eslint-compat-utils: 0.6.5(eslint@9.35.0(jiti@2.7.0)) globals: 16.5.0 postcss: 8.5.15 - postcss-selector-parser: 7.1.4 + postcss-selector-parser: 7.1.1 transitivePeerDependencies: - supports-color @@ -10154,7 +10289,7 @@ snapshots: array-includes: 3.1.9 array.prototype.flatmap: 1.3.3 ast-types-flow: 0.0.8 - axe-core: 4.12.1 + axe-core: 4.12.0 axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 @@ -10174,7 +10309,7 @@ snapshots: array.prototype.flatmap: 1.3.3 array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.3.3 + es-iterator-helpers: 1.3.2 eslint: 9.35.0(jiti@2.7.0) estraverse: 5.3.0 hasown: 2.0.4 @@ -10360,13 +10495,12 @@ snapshots: path-expression-matcher: 1.5.0 xml-naming: 0.1.0 - fast-xml-parser@5.9.0: + fast-xml-parser@5.8.0: dependencies: - '@nodable/entities': 2.2.0 + '@nodable/entities': 2.1.1 fast-xml-builder: 1.2.0 - is-unsafe: 1.0.1 path-expression-matcher: 1.5.0 - strnum: 2.4.0 + strnum: 2.3.0 xml-naming: 0.1.0 fastq@1.20.1: @@ -10449,17 +10583,14 @@ snapshots: function-bind@1.1.2: {} - function.prototype.name@1.2.0: + function.prototype.name@1.1.8: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 - es-define-property: 1.0.1 - es-errors: 1.3.0 + define-properties: 1.2.1 functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 hasown: 2.0.4 is-callable: 1.2.7 - is-document.all: 1.0.0 functions-have-names@1.2.3: {} @@ -10875,7 +11006,7 @@ snapshots: dependencies: es-errors: 1.3.0 hasown: 2.0.4 - side-channel: 1.1.1 + side-channel: 1.1.0 internmap@1.0.1: {} @@ -10946,10 +11077,6 @@ snapshots: is-docker@4.0.0: {} - is-document.all@1.0.0: - dependencies: - call-bound: 1.0.4 - is-extendable@0.1.1: {} is-extglob@2.1.1: {} @@ -11021,9 +11148,7 @@ snapshots: is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.22 - - is-unsafe@1.0.1: {} + which-typed-array: 1.1.21 is-weakmap@2.0.2: {} @@ -11122,7 +11247,7 @@ snapshots: just-bash@3.0.1: dependencies: diff: 8.0.4 - fast-xml-parser: 5.9.0 + fast-xml-parser: 5.8.0 file-type: 21.3.4 ini: 6.0.0 minimatch: 10.2.5 @@ -11520,14 +11645,14 @@ snapshots: d3-sankey: 0.12.3 dagre-d3-es: 7.0.14 dayjs: 1.11.21 - dompurify: 3.4.10 - es-toolkit: 1.47.1 + dompurify: 3.4.8 + es-toolkit: 1.47.0 katex: 0.16.47 khroma: 2.1.0 marked: 16.4.2 roughjs: 4.6.6 stylis: 4.4.0 - ts-dedent: 2.3.0 + ts-dedent: 2.2.0 uuid: 14.0.0 micromark-core-commonmark@2.0.3: @@ -11659,8 +11784,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.17.0 - acorn-jsx: 5.3.2(acorn@8.17.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) micromark-extension-mdx-expression: 3.0.1 micromark-extension-mdx-jsx: 3.0.2 micromark-extension-mdx-md: 2.0.0 @@ -12104,7 +12229,7 @@ snapshots: klaw-sync: 6.0.0 minimist: 1.2.8 open: 7.4.2 - semver: 7.8.4 + semver: 7.8.1 slash: 2.0.0 tmp: 0.2.7 yaml: 2.9.0 @@ -12168,7 +12293,7 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@7.1.4: + postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -12613,35 +12738,35 @@ snapshots: robust-predicates@3.0.3: {} - rollup@4.62.0: + rollup@4.61.0: dependencies: '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.62.0 - '@rollup/rollup-android-arm64': 4.62.0 - '@rollup/rollup-darwin-arm64': 4.62.0 - '@rollup/rollup-darwin-x64': 4.62.0 - '@rollup/rollup-freebsd-arm64': 4.62.0 - '@rollup/rollup-freebsd-x64': 4.62.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.62.0 - '@rollup/rollup-linux-arm-musleabihf': 4.62.0 - '@rollup/rollup-linux-arm64-gnu': 4.62.0 - '@rollup/rollup-linux-arm64-musl': 4.62.0 - '@rollup/rollup-linux-loong64-gnu': 4.62.0 - '@rollup/rollup-linux-loong64-musl': 4.62.0 - '@rollup/rollup-linux-ppc64-gnu': 4.62.0 - '@rollup/rollup-linux-ppc64-musl': 4.62.0 - '@rollup/rollup-linux-riscv64-gnu': 4.62.0 - '@rollup/rollup-linux-riscv64-musl': 4.62.0 - '@rollup/rollup-linux-s390x-gnu': 4.62.0 - '@rollup/rollup-linux-x64-gnu': 4.62.0 - '@rollup/rollup-linux-x64-musl': 4.62.0 - '@rollup/rollup-openbsd-x64': 4.62.0 - '@rollup/rollup-openharmony-arm64': 4.62.0 - '@rollup/rollup-win32-arm64-msvc': 4.62.0 - '@rollup/rollup-win32-ia32-msvc': 4.62.0 - '@rollup/rollup-win32-x64-gnu': 4.62.0 - '@rollup/rollup-win32-x64-msvc': 4.62.0 + '@rollup/rollup-android-arm-eabi': 4.61.0 + '@rollup/rollup-android-arm64': 4.61.0 + '@rollup/rollup-darwin-arm64': 4.61.0 + '@rollup/rollup-darwin-x64': 4.61.0 + '@rollup/rollup-freebsd-arm64': 4.61.0 + '@rollup/rollup-freebsd-x64': 4.61.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.61.0 + '@rollup/rollup-linux-arm-musleabihf': 4.61.0 + '@rollup/rollup-linux-arm64-gnu': 4.61.0 + '@rollup/rollup-linux-arm64-musl': 4.61.0 + '@rollup/rollup-linux-loong64-gnu': 4.61.0 + '@rollup/rollup-linux-loong64-musl': 4.61.0 + '@rollup/rollup-linux-ppc64-gnu': 4.61.0 + '@rollup/rollup-linux-ppc64-musl': 4.61.0 + '@rollup/rollup-linux-riscv64-gnu': 4.61.0 + '@rollup/rollup-linux-riscv64-musl': 4.61.0 + '@rollup/rollup-linux-s390x-gnu': 4.61.0 + '@rollup/rollup-linux-x64-gnu': 4.61.0 + '@rollup/rollup-linux-x64-musl': 4.61.0 + '@rollup/rollup-openbsd-x64': 4.61.0 + '@rollup/rollup-openharmony-arm64': 4.61.0 + '@rollup/rollup-win32-arm64-msvc': 4.61.0 + '@rollup/rollup-win32-ia32-msvc': 4.61.0 + '@rollup/rollup-win32-x64-gnu': 4.61.0 + '@rollup/rollup-win32-x64-msvc': 4.61.0 fsevents: 2.3.3 roughjs@4.6.6: @@ -12689,6 +12814,19 @@ snapshots: dependencies: suf-log: 2.5.3 + satteri@0.8.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + optionalDependencies: + '@bruits/satteri-darwin-arm64': 0.8.1 + '@bruits/satteri-darwin-x64': 0.8.1 + '@bruits/satteri-linux-x64-gnu': 0.8.1 + '@bruits/satteri-wasm32-wasi': 0.8.1 + '@bruits/satteri-win32-x64-msvc': 0.8.1 + sax@1.6.0: {} scheduler@0.25.0: {} @@ -12706,6 +12844,8 @@ snapshots: semver@6.3.1: {} + semver@7.8.1: {} + semver@7.8.4: {} set-function-length@1.2.2: @@ -12830,7 +12970,7 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.1.1: + side-channel@1.1.0: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -12895,9 +13035,9 @@ snapshots: stackback@0.0.2: {} - starlight-image-zoom@0.14.2(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)): + starlight-image-zoom@0.14.2(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)): dependencies: - '@astrojs/starlight': 0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + '@astrojs/starlight': 0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) mdast-util-mdx-jsx: 3.2.0 rehype-raw: 7.0.0 unist-util-visit: 5.1.0 @@ -12905,11 +13045,11 @@ snapshots: transitivePeerDependencies: - supports-color - starlight-links-validator@0.24.1(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0)): + starlight-links-validator@0.24.1(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3))(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0)): dependencies: - '@astrojs/starlight': 0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + '@astrojs/starlight': 0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) '@types/picomatch': 4.0.3 - astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0) + astro: 6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0) github-slugger: 2.0.0 hast-util-from-html: 2.0.3 is-absolute-url: 5.0.0 @@ -12922,19 +13062,19 @@ snapshots: transitivePeerDependencies: - supports-color - starlight-package-managers@0.12.0(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)): + starlight-package-managers@0.12.0(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)): dependencies: - '@astrojs/starlight': 0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + '@astrojs/starlight': 0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) - starlight-scroll-to-top@1.0.1(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)): + starlight-scroll-to-top@1.0.1(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)): dependencies: - '@astrojs/starlight': 0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + '@astrojs/starlight': 0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) - starlight-showcases@0.3.2(@astrojs/starlight@0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)): + starlight-showcases@0.3.2(@astrojs/starlight@0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3)): dependencies: '@astro-community/astro-embed-twitter': 0.5.11 '@astro-community/astro-embed-youtube': 0.5.10 - '@astrojs/starlight': 0.40.0(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.62.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) + '@astrojs/starlight': 0.40.0(@astrojs/markdown-satteri@0.3.0)(astro@6.4.7(@types/node@25.9.3)(jiti@2.7.0)(lightningcss@1.32.0)(rollup@4.61.0)(tsx@4.22.4)(yaml@2.9.0))(typescript@5.9.3) std-env@4.1.0: {} @@ -12984,14 +13124,14 @@ snapshots: internal-slot: 1.1.0 regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 - side-channel: 1.1.1 + side-channel: 1.1.0 string.prototype.repeat@1.0.0: dependencies: define-properties: 1.2.1 es-abstract: 1.24.2 - string.prototype.trim@1.2.11: + string.prototype.trim@1.2.10: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 @@ -13000,9 +13140,8 @@ snapshots: es-abstract: 1.24.2 es-object-atoms: 1.1.2 has-property-descriptors: 1.0.2 - safe-regex-test: 1.1.0 - string.prototype.trimend@1.0.10: + string.prototype.trimend@1.0.9: dependencies: call-bind: 1.0.9 call-bound: 1.0.4 @@ -13044,9 +13183,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 - strnum@2.4.0: - dependencies: - anynum: 1.0.0 + strnum@2.3.0: {} strtok3@10.3.5: dependencies: @@ -13190,7 +13327,7 @@ snapshots: dependencies: typescript: 5.9.3 - ts-dedent@2.3.0: {} + ts-dedent@2.2.0: {} tsconfck@3.1.6(typescript@5.9.3): optionalDependencies: @@ -13204,7 +13341,7 @@ snapshots: tsx@4.22.4: dependencies: - esbuild: 0.28.1 + esbuild: 0.28.0 optionalDependencies: fsevents: 2.3.3 @@ -13296,7 +13433,7 @@ snapshots: undici-types@7.24.6: {} - undici@6.27.0: {} + undici@6.26.0: {} undici@7.24.8: {} @@ -13474,7 +13611,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.15 - rollup: 4.62.0 + rollup: 4.61.0 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 25.9.3 @@ -13643,7 +13780,7 @@ snapshots: which-builtin-type@1.2.1: dependencies: call-bound: 1.0.4 - function.prototype.name: 1.2.0 + function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 is-async-function: 2.1.1 is-date-object: 1.1.0 @@ -13654,7 +13791,7 @@ snapshots: isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.22 + which-typed-array: 1.1.21 which-collection@1.0.2: dependencies: @@ -13665,7 +13802,7 @@ snapshots: which-pm-runs@1.1.0: {} - which-typed-array@1.1.22: + which-typed-array@1.1.21: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.9 diff --git a/src/components/AnchorHeading.astro b/src/components/AnchorHeading.astro index b5cc5c42723..198af027e48 100644 --- a/src/components/AnchorHeading.astro +++ b/src/components/AnchorHeading.astro @@ -1,10 +1,9 @@ --- import { z } from "astro/zod"; -import { marked } from "marked"; import { slug as GithubSlug } from "github-slugger"; +import { defineHastPlugin, markdownToHtml } from "satteri"; -import { process } from "~/util/rehype"; -import rehypeAutoLinkHeadings from "~/plugins/rehype/autolink-headings"; +import autolinkHeadings from "~/plugins/satteri/autolink-headings"; type Props = z.infer; @@ -16,14 +15,29 @@ const props = z.object({ const { title, slug, depth } = props.parse(Astro.props); -const slugified = GithubSlug(slug ?? title); - -const tag = `h${depth}` as "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; +/** + * An inline plugin that adds an ID to the header so it can be linked by `autolinkHeadings`. + * The syntax used for the `headingSlugs` plugin can't be used here because satteri does not have a simple way to go from mdx to html. + * This one-off plugin allows us to do the same thing via pure md. + **/ +const setHeadingId = defineHastPlugin({ + name: "set-heading-id", + element: { + filter: ["h1", "h2", "h3", "h4", "h5", "h6"], + visit(node, ctx) { + const id = slug ?? ctx.textContent(node); + if (id) { + ctx.setProperty(node, "id", GithubSlug(id)); + } + }, + }, +}); -const html = await process( - `<${tag} id=${slugified}>${marked.parseInline(title)}`, - [rehypeAutoLinkHeadings], -); +const md = `${"#".repeat(depth)} ${title}`; +const { html } = markdownToHtml(md, { + features: { gfm: true, smartPunctuation: false }, + hastPlugins: [setHeadingId, autolinkHeadings], +}); --- diff --git a/src/components/ListTutorials.astro b/src/components/ListTutorials.astro index 9c044017556..eb85ea8725d 100644 --- a/src/components/ListTutorials.astro +++ b/src/components/ListTutorials.astro @@ -2,9 +2,6 @@ import { getCollection, getEntry, type CollectionEntry } from "astro:content"; import { formatDistance } from "date-fns"; -import { process } from "~/util/rehype"; -import rehypeExternalLinks from "~/plugins/rehype/external-links"; - type DocsEntry = CollectionEntry<"docs">; const tutorials: Array = []; @@ -51,25 +48,15 @@ const timeAgo = (date?: Date) => { { - tutorials.map(async (tutorial) => { - const title = tutorial.data.title; - - const href = `/${tutorial.id}/`; - - const anchor = await process(`${title}`, [ - rehypeExternalLinks, - ]); - - return ( - - - - - {timeAgo(tutorial.data.reviewed)} - {tutorial.data.difficulty} - - ); - }) + tutorials.map((tutorial) => ( + + + {tutorial.data.title} + + {timeAgo(tutorial.data.reviewed)} + {tutorial.data.difficulty} + + )) } diff --git a/src/content/changelog/analytics/2025-10-01-confidence-intervals.mdx b/src/content/changelog/analytics/2025-10-01-confidence-intervals.mdx index e8c0c6621a0..8ddd74f2de5 100644 --- a/src/content/changelog/analytics/2025-10-01-confidence-intervals.mdx +++ b/src/content/changelog/analytics/2025-10-01-confidence-intervals.mdx @@ -3,7 +3,7 @@ title: New Confidence Intervals in GraphQL Analytics API description: Confidence intervals are now supported in the GraphQL Analytics API to show statistical ranges for sampled data results date: 2025-10-01 --- - + The GraphQL Analytics API now supports confidence intervals for `sum` and `count` fields on adaptive (sampled) datasets. Confidence intervals provide a statistical range around sampled results, helping verify accuracy and quantify uncertainty. - **Supported datasets**: Adaptive (sampled) datasets only. diff --git a/src/content/changelog/fundamentals/2025-10-30-member-management-improvements.mdx b/src/content/changelog/fundamentals/2025-10-30-member-management-improvements.mdx index b8e0027220e..4417a481828 100644 --- a/src/content/changelog/fundamentals/2025-10-30-member-management-improvements.mdx +++ b/src/content/changelog/fundamentals/2025-10-30-member-management-improvements.mdx @@ -19,7 +19,7 @@ We overhauled the Invite Members UI to simplify inviting users and assigning per **Refreshed Members Overview Page** - + We've updated the Members Overview Page to clearly display: - Member 2FA status - Which members hold Super Admin privileges diff --git a/src/content/changelog/gateway/2025-07-28-Spam-domain-category-introduced.mdx b/src/content/changelog/gateway/2025-07-28-Spam-domain-category-introduced.mdx index 99deeee7c9c..8fdc8ab2d97 100644 --- a/src/content/changelog/gateway/2025-07-28-Spam-domain-category-introduced.mdx +++ b/src/content/changelog/gateway/2025-07-28-Spam-domain-category-introduced.mdx @@ -3,9 +3,9 @@ title: Scam domain category introduced under Security Threats description: You can now create policies specifically targeting the Scam content date: 2025-07-28 --- - + We have introduced a new Security Threat category called **Scam**. Relevant domains are marked with the Scam category. Scam typically refers to fraudulent websites and schemes designed to trick victims into giving away money or personal information. - + **New category added** diff --git a/src/content/changelog/security-center/2025-07-18-brand-protection-api.mdx b/src/content/changelog/security-center/2025-07-18-brand-protection-api.mdx index 80b92a2e387..3ec7049a73f 100644 --- a/src/content/changelog/security-center/2025-07-18-brand-protection-api.mdx +++ b/src/content/changelog/security-center/2025-07-18-brand-protection-api.mdx @@ -4,9 +4,9 @@ title: New APIs for Brand Protection setup description: You can now use the Brand Protection API endpoints to manage your Brand Protection queries date: 2025-07-18 --- - + The Brand Protection API is now available, allowing users to create new queries and delete existing ones, fetch matches and more! - + What you can do: - **create new string or logo query** - **delete string or logo queries** diff --git a/src/content/changelog/security-center/2026-04-08-threat-events-notification.mdx b/src/content/changelog/security-center/2026-04-08-threat-events-notification.mdx index 14417dfa3c7..14c2ac82414 100644 --- a/src/content/changelog/security-center/2026-04-08-threat-events-notification.mdx +++ b/src/content/changelog/security-center/2026-04-08-threat-events-notification.mdx @@ -3,25 +3,25 @@ title: Real-time alerts and daily digests for Threat Events description: You can now subscribe to automated notifications for your saved views in Threat Events date: 2026-04-08 --- - + You can now automate your threat monitoring by setting up custom alerts in your saved views. Instead of manually checking the dashboard for updates, you can subscribe to notifications that trigger whenever new data matches your specific filter sets, like new activity associated to a particular threat actor or spikes in activity within your industry. - + ### Stay ahead of emerging threats - + By linking your saved views to the Cloudflare Notifications Center, you can ensure the right information reaches your team at the right time. - + - **Immediate Alerts**: receive real-time notifications the moment a critical event is detected that matches your saved criteria. This is essential for high-priority monitoring, such as tracking active campaigns from specific APT groups. - + - **Daily Digests**: opt for a summarized report delivered once a day. This is ideal for maintaining situational awareness of broader trends, like regional activity shifts or industry-wide threat landscapes, without cluttering your inbox. - + ![Threat Events notifications](~/assets/images/changelog/security-center/threat-events-notifications.png) - + ### How to get started - + To set up an alert, go to **Application Security** > **Threat Intelligence** > **Threat Events**. From there: - + 1. Choose your datasets and apply your desired filters and select **Save View** (or select an existing one). 2. Open the **Manage Saved Views** menu. 3. Select **Add Alert** next to your chosen view to configure your notification preferences in the Cloudflare dashboard. - + For more technical details on configuring notifications, refer to the [Threat Events documentation](/security-center/cloudforce-one/). diff --git a/src/content/changelog/waf/2026-05-04-waf-release.mdx b/src/content/changelog/waf/2026-05-04-waf-release.mdx index 1d27b8dbad9..58a075d12fa 100644 --- a/src/content/changelog/waf/2026-05-04-waf-release.mdx +++ b/src/content/changelog/waf/2026-05-04-waf-release.mdx @@ -3,21 +3,21 @@ title: "WAF Release - 2026-05-04" description: Cloudflare WAF managed rulesets 2026-05-04 release date: 2026-05-04 --- - + import { RuleID } from "~/components"; - + This week's release focuses on new detections to expand coverage across command injection, SQL injection, PHP object injection, remote code execution, and XSS attack vectors. - + **Key Findings** - + - Existing rule enhancements have been deployed to improve detection resilience against broad classes of web attacks and strengthen behavioral coverage. - - + + **Continuous Rule Improvements** - + We are continuously refining our managed rules to provide more resilient protection and deeper insights into attack patterns. To ensure an optimal security posture, we recommend consistently monitoring the Security Events dashboard and adjusting rule actions as these enhancements are deployed. - - + + diff --git a/src/content/changelog/workers-ai/2025-10-02-deepgram-flux.mdx b/src/content/changelog/workers-ai/2025-10-02-deepgram-flux.mdx index 41abd7c5924..75dcaf2c7f4 100644 --- a/src/content/changelog/workers-ai/2025-10-02-deepgram-flux.mdx +++ b/src/content/changelog/workers-ai/2025-10-02-deepgram-flux.mdx @@ -31,19 +31,19 @@ export default { }, } satisfies ExportedHandler; ``` - + 2. Deploy your worker ```bash npx wrangler deploy ``` - + 3. Write a client script to connect to your worker and start sending random audio bytes to it ```js const ws = new WebSocket('wss://'); - + ws.onopen = () => { console.log('Connected to WebSocket'); - + // Generate and send random audio bytes // You can replace this part with a function // that reads from your mic or other audio source @@ -51,21 +51,21 @@ ws.onopen = () => { ws.send(audioData); console.log('Audio data sent'); }; - + ws.onmessage = (event) => { // Transcription will be received here // Add your custom logic to parse the data console.log('Received:', event.data); }; - + ws.onerror = (error) => { console.error('WebSocket error:', error); }; - + ws.onclose = () => { console.log('WebSocket closed'); }; - + // Generate random audio data (1 second of noise at 44.1kHz, mono) function generateRandomAudio() { const sampleRate = 44100; @@ -73,11 +73,11 @@ function generateRandomAudio() { const numSamples = sampleRate * duration; const buffer = new ArrayBuffer(numSamples * 2); const view = new Int16Array(buffer); - + for (let i = 0; i < numSamples; i++) { view[i] = Math.floor(Math.random() * 65536 - 32768); } - + return buffer; } ``` \ No newline at end of file diff --git a/src/content/changelog/workers-ai/2025-11-25-flux-2-dev-workers-ai.mdx b/src/content/changelog/workers-ai/2025-11-25-flux-2-dev-workers-ai.mdx index dc6814a67cd..744447f0b54 100644 --- a/src/content/changelog/workers-ai/2025-11-25-flux-2-dev-workers-ai.mdx +++ b/src/content/changelog/workers-ai/2025-11-25-flux-2-dev-workers-ai.mdx @@ -106,20 +106,20 @@ Through Workers AI Binding: async function streamToBlob(stream: ReadableStream, contentType: string): Promise { const reader = stream.getReader(); const chunks = []; - + while (true) { const { done, value } = await reader.read(); if (done) break; chunks.push(value); } - + return new Blob(chunks, { type: contentType }); } const image0 = await fetch("http://image-url"); const image1 = await fetch("http://image-url"); const form = new FormData(); - + const image_blob0 = await streamToBlob(image0.body, "image/png"); const image_blob1 = await streamToBlob(image1.body, "image/png"); form.append('input_image_0', image_blob0) @@ -134,7 +134,7 @@ const formRequest = new Request('http://dummy', { }); const formStream = formRequest.body; const formContentType = formRequest.headers.get('content-type') || 'multipart/form-data'; - + const resp = await env.AI.run("@cf/black-forest-labs/flux-2-dev", { multipart: { body: form, diff --git a/src/content/changelog/workers/2025-08-15-static-assets-redirect-url.mdx b/src/content/changelog/workers/2025-08-15-static-assets-redirect-url.mdx index 26a69c93645..bb88eaba2e7 100644 --- a/src/content/changelog/workers/2025-08-15-static-assets-redirect-url.mdx +++ b/src/content/changelog/workers/2025-08-15-static-assets-redirect-url.mdx @@ -3,7 +3,7 @@ title: 'Workers Static Assets: Corrected handling of double slashes in redirect description: Corrected handling of double slashes in redirect rule paths date: 2025-08-15 --- - + [Static Assets](/workers/static-assets/): Fixed a bug in how [redirect rules](https://developers.cloudflare.com/workers/static-assets/redirects/) defined in your Worker's `_redirects` file are processed. If you're serving Static Assets with a `_redirects` file containing a rule like `/ja/* /:splat`, paths with double slashes were previously misinterpreted as external URLs. For example, visiting `/ja//example.com` would incorrectly redirect to `https://example.com` instead of `/example.com` on your domain. This has been fixed and double slashes now correctly resolve as local paths. Note: [Cloudflare Pages](/pages/) was not affected by this issue. diff --git a/src/content/changelog/workers/2025-09-19-ratelimit-workers-ga.mdx b/src/content/changelog/workers/2025-09-19-ratelimit-workers-ga.mdx index f4d8ebd421f..02bbc08abd7 100644 --- a/src/content/changelog/workers/2025-09-19-ratelimit-workers-ga.mdx +++ b/src/content/changelog/workers/2025-09-19-ratelimit-workers-ga.mdx @@ -5,7 +5,7 @@ products: - workers date: 2025-09-19 --- - + [Rate Limiting within Cloudflare Workers](/workers/runtime-apis/bindings/rate-limit/) is now Generally Available (GA). The `ratelimit` binding is now stable and recommended for all production workloads. Existing deployments using the unsafe binding will continue to function to allow for a smooth transition. diff --git a/src/content/docs/api-shield/reference/terraform.mdx b/src/content/docs/api-shield/reference/terraform.mdx index 823b0b64274..ef295c6661b 100644 --- a/src/content/docs/api-shield/reference/terraform.mdx +++ b/src/content/docs/api-shield/reference/terraform.mdx @@ -62,7 +62,7 @@ resource "cloudflare_api_shield_operation" "get_image" { host = "example.com" endpoint = "/api/images/{var1}" } - + resource "cloudflare_api_shield_operation" "post_image" { zone_id = var.zone_id method = "POST" @@ -90,13 +90,13 @@ resource "cloudflare_schema_validation_schemas" "example_schema" { source = file("./schemas/example-schema.yaml") validation_enabled = true } - + # Block all requests that violate schema by default resource "cloudflare_schema_validation_settings" "zone_level_settings" { zone_id = var.zone_id validation_default_mitigation_action = "block" } - + # For endpoint post_image - only log requests that violate schema resource "cloudflare_schema_validation_operation_settings" "post_image_log_only" { zone_id = var.zone_id diff --git a/src/content/docs/cloudflare-one/email-security/settings/detection-settings/allow-policies.mdx b/src/content/docs/cloudflare-one/email-security/settings/detection-settings/allow-policies.mdx index d12d8110a67..e0ef76a9620 100644 --- a/src/content/docs/cloudflare-one/email-security/settings/detection-settings/allow-policies.mdx +++ b/src/content/docs/cloudflare-one/email-security/settings/detection-settings/allow-policies.mdx @@ -75,7 +75,7 @@ Below you can find a list of known services you can add when configuring an Acce ```.*@docusign\.net``` - Twitter - Mentions/Retweets - + ```notify@twitter.com``` - GitHub (mentions and notifications) diff --git a/src/content/docs/d1/tutorials/d1-and-prisma-orm.mdx b/src/content/docs/d1/tutorials/d1-and-prisma-orm.mdx index 3ae7982d8bf..64bb7a1593d 100644 --- a/src/content/docs/d1/tutorials/d1-and-prisma-orm.mdx +++ b/src/content/docs/d1/tutorials/d1-and-prisma-orm.mdx @@ -230,7 +230,7 @@ npx prisma migrate diff --from-empty --to-schema-datamodel ./prisma/schema.prism - + This stores a SQL statement to create a new `User` table in your migration file from before, here is what it looks like: 1. In the Cloudflare dashboard, go to the **L3/4 DDoS protection** page. - + 2. Go to **Advanced Protection**. 3. Under **General settings** > **Allowlist**, select **Edit**. diff --git a/src/content/docs/ddos-protection/advanced-ddos-systems/how-to/add-prefix.mdx b/src/content/docs/ddos-protection/advanced-ddos-systems/how-to/add-prefix.mdx index 7906194f1a6..4d23aab8b71 100644 --- a/src/content/docs/ddos-protection/advanced-ddos-systems/how-to/add-prefix.mdx +++ b/src/content/docs/ddos-protection/advanced-ddos-systems/how-to/add-prefix.mdx @@ -17,7 +17,7 @@ To add a [prefix](/ddos-protection/advanced-ddos-systems/concepts/#prefixes) to 1. In the Cloudflare dashboard, go to the **L3/4 DDoS protection** page. - + 2. Go to **Advanced Protection**. 3. Under **General settings** > **Prefixes**, select **Edit**. diff --git a/src/content/docs/ddos-protection/advanced-ddos-systems/how-to/create-filter.mdx b/src/content/docs/ddos-protection/advanced-ddos-systems/how-to/create-filter.mdx index d71722bdfc1..bfad2d36d7b 100644 --- a/src/content/docs/ddos-protection/advanced-ddos-systems/how-to/create-filter.mdx +++ b/src/content/docs/ddos-protection/advanced-ddos-systems/how-to/create-filter.mdx @@ -27,7 +27,7 @@ To create a [filter](/ddos-protection/advanced-ddos-systems/concepts/#filter) fo 1. In the Cloudflare dashboard, go to the **L3/4 DDoS protection** page. - + 2. Go to **Advanced Protection** > **Advanced TCP Protection**. 3. Under the system component for which you are creating the filter (**SYN Flood Protection** or **Out-of-state TCP Protection**), select **Create** next to the type of filter you want to create: diff --git a/src/content/docs/ddos-protection/advanced-ddos-systems/overview/index.mdx b/src/content/docs/ddos-protection/advanced-ddos-systems/overview/index.mdx index 495f1aa4c75..f9fae3ab34b 100644 --- a/src/content/docs/ddos-protection/advanced-ddos-systems/overview/index.mdx +++ b/src/content/docs/ddos-protection/advanced-ddos-systems/overview/index.mdx @@ -120,7 +120,7 @@ Enable the Advanced DDoS system and begin routing traffic through it. 1. In the Cloudflare dashboard, go to the **L3/4 DDoS protection** page. - + 2. Go to **Advanced Protection** > **General settings**. 3. Under **General settings**, toggle the feature status **On**. diff --git a/src/content/docs/learning-paths/dns-best-practices/concepts/phase-4.mdx b/src/content/docs/learning-paths/dns-best-practices/concepts/phase-4.mdx index e1f0d1f96eb..73bbfa09bd0 100644 --- a/src/content/docs/learning-paths/dns-best-practices/concepts/phase-4.mdx +++ b/src/content/docs/learning-paths/dns-best-practices/concepts/phase-4.mdx @@ -28,7 +28,7 @@ Enable DNSSEC only after you are confident that DNS is resolving correctly throu 2. Select **Enable DNSSEC**. Cloudflare will sign your zone and generate `DNSKEY` and `DS` record details. - + **Action at registrar:** 1. Log in to your domain registrar. 2. Navigate to the DNSSEC management section for your domain. diff --git a/src/content/docs/log-explorer/index.mdx b/src/content/docs/log-explorer/index.mdx index 89e85b9513f..67067dfb8c7 100644 --- a/src/content/docs/log-explorer/index.mdx +++ b/src/content/docs/log-explorer/index.mdx @@ -28,7 +28,7 @@ Contract customers can choose to store their logs in Log Explorer for up to two ## Permissions Access to Log Explorer features is controlled through specific permissions. Each permission grants users the ability to perform certain actions, such as querying logs, managing datasets, or creating dashboards. - + | Feature | Required Permission | Description | |----------|--------------------|--------------| | **Manage datasets** | `Logs Edit` | Add, enable, or disable datasets. | diff --git a/src/content/docs/logs/logpush/logpush-job/enable-destinations/r2.mdx b/src/content/docs/logs/logpush/logpush-job/enable-destinations/r2.mdx index 3db5d9e222d..456e7b75f34 100644 --- a/src/content/docs/logs/logpush/logpush-job/enable-destinations/r2.mdx +++ b/src/content/docs/logs/logpush/logpush-job/enable-destinations/r2.mdx @@ -163,7 +163,7 @@ Once your logs are stored in R2, you can download them using various methods: ### Dashboard 1. In the Cloudflare dashboard, go to the **R2** page. - + 2. Select your bucket. diff --git a/src/content/docs/logs/logpush/logpush-job/filters.mdx b/src/content/docs/logs/logpush/logpush-job/filters.mdx index e3d0dec5946..589e7d3c587 100644 --- a/src/content/docs/logs/logpush/logpush-job/filters.mdx +++ b/src/content/docs/logs/logpush/logpush-job/filters.mdx @@ -100,9 +100,9 @@ Here is an example request using cURL via API: To set filters through the dashboard: 1. In the Cloudflare dashboard, go to the **Logpush** page at the account or or domain (also known as zone) level. - + For account: - + For domain (also known as zone): diff --git a/src/content/docs/logs/reference/change-notices/2023-02-01-security-fields-updates.mdx b/src/content/docs/logs/reference/change-notices/2023-02-01-security-fields-updates.mdx index 090c84dab4f..6c0245bb0a9 100644 --- a/src/content/docs/logs/reference/change-notices/2023-02-01-security-fields-updates.mdx +++ b/src/content/docs/logs/reference/change-notices/2023-02-01-security-fields-updates.mdx @@ -143,7 +143,7 @@ After updating Logpush jobs, you may need to update external filters or reports ### Update Logpush job in the dashboard 1. In the Cloudflare dashboard, go to the **Logpush** page. - + 2. Select **Edit** next to the Logpush job you wish to edit. diff --git a/src/content/docs/speed/observatory/rum-beacon.mdx b/src/content/docs/speed/observatory/rum-beacon.mdx index 66c0e803585..5718f76caee 100644 --- a/src/content/docs/speed/observatory/rum-beacon.mdx +++ b/src/content/docs/speed/observatory/rum-beacon.mdx @@ -8,7 +8,7 @@ tags: - Privacy sidebar: order: 4 - + --- The RUM beacon is a JavaScript snippet that runs when a Cloudflare customer enables RUM through [Web Analytics](/web-analytics/) or [Observatory](/speed/observatory/). This script runs in users' browsers when they visit the customer's site, and its purpose is to collect performance-related data, for example, page load time, and send it to Cloudflare's systems for processing. This [data](/web-analytics/data-metrics/) is then presented to the customer, providing valuable insights into the website's performance and usage. diff --git a/src/content/docs/waiting-room/how-to/control-user-session.mdx b/src/content/docs/waiting-room/how-to/control-user-session.mdx index a8981dcd210..8dd9ad8c201 100644 --- a/src/content/docs/waiting-room/how-to/control-user-session.mdx +++ b/src/content/docs/waiting-room/how-to/control-user-session.mdx @@ -26,7 +26,7 @@ To terminate a user's session when they perform a specific action, you can send To enable this feature in the Cloudflare Dashboard, check the box next to Allow session termination via origin commands from the dashboard. To enable this feature through the [Cloudflare API](/api/resources/waiting_rooms/methods/update/), update the `enabled_origin_commands` property to include the value `”revoke”` in the list of enabled origin commands. - + Then, to return a revocation origin command and revoke the user's session associated with the current request, add the `Cf-Waiting-Room-Command: revoke` HTTP header to the response from your origin. To get the number of sessions revoked, you can query `sessionsRevoked` metrics from your [Waiting Room analytics](/waiting-room/waiting-room-analytics/#graphql-analytics) data via GraphQL API. diff --git a/src/content/partials/logs/enable-logpush-job.mdx b/src/content/partials/logs/enable-logpush-job.mdx index 9c86c3c83fa..d8997e68fe6 100644 --- a/src/content/partials/logs/enable-logpush-job.mdx +++ b/src/content/partials/logs/enable-logpush-job.mdx @@ -6,9 +6,9 @@ import { DashButton } from "~/components"; 1. In the Cloudflare dashboard, go to the **Logpush** page at the account or or domain (also known as zone) level. - + For account: - + For domain (also known as zone): 2. Depending on your choice, you have access to [account-scoped datasets](/logs/logpush/logpush-job/datasets/account/) and [zone-scoped datasets](/logs/logpush/logpush-job/datasets/zone/), respectively. diff --git a/src/plugins/rehype/external-links.ts b/src/plugins/rehype/external-links.ts index 8c7d1919633..3d213a29a89 100644 --- a/src/plugins/rehype/external-links.ts +++ b/src/plugins/rehype/external-links.ts @@ -1,14 +1,14 @@ import rehypeExternalLinks, { type Options } from "rehype-external-links"; import type { Element } from "hast"; +import { externalLinkArrow } from "../shared"; + function hasImgChild(node: Element): boolean { return node.children.some( (child) => child.type === "element" && child.tagName === "img", ); } -export const externalLinkArrow = " ↗"; - export const rehypeExternalLinksOptions = { content: (element) => { if (!hasImgChild(element)) { diff --git a/src/plugins/rehype/heading-slugs.ts b/src/plugins/rehype/heading-slugs.ts index eee76801b6f..2116cfa71f6 100644 --- a/src/plugins/rehype/heading-slugs.ts +++ b/src/plugins/rehype/heading-slugs.ts @@ -1,7 +1,7 @@ import { toString } from "hast-util-to-string"; import { visit } from "unist-util-visit"; import GithubSlugger from "github-slugger"; -import { externalLinkArrow } from "./external-links"; +import { externalLinkArrow } from "../shared"; import type { Root } from "hast"; import type { MdxTextExpression } from "mdast-util-mdx-expression"; @@ -29,7 +29,6 @@ export default function () { const text = element.children.at(-2) as MdxTextExpression; text.value = text.value.trimEnd(); - element.children.with(-2, text); } } else { if (!element.properties.id) { diff --git a/src/plugins/rehype/index.node.test.ts b/src/plugins/rehype/index.node.test.ts index 163923e7539..d66cfad8e1f 100644 --- a/src/plugins/rehype/index.node.test.ts +++ b/src/plugins/rehype/index.node.test.ts @@ -4,7 +4,6 @@ import { unified } from "unified"; import rehypeParse from "rehype-parse"; import rehypeStringify from "rehype-stringify"; -import rehypeAutolinkHeadings from "./autolink-headings"; import rehypeExternalLinks from "./external-links"; import rehypeHeadingSlugs from "./heading-slugs"; import rehypeMermaid from "./mermaid"; @@ -86,33 +85,6 @@ describe("external-links", () => { }); }); -describe("autolink-headings", () => { - const process = async (html: string) => { - const file = await unified() - .data("settings", { - fragment: true, - }) - .use([rehypeParse, rehypeAutolinkHeadings, rehypeStringify]) - .process(html); - - return file.toString(); - }; - - test("ignores headings without id", async () => { - const text = await process("

foo

"); - - expect(text).toMatchInlineSnapshot(`"

foo

"`); - }); - - test("wraps heading with id", async () => { - const text = await process("

foo

"); - - expect(text).toMatchInlineSnapshot( - `"

foo

"`, - ); - }); -}); - describe("mermaid", () => { const process = async (html: string) => { const file = await unified() diff --git a/src/plugins/rehype/shift-headings.ts b/src/plugins/rehype/shift-headings.ts deleted file mode 100644 index d26e53f9a6b..00000000000 --- a/src/plugins/rehype/shift-headings.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { headingRank } from "hast-util-heading-rank"; -import { visit } from "unist-util-visit"; -import type { Root, Element } from "hast"; - -export default function () { - return function (tree: Root, file: any) { - visit(tree, "element", function (element) { - if ( - !file.history.find((path: string) => - path.includes("/src/content/changelog/"), - ) - ) { - return; - } - - const classNames = (element.properties.className as string[]) ?? []; - - if (classNames.includes("heading-wrapper")) { - const heading = element.children.find( - (el) => el.type === "element" && headingRank(el), - ) as Element | undefined; - - if (heading) { - let level = headingRank(heading); - - if (level && level < 4) { - const index = classNames.indexOf(`level-h${level}`); - - level = 4; - element.children[element.children.indexOf(heading)] = { - ...heading, - tagName: "h" + (level > 6 ? 6 : level < 1 ? 1 : level), - }; - - classNames[index] = `level-h${level}`; - } - } - } - }); - }; -} diff --git a/src/plugins/remark/validate-images.ts b/src/plugins/remark/validate-images.ts deleted file mode 100644 index 07b434f937a..00000000000 --- a/src/plugins/remark/validate-images.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { existsSync } from "node:fs"; -import { join } from "node:path"; -import { visit } from "unist-util-visit"; - -import type { Node } from "unist"; -import type { VFile } from "vfile"; - -interface ImageNode extends Node { - type: "image"; - url: string; - position?: { - start: { line: number; column: number }; - end: { line: number; column: number }; - }; -} - -export default function validateImages() { - const rootDir = process.cwd(); - - const assetsDir = join(rootDir, "src", "assets"); - const publicDir = join(rootDir, "public"); - - return (tree: Node, file: VFile) => { - visit(tree, "image", (node: ImageNode) => { - const { url } = node; - let fullPath: string; - - if (url.startsWith("~/assets/")) { - fullPath = join(assetsDir, url.slice(9)); - } else if (url.startsWith("/")) { - fullPath = join(publicDir, url); - } else { - // Remote image or unrecognised URL - return; - } - - if (!existsSync(fullPath)) { - const position = node.position - ? ` at line ${node.position.start.line}, column ${node.position.start.column}` - : ""; - - const error = new Error( - `Image not found: "${url}"${position} in ${file.path}\n` + - `Expected to find at: ${fullPath}`, - ) as Error & { file?: string }; - - error.file = file.path; - throw error; - } - }); - }; -} diff --git a/src/plugins/satteri/autolink-headings.node.test.ts b/src/plugins/satteri/autolink-headings.node.test.ts new file mode 100644 index 00000000000..f3d9ebb13dc --- /dev/null +++ b/src/plugins/satteri/autolink-headings.node.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, test } from "vitest"; +import { markdownToHtml } from "satteri"; + +import autolinkHeadings from "./autolink-headings"; +import headingSlugs from "./heading-slugs"; + +function render(source: string): string { + const result = markdownToHtml(source, { + // heading-slugs runs first so headings have ids for autolink-headings to wrap. + hastPlugins: [headingSlugs, autolinkHeadings], + }); + return result.html; +} + +function renderWithoutSlugs(source: string): string { + const result = markdownToHtml(source, { + hastPlugins: [autolinkHeadings], + }); + return result.html; +} + +const EXPECTED_ANCHOR_ICON = + ''; + +describe("autolink-headings", () => { + test("wraps headings that have an id", () => { + expect(render("## foo")).toMatchInlineSnapshot(` + " + " + `); + }); + + test("uses the heading rank in the wrapper class", () => { + expect(render("#### deep heading")).toMatchInlineSnapshot(` + " + " + `); + }); + + test("anchor href matches the heading id", () => { + expect(render("### My Section")).toMatchInlineSnapshot(` + " + " + `); + }); + + test("ignores headings without an id", () => { + expect(renderWithoutSlugs("## foo")).toMatchInlineSnapshot(` + "

foo

+ " + `); + }); +}); diff --git a/src/plugins/satteri/autolink-headings.ts b/src/plugins/satteri/autolink-headings.ts new file mode 100644 index 00000000000..e009a9763a7 --- /dev/null +++ b/src/plugins/satteri/autolink-headings.ts @@ -0,0 +1,34 @@ +import { h } from "hastscript"; +import { defineHastPlugin } from "satteri"; + +import { AnchorLinkIcon } from "../shared"; + +const HEADINGS = ["h1", "h2", "h3", "h4", "h5", "h6"]; + +export default function autolinkHeadings() { + return defineHastPlugin({ + name: "autolink-headings", + element: { + filter: HEADINGS, + visit(node, ctx) { + const id = node.properties?.id; + if (typeof id !== "string") { + return; + } + + const anchor = h("a", { class: "anchor-link", href: `#${id}` }, [ + AnchorLinkIcon, + ]); + + const wrapper = h( + "div", + { tabindex: -1, class: `heading-wrapper level-${node.tagName}` }, + [anchor], + ); + + // wrapNode keeps the wrapper's declared children after the heading: div > [heading, anchor]. + ctx.wrapNode(node, wrapper); + }, + }, + }); +} diff --git a/src/plugins/satteri/external-links.node.test.ts b/src/plugins/satteri/external-links.node.test.ts new file mode 100644 index 00000000000..cdda4e2784a --- /dev/null +++ b/src/plugins/satteri/external-links.node.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, test } from "vitest"; +import { markdownToHtml } from "satteri"; + +import externalLinks from "./external-links"; + +function render(source: string): string { + const result = markdownToHtml(source, { + hastPlugins: [externalLinks], + }); + return result.html; +} + +describe("external-links", () => { + test("annotates absolute https links", () => { + expect(render("[foo](https://example.com)")).toMatchInlineSnapshot(` + "

foo

+ " + `); + }); + + test("annotates absolute http links", () => { + expect(render("[foo](http://example.com)")).toMatchInlineSnapshot(` + "

foo

+ " + `); + }); + + test("leaves internal links untouched", () => { + expect(render("[foo](/workers/)")).toMatchInlineSnapshot(` + "

foo

+ " + `); + }); + + test("leaves anchor-only links untouched", () => { + expect(render("[foo](#section)")).toMatchInlineSnapshot(` + "

foo

+ " + `); + }); + + test("leaves mailto links untouched", () => { + expect(render("[foo](mailto:hi@example.com)")).toMatchInlineSnapshot(` + "

foo

+ " + `); + }); + + test("does not append the arrow when the link wraps an image", () => { + expect(render("[![alt](/image.jpg)](https://example.com)")) + .toMatchInlineSnapshot(` + "

alt

+ " + `); + }); +}); diff --git a/src/plugins/satteri/external-links.ts b/src/plugins/satteri/external-links.ts new file mode 100644 index 00000000000..ea1d4200d7f --- /dev/null +++ b/src/plugins/satteri/external-links.ts @@ -0,0 +1,38 @@ +import { defineHastPlugin } from "satteri"; +import type { Element } from "hast"; + +import { externalLinkArrow } from "../shared"; + +function hasImgChild(node: Element): boolean { + return node.children.some( + (child) => child.type === "element" && child.tagName === "img", + ); +} + +export default function externalLinks() { + return defineHastPlugin({ + name: "external-links", + element: { + filter: ["a"], + visit(node, ctx) { + const href = node.properties?.href; + + if (typeof href !== "string" || !/^https?:\/\//.test(href)) { + return; + } + + ctx.setProperty(node, "target", "_blank"); + ctx.setProperty(node, "rel", ["noopener"]); + + if (!hasImgChild(node)) { + ctx.appendChild(node, { + type: "element", + tagName: "span", + properties: { className: ["external-link"] }, + children: [{ type: "text", value: externalLinkArrow }], + }); + } + }, + }, + }); +} diff --git a/src/plugins/satteri/heading-slugs.node.test.ts b/src/plugins/satteri/heading-slugs.node.test.ts new file mode 100644 index 00000000000..6b01a9ec611 --- /dev/null +++ b/src/plugins/satteri/heading-slugs.node.test.ts @@ -0,0 +1,69 @@ +import { describe, expect, test } from "vitest"; +import { markdownToHtml } from "satteri"; + +import headingSlugs from "./heading-slugs"; +import externalLinks from "./external-links"; + +function render(source: string): string { + const result = markdownToHtml(source, { + hastPlugins: [headingSlugs], + }); + return result.html; +} + +function renderWithExternalLinks(source: string): string { + const result = markdownToHtml(source, { + // external-links runs first so heading-slugs has to strip the trailing arrow. + hastPlugins: [externalLinks, headingSlugs], + }); + return result.html; +} + +describe("heading-slugs", () => { + test("adds a slug derived from text content", () => { + expect(render("## Hello World")).toMatchInlineSnapshot(` + "

Hello World

+ " + `); + }); + + test("dedupes slugs across a single document", () => { + expect(render("## Same\n\n## Same\n\n### Same")).toMatchInlineSnapshot(` + "

Same

+

Same

+

Same

+ " + `); + }); + + test("strips the external-link arrow before slugifying", () => { + expect(renderWithExternalLinks("## [Linked Heading](https://example.com)")) + .toMatchInlineSnapshot(` + "

Linked Heading

+ " + `); + }); + + test("handles all heading ranks", () => { + expect( + render( + "# One\n\n## Two\n\n### Three\n\n#### Four\n\n##### Five\n\n###### Six", + ), + ).toMatchInlineSnapshot(` + "

One

+

Two

+

Three

+

Four

+
Five
+
Six
+ " + `); + }); + + test("slugifies headings with punctuation and casing", () => { + expect(render("## Hello, World! 123")).toMatchInlineSnapshot(` + "

Hello, World! 123

+ " + `); + }); +}); diff --git a/src/plugins/satteri/heading-slugs.ts b/src/plugins/satteri/heading-slugs.ts new file mode 100644 index 00000000000..11e21667ab3 --- /dev/null +++ b/src/plugins/satteri/heading-slugs.ts @@ -0,0 +1,45 @@ +import GithubSlugger from "github-slugger"; +import { defineHastPlugin } from "satteri"; + +import { externalLinkArrow } from "../shared"; + +const HEADINGS = ["h1", "h2", "h3", "h4", "h5", "h6"]; + +// # foo {/*bar*/} = foo +export default function headingSlugs() { + const slugs = new GithubSlugger(); + + return defineHastPlugin({ + name: "heading-slugs", + element: { + filter: HEADINGS, + visit(node, ctx) { + const last = node.children.at(-1); + + if (last?.type === "mdxTextExpression") { + if (last.value.startsWith("/*") && last.value.endsWith("*/")) { + const id = last.value.slice(2, -2).trim(); + ctx.setProperty(node, "id", slugs.slug(id)); + + const index = node.children.length - 2; + const text = node.children[index]; + if (text?.type === "text") { + ctx.removeChildAt(node, index); + ctx.insertChildAt(node, index, { + type: "text", + value: text.value.trimEnd(), + }); + } + } + } else if (!node.properties?.id) { + const text = ctx + .textContent(node) + .replaceAll(externalLinkArrow, "") + .trimEnd(); + + ctx.setProperty(node, "id", slugs.slug(text)); + } + }, + }, + }); +} diff --git a/src/plugins/satteri/index.ts b/src/plugins/satteri/index.ts new file mode 100644 index 00000000000..d53a6344537 --- /dev/null +++ b/src/plugins/satteri/index.ts @@ -0,0 +1,25 @@ +import type { HastPluginDefinition, MdastPluginDefinition } from "satteri"; + +import validateImages from "./validate-images"; +import mermaid from "./mermaid"; +import externalLinks from "./external-links"; +import headingSlugs from "./heading-slugs"; +import autolinkHeadings from "./autolink-headings"; +import titleFigure from "./title-figure"; +import shiftHeadings from "./shift-headings"; + +// Authored as factories so per-document state (the heading slugger) resets per +// page; Sätteri invokes them once per compile. `@astrojs/markdown-satteri` types +// only the resolved definition shape, hence the cast. +export const mdastPlugins = [ + validateImages, +] as unknown as MdastPluginDefinition[]; + +export const hastPlugins = [ + mermaid, + externalLinks, + headingSlugs, + autolinkHeadings, + titleFigure, + shiftHeadings, +] as unknown as HastPluginDefinition[]; diff --git a/src/plugins/satteri/mermaid.node.test.ts b/src/plugins/satteri/mermaid.node.test.ts new file mode 100644 index 00000000000..eb6cc992557 --- /dev/null +++ b/src/plugins/satteri/mermaid.node.test.ts @@ -0,0 +1,51 @@ +import { describe, expect, test } from "vitest"; +import { markdownToHtml } from "satteri"; + +import mermaid from "./mermaid"; + +function render(source: string): string { + const result = markdownToHtml(source, { + hastPlugins: [mermaid], + }); + return result.html; +} + +describe("mermaid", () => { + test("rewrites a ```mermaid fenced code block", () => { + const source = ["```mermaid", "graph TD;", "A-->B;", "```"].join("\n"); + + expect(render(source)).toMatchInlineSnapshot(` + "
graph TD;
+			A-->B;
+			
+ " + `); + }); + + test("leaves non-mermaid code blocks alone", () => { + const source = ["```ts", "const x = 1;", "```"].join("\n"); + + expect(render(source)).toMatchInlineSnapshot(` + "
const x = 1;
+			
+ " + `); + }); + + test("leaves unlabelled fenced code blocks alone", () => { + const source = ["```", "plain text", "```"].join("\n"); + + expect(render(source)).toMatchInlineSnapshot(` + "
plain text
+			
+ " + `); + }); + + test("leaves inline code alone", () => { + expect(render("an `inline mermaid` reference")).toMatchInlineSnapshot(` + "

an inline mermaid reference

+ " + `); + }); +}); diff --git a/src/plugins/satteri/mermaid.ts b/src/plugins/satteri/mermaid.ts new file mode 100644 index 00000000000..cc8774b0d4c --- /dev/null +++ b/src/plugins/satteri/mermaid.ts @@ -0,0 +1,53 @@ +import { defineHastPlugin } from "satteri"; +import { parse } from "space-separated-tokens"; +import type { Element, ElementContent } from "hast"; + +const nonWhitespacePattern = /\w/; + +function isMermaidCode(node: ElementContent): node is Element { + if (node.type !== "element" || node.tagName !== "code") { + return false; + } + + let className = node.properties?.className; + if (typeof className === "string") { + className = parse(className); + } + + return Array.isArray(className) && className.includes("language-mermaid"); +} + +export default function mermaid() { + return defineHastPlugin({ + name: "mermaid", + element: { + filter: ["pre"], + visit(node, ctx) { + let code: Element | undefined; + + for (const child of node.children) { + if (child.type === "text") { + if (nonWhitespacePattern.test(child.value)) { + return; + } + } else if (isMermaidCode(child)) { + code = child; + } else { + return; + } + } + + if (!code) { + return; + } + + return { + type: "element", + tagName: "pre", + properties: { className: ["mermaid"] }, + children: [{ type: "text", value: ctx.textContent(code) }], + }; + }, + }, + }); +} diff --git a/src/plugins/satteri/shift-headings.node.test.ts b/src/plugins/satteri/shift-headings.node.test.ts new file mode 100644 index 00000000000..e2f6704003b --- /dev/null +++ b/src/plugins/satteri/shift-headings.node.test.ts @@ -0,0 +1,76 @@ +import { pathToFileURL } from "node:url"; +import { describe, expect, test } from "vitest"; +import { markdownToHtml } from "satteri"; + +import shiftHeadings from "./shift-headings"; +import headingSlugs from "./heading-slugs"; +import autolinkHeadings from "./autolink-headings"; + +function render(source: string, fileURL?: URL): string { + // shift-headings runs after autolink-headings has produced the + // `.heading-wrapper` div it needs to mutate. + const result = markdownToHtml(source, { + hastPlugins: [headingSlugs, autolinkHeadings, shiftHeadings], + fileURL, + }); + return result.html; +} + +describe("shift-headings", () => { + describe("with a changelog file", () => { + const changelogURL = pathToFileURL( + `${process.cwd()}/src/content/changelog/workers/2025-01-01-example.mdx`, + ); + + test("rewrites h1 to h4 inside changelog wrappers", () => { + expect(render("# Title", changelogURL)).toMatchInlineSnapshot(` + "

Title

+ " + `); + }); + + test("rewrites h2 to h4 inside changelog wrappers", () => { + expect(render("## A subhead", changelogURL)).toMatchInlineSnapshot(` + "

A subhead

+ " + `); + }); + + test("rewrites h3 to h4 inside changelog wrappers", () => { + expect(render("### A deeper head", changelogURL)).toMatchInlineSnapshot(` + "

A deeper head

+ " + `); + }); + + test("does not change h4, h5, or h6", () => { + expect(render("#### Four\n\n##### Five\n\n###### Six", changelogURL)) + .toMatchInlineSnapshot(` + "

Four

+
Five
+
Six
+ " + `); + }); + }); + + describe("without a changelog file", () => { + const docsURL = pathToFileURL( + `${process.cwd()}/src/content/docs/workers/index.mdx`, + ); + + test("does nothing outside the changelog directory", () => { + expect(render("# Title", docsURL)).toMatchInlineSnapshot(` + "

Title

+ " + `); + }); + + test("does nothing when fileURL is missing", () => { + expect(render("# Title")).toMatchInlineSnapshot(` + "

Title

+ " + `); + }); + }); +}); diff --git a/src/plugins/satteri/shift-headings.ts b/src/plugins/satteri/shift-headings.ts new file mode 100644 index 00000000000..ed81915003e --- /dev/null +++ b/src/plugins/satteri/shift-headings.ts @@ -0,0 +1,50 @@ +import { fileURLToPath } from "node:url"; +import { headingRank } from "hast-util-heading-rank"; +import { defineHastPlugin } from "satteri"; +import type { Element } from "hast"; + +export default function shiftHeadings() { + return defineHastPlugin({ + name: "shift-headings", + element: { + filter: ["div"], + visit(node, ctx) { + if ( + !ctx.fileURL || + !fileURLToPath(ctx.fileURL).includes("/src/content/changelog/") + ) { + return; + } + + const classNames = (node.properties?.className as string[]) ?? []; + + if (!classNames.includes("heading-wrapper")) { + return; + } + + const index = node.children.findIndex( + (el) => el.type === "element" && headingRank(el), + ); + if (index === -1) { + return; + } + + const heading = node.children[index] as Element; + const level = headingRank(heading); + + if (level && level < 4) { + const classIndex = classNames.indexOf(`level-h${level}`); + + ctx.removeChildAt(node, index); + ctx.insertChildAt(node, index, { ...heading, tagName: "h4" }); + + if (classIndex !== -1) { + const updated = [...classNames]; + updated[classIndex] = "level-h4"; + ctx.setProperty(node, "className", updated); + } + } + }, + }, + }); +} diff --git a/src/plugins/satteri/title-figure.node.test.ts b/src/plugins/satteri/title-figure.node.test.ts new file mode 100644 index 00000000000..86df3a9dd77 --- /dev/null +++ b/src/plugins/satteri/title-figure.node.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, test } from "vitest"; +import { markdownToHtml } from "satteri"; + +import titleFigure from "./title-figure"; + +function render(source: string): string { + const result = markdownToHtml(source, { + hastPlugins: [titleFigure], + }); + return result.html; +} + +describe("title-figure", () => { + test("wraps a single image with a title in a
", () => { + expect(render(`![a cat](/cat.png "Pictured: a cat")`)) + .toMatchInlineSnapshot(` + "
a cat
Pictured: a cat
+ " + `); + }); + + test("returns the image untouched when it has no title", () => { + expect(render(`![a cat](/cat.png)`)).toMatchInlineSnapshot(` + "a cat + " + `); + }); + + test("handles multiple images", () => { + expect(render(`![](/a.png "A")\n![](/b.png)`)).toMatchInlineSnapshot(` + "
A
+ " + `); + }); + + test("ignores paragraphs without images", () => { + expect(render("just words")).toMatchInlineSnapshot(` + "

just words

+ " + `); + }); +}); diff --git a/src/plugins/satteri/title-figure.ts b/src/plugins/satteri/title-figure.ts new file mode 100644 index 00000000000..75e9e3ec0eb --- /dev/null +++ b/src/plugins/satteri/title-figure.ts @@ -0,0 +1,40 @@ +import { h } from "hastscript"; +import { defineHastPlugin } from "satteri"; +import type { Element } from "hast"; + +function buildFigure(img: Element): Element { + const title = `${img.properties?.title ?? ""}`; + if (!title) { + return img; + } + + return h("figure", [h("img", { ...img.properties }), h("figcaption", title)]); +} + +export default function titleFigure() { + return defineHastPlugin({ + name: "title-figure", + element: { + filter: ["p"], + visit(node, ctx) { + const images = node.children.filter( + (child): child is Element => + child.type === "element" && child.tagName === "img", + ); + + if (images.length === 0) { + return; + } + + const figures = images.map(buildFigure); + + if (figures.length === 1) { + return figures[0]; + } + + ctx.insertBefore(node, figures); + ctx.removeNode(node); + }, + }, + }); +} diff --git a/src/plugins/satteri/validate-images.node.test.ts b/src/plugins/satteri/validate-images.node.test.ts new file mode 100644 index 00000000000..24bd9680bcd --- /dev/null +++ b/src/plugins/satteri/validate-images.node.test.ts @@ -0,0 +1,82 @@ +import { pathToFileURL } from "node:url"; +import { describe, expect, test } from "vitest"; +import { markdownToHtml } from "satteri"; + +import validateImages from "./validate-images"; + +const fakePage = pathToFileURL(`${process.cwd()}/src/content/docs/example.mdx`); + +function render( + source: string, + options: { fileURL?: URL | null } = { fileURL: fakePage }, +): string { + const result = markdownToHtml(source, { + mdastPlugins: [validateImages], + fileURL: options.fileURL ?? undefined, + }); + return result.html; +} + +describe("validate-images", () => { + test("accepts ~/assets paths that resolve to a real file", () => { + expect(() => + render("![cat](~/assets/images/1.1.1.1/google-sheet-function.png)"), + ).not.toThrow(); + }); + + test("accepts /public paths that resolve to a real file", () => { + expect(() => render("![](/favicon.png)")).not.toThrow(); + }); + + test("ignores remote URLs", () => { + expect(() => render("![](https://example.com/cat.png)")).not.toThrow(); + }); + + test("ignores bare relative URLs", () => { + expect(() => render("![](relative-image.png)")).not.toThrow(); + }); + + test("throws for missing ~/assets paths", () => { + expect(() => render("![](~/assets/images/does-not-exist.png)")).toThrow( + /Image not found: "~\/assets\/images\/does-not-exist\.png"/, + ); + }); + + test("throws for missing absolute public paths", () => { + expect(() => render("![](/nope/missing.png)")).toThrow( + /Image not found: "\/nope\/missing\.png"/, + ); + }); + + test("error message includes position and source file path", () => { + try { + render("text\n\n![](~/assets/images/missing.png)"); + expect.fail("expected validate-images to throw"); + } catch (err) { + const message = (err as Error).message; + expect(message).toContain("at line 3, column 1"); + expect(message).toContain("/src/content/docs/example.mdx"); + expect(message).toContain("Expected to find at:"); + } + }); + + test("attaches the source file path to the error", () => { + try { + render("![](~/assets/images/missing.png)"); + expect.fail("expected validate-images to throw"); + } catch (err) { + expect((err as Error & { file?: string }).file).toContain( + "/src/content/docs/example.mdx", + ); + } + }); + + test("falls back to when no fileURL is provided", () => { + try { + render("![](~/assets/images/missing.png)", { fileURL: null }); + expect.fail("expected validate-images to throw"); + } catch (err) { + expect((err as Error).message).toContain(""); + } + }); +}); diff --git a/src/plugins/satteri/validate-images.ts b/src/plugins/satteri/validate-images.ts new file mode 100644 index 00000000000..66c5ae67ead --- /dev/null +++ b/src/plugins/satteri/validate-images.ts @@ -0,0 +1,46 @@ +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { fileURLToPath } from "node:url"; + +import { defineMdastPlugin } from "satteri"; + +export default function validateImages() { + const rootDir = process.cwd(); + + const assetsDir = join(rootDir, "src", "assets"); + const publicDir = join(rootDir, "public"); + + return defineMdastPlugin({ + name: "validate-images", + image(node, ctx) { + const { url } = node; + let fullPath: string; + + if (url.startsWith("~/assets/")) { + fullPath = join(assetsDir, url.slice(9)); + } else if (url.startsWith("/")) { + fullPath = join(publicDir, url); + } else { + // Remote image or unrecognised URL + return; + } + + if (existsSync(fullPath)) { + return; + } + + const where = node.position + ? ` at line ${node.position.start.line}, column ${node.position.start.column}` + : ""; + const file = ctx.fileURL ? fileURLToPath(ctx.fileURL) : ""; + + const error = new Error( + `Image not found: "${url}"${where} in ${file}\n` + + `Expected to find at: ${fullPath}`, + ) as Error & { file?: string }; + + error.file = file; + throw error; + }, + }); +} diff --git a/src/plugins/rehype/autolink-headings.ts b/src/plugins/shared.ts similarity index 57% rename from src/plugins/rehype/autolink-headings.ts rename to src/plugins/shared.ts index 4fd5baa6e04..d6939d4987a 100644 --- a/src/plugins/rehype/autolink-headings.ts +++ b/src/plugins/shared.ts @@ -1,20 +1,8 @@ -import rehypeAutolinkHeadings, { type Options } from "rehype-autolink-headings"; import { h } from "hastscript"; -export const rehypeAutolinkHeadingsOptions = { - properties: { - class: "anchor-link", - }, - behavior: "after", - group: ({ tagName }: { tagName: string }) => - h("div", { - tabIndex: -1, - class: `heading-wrapper level-${tagName}`, - }), - content: () => [AnchorLinkIcon], -} as const satisfies Options; +export const externalLinkArrow = " ↗"; -const AnchorLinkIcon = h( +export const AnchorLinkIcon = h( "span", { ariaHidden: "true", @@ -33,7 +21,3 @@ const AnchorLinkIcon = h( }), ), ); - -export default function () { - return rehypeAutolinkHeadings(rehypeAutolinkHeadingsOptions); -} diff --git a/src/util/props.node.test.ts b/src/util/props.node.test.ts index a02e7b8a3b5..8e4b4859e74 100644 --- a/src/util/props.node.test.ts +++ b/src/util/props.node.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "vitest"; import { generateDescription } from "./props"; -import { externalLinkArrow } from "~/plugins/rehype/external-links"; +import { externalLinkArrow } from "~/plugins/shared"; describe("description", () => { describe("markdown", () => { @@ -14,10 +14,10 @@ describe("description", () => { test("removes external link icon", async () => { const desc = await generateDescription({ - markdown: `[links${externalLinkArrow}](/) and **${externalLinkArrow}stuff**`, + markdown: `[links${externalLinkArrow}](/) and **stuff${externalLinkArrow}**`, }); - expect(desc).toEqual("links and \\*\\*stuff\\*\\*"); + expect(desc).toEqual("links and stuff"); }); }); diff --git a/src/util/props.ts b/src/util/props.ts index cf6a24b3879..1006f534c9e 100644 --- a/src/util/props.ts +++ b/src/util/props.ts @@ -1,9 +1,9 @@ import type { StarlightRouteData } from "@astrojs/starlight/route-data"; import { parse } from "node-html-parser"; import he from "he"; -import { remark } from "remark"; -import strip from "strip-markdown"; -import { externalLinkArrow } from "~/plugins/rehype/external-links"; +import { toString as mdastToString } from "mdast-util-to-string"; +import { markdownToMdast } from "satteri"; +import { externalLinkArrow } from "~/plugins/shared"; type TableOfContentsItems = NonNullable["items"]; @@ -74,9 +74,10 @@ export async function generateDescription({ let description = undefined; if (markdown) { - const file = await remark().use(strip).process(markdown); - - description = file.toString(); + const tree = markdownToMdast(markdown, { + features: { frontmatter: false, gfm: true }, + }); + description = mdastToString(tree).replace(/\s+/g, " "); } else if (html) { const dom = parse(html); const paragraph = dom.querySelector(":root > p"); diff --git a/src/util/rehype.ts b/src/util/rehype.ts deleted file mode 100644 index 1c88c639ab9..00000000000 --- a/src/util/rehype.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { rehype } from "rehype"; -import type { PluggableList } from "unified"; - -export async function process(html: string, plugins: PluggableList) { - const file = await rehype() - .data("settings", { - fragment: true, - }) - .use(plugins) - .process(html); - - return file.toString(); -} diff --git a/src/util/sidebar.ts b/src/util/sidebar.ts index ec73d0264f3..b0b9a9331ae 100644 --- a/src/util/sidebar.ts +++ b/src/util/sidebar.ts @@ -2,7 +2,7 @@ import type { AstroGlobal } from "astro"; import type { StarlightRouteData } from "@astrojs/starlight/route-data"; import { getEntry, getCollection } from "astro:content"; -import { externalLinkArrow } from "~/plugins/rehype/external-links"; +import { externalLinkArrow } from "~/plugins/shared"; type Link = Extract & { order?: number;