Add llms-full.txt and AI-readability signals to the docs (#2911)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-08-28 19:30:13 +02:00
1 parent dbf2663efe
commit 73f7c2a80b
16 files changed
+341 -97

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/docs": minor
---
Added `Accept: text/markdown` content negotiation for docs pages, with q-value parsing and `406` responses.
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/docs": minor
---
Added a `llms-full.txt` page with all docs in one file, `Content-Signal` in robots.txt and markdown `Link` alternate headers.
+3 -57
View File
@@ -6,6 +6,7 @@ import { satteri } from '@astrojs/markdown-satteri'
import { unwrapJsxParagraphs } from './lib/satteri-unwrap-jsx-paragraphs.mjs' import { unwrapJsxParagraphs } from './lib/satteri-unwrap-jsx-paragraphs.mjs'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
import { copyAssets } from '../.build/copy-assets' import { copyAssets } from '../.build/copy-assets'
import { redirects } from './lib/redirects.ts'
/** @param {string} p */ /** @param {string} p */
const path = (p) => fileURLToPath(new URL(p, import.meta.url)) const path = (p) => fileURLToPath(new URL(p, import.meta.url))
@@ -30,63 +31,8 @@ export default defineConfig({
enabled: true, enabled: true,
}, },
}), }),
// Renamed/moved pages. Add an entry here whenever a docs URL changes. // renamed/moved pages, shared with middleware.ts
// The plural component slugs are the pre-Astro URLs still present in the redirects,
// Google index, Algolia search results and external backlinks.
redirects: {
'/ui/base/markdown': { status: 301, destination: '/ui/base/prose' },
// @tabler/icons-eps is no longer maintained; PDF is the vector format to use.
'/icons/static-files/eps': { status: 301, destination: '/icons/static-files/pdf' },
...Object.fromEntries(
[
['alerts', 'alert'],
['avatars', 'avatar'],
['badges', 'badge'],
['buttons', 'button'],
['cards', 'card'],
['dropdowns', 'dropdown'],
['icons', 'icon'],
['modals', 'modal'],
['ribbons', 'ribbon'],
['spinners', 'spinner'],
['statuses', 'status'],
['steps', 'step'],
['tables', 'table'],
['tabs', 'tab'],
['timelines', 'timeline'],
['toasts', 'toast'],
['tooltips', 'tooltip'],
].map(([from, to]) => [`/ui/components/${from}`, { status: 301, destination: `/ui/components/${to}` }]),
),
// Components that need a third-party library moved to /ui/plugins/.
...Object.fromEntries(['autosize', 'chart', 'countup', 'dropzone', 'fullcalendar', 'inline-player', 'lightbox', 'range-slider', 'signature', 'vector-map', 'wysiwyg'].map((slug) => [`/ui/components/${slug}`, { status: 301, destination: `/ui/plugins/${slug}` }])),
// Pre-Astro plural urls for two of those pages, sent straight to the new home.
'/ui/components/charts': { status: 301, destination: '/ui/plugins/chart' },
'/ui/components/vector-maps': { status: 301, destination: '/ui/plugins/vector-map' },
// The form- prefix was redundant inside /ui/forms/.
'/ui/forms/form-elements': { status: 301, destination: '/ui/forms/elements' },
'/ui/forms/form-fieldset': { status: 301, destination: '/ui/forms/fieldset' },
'/ui/forms/form-floating': { status: 301, destination: '/ui/forms/floating-labels' },
'/ui/forms/form-helpers': { status: 301, destination: '/ui/forms/helpers' },
'/ui/forms/form-selectboxes': { status: 301, destination: '/ui/forms/select-group' },
'/ui/forms/form-image-check': { status: 301, destination: '/ui/forms/image-check' },
'/ui/forms/form-color-check': { status: 301, destination: '/ui/forms/color-check' },
'/ui/forms/form-select-tomselect': { status: 301, destination: '/ui/plugins/advanced-select' },
'/ui/forms/form-colorpicker': { status: 301, destination: '/ui/plugins/color-picker' },
'/ui/forms/form-datepicker': { status: 301, destination: '/ui/plugins/date-picker' },
'/ui/forms/form-input-mask': { status: 301, destination: '/ui/plugins/input-mask' },
'/ui/forms/form-validation': { status: 301, destination: '/ui/forms/validation' },
// Illustrations and Emails lost their "introduction" wrapper.
'/illustrations/introduction': { status: 301, destination: '/illustrations' },
'/illustrations/introduction/preview': { status: 301, destination: '/illustrations/preview' },
'/illustrations/introduction/contents': { status: 301, destination: '/illustrations/contents' },
'/illustrations/introduction/customization': { status: 301, destination: '/illustrations/customization' },
'/illustrations/introduction/license': { status: 301, destination: '/illustrations/license' },
'/emails/introduction': { status: 301, destination: '/emails' },
'/emails/introduction/contents': { status: 301, destination: '/emails/contents' },
'/emails/introduction/compiled-html': { status: 301, destination: '/emails/compiled-html' },
'/emails/introduction/source-html': { status: 301, destination: '/emails/source-html' },
},
// pages live at the package root (./pages) — content-first layout; all // pages live at the package root (./pages) — content-first layout; all
// components/lib/data are shared (see the @shared alias). The docs content // components/lib/data are shared (see the @shared alias). The docs content
// itself lives in ./content and is rendered by pages/[...slug].astro. // itself lives in ./content and is rendered by pages/[...slug].astro.
+7
View File
@@ -302,6 +302,13 @@ const relatedPages = await Promise.all(
<body class="d-flex flex-column"> <body class="d-flex flex-column">
<a href="#content" class="visually-hidden-focusable skip-link">Skip to main content</a> <a href="#content" class="visually-hidden-focusable skip-link">Skip to main content</a>
{
markdownUrl && (
<div class="visually-hidden" aria-hidden="true">
A Markdown version of this page is available at {`${site.docsUrl}${markdownUrl}`}.
</div>
)
}
<!-- BEGIN GLOBAL THEME SCRIPT --> <!-- BEGIN GLOBAL THEME SCRIPT -->
<script is:inline src="/dist/js/tabler-theme.js"></script> <script is:inline src="/dist/js/tabler-theme.js"></script>
<script is:inline> <script is:inline>
+66
View File
@@ -0,0 +1,66 @@
// Accept negotiation between text/html and text/markdown (RFC 9110 q-values).
// A tie goes to markdown only when the client named text/markdown explicitly,
// so `Accept: */*` from a browser still gets html; 'none' means answer 406.
type MediaRange = {
type: string
subtype: string
q: number
}
export type Format = 'html' | 'markdown' | 'none'
function parseAccept(header: string): MediaRange[] {
return header
.split(',')
.map((part): MediaRange => {
const [range = '', ...params] = part.trim().split(';')
const [type = '', subtype = ''] = range.trim().toLowerCase().split('/')
let q = 1
for (const param of params) {
const [key, value] = param.split('=')
if (key?.trim().toLowerCase() === 'q') {
const parsed = Number.parseFloat(value ?? '')
// a present but unparsable q fails closed
q = Number.isNaN(parsed) ? 0 : Math.min(Math.max(parsed, 0), 1)
}
}
return { type, subtype, q }
})
.filter((range) => range.type !== '' && range.subtype !== '')
}
// The q of the most specific matching range: exact type beats `text/*` beats `*/*`.
function match(ranges: MediaRange[], type: string, subtype: string) {
let q = 0
let specificity = -1
let explicit = false
for (const range of ranges) {
let rangeSpecificity: number
if (range.type === type && range.subtype === subtype) rangeSpecificity = 2
else if (range.type === type && range.subtype === '*') rangeSpecificity = 1
else if (range.type === '*' && range.subtype === '*') rangeSpecificity = 0
else continue
if (rangeSpecificity > specificity) {
specificity = rangeSpecificity
q = range.q
explicit = rangeSpecificity === 2
}
}
return { q, explicit }
}
export function preferredFormat(header: string | null): Format {
if (!header || header.trim() === '') return 'html'
const ranges = parseAccept(header)
if (ranges.length === 0) return 'html'
const html = match(ranges, 'text', 'html')
const markdown = match(ranges, 'text', 'markdown')
if (markdown.q > html.q) return 'markdown'
if (markdown.q === html.q && markdown.q > 0 && markdown.explicit) return 'markdown'
if (html.q > 0) return 'html'
if (markdown.q > 0) return 'markdown'
return 'none'
}
+30 -4
View File
@@ -17,6 +17,7 @@ import { experimental_AstroContainer as AstroContainer } from 'astro/container'
import { getContainerRenderer } from '@astrojs/mdx/container-renderer' import { getContainerRenderer } from '@astrojs/mdx/container-renderer'
import { beautifyHtml, extractMarkedSnippet } from '@shared/lib/code-example' import { beautifyHtml, extractMarkedSnippet } from '@shared/lib/code-example'
import { site } from '@shared/lib/site' import { site } from '@shared/lib/site'
import docs from '@data/docs.json'
import packageManagers from '@data/package-managers.json' import packageManagers from '@data/package-managers.json'
import { cdnCssTag, cdnJsTag, cdnPackageSnippet, cdnPluginSnippet } from './cdn-snippets.ts' import { cdnCssTag, cdnJsTag, cdnPackageSnippet, cdnPluginSnippet } from './cdn-snippets.ts'
@@ -154,8 +155,8 @@ async function renderedExamples(entry: CollectionEntry<'docs'>): Promise<(string
const markup = block.match(/data-clipboard-text="([^"]*)"/) ?? block.match(/data-example-markup="([^"]*)"/) const markup = block.match(/data-clipboard-text="([^"]*)"/) ?? block.match(/data-example-markup="([^"]*)"/)
return markup ? beautifyHtml(decodeEntities(markup[1]!)) : null return markup ? beautifyHtml(decodeEntities(markup[1]!)) : null
}) })
} catch { } catch (error) {
// A page that fails to render still gets its prose and its source-level examples. console.warn(`[llms] Rendering ${entry.id} failed, examples fall back to their MDX source:`, error)
return [] return []
} }
} }
@@ -222,13 +223,38 @@ export async function mdxToMarkdown(body: string, examples: (string | null)[] =
.trim() .trim()
} }
/** A single docs page as a standalone markdown document. */ async function buildPageMarkdown(entry: CollectionEntry<'docs'>, url: string): Promise<string> {
export async function pageMarkdown(entry: CollectionEntry<'docs'>, url: string): Promise<string> {
const { title, summary, description } = entry.data const { title, summary, description } = entry.data
const header = [`# ${title}`, '', `> ${summary}`, '', description, '', `Source: ${url}`, '', '---', ''].join('\n') const header = [`# ${title}`, '', `> ${summary}`, '', description, '', `Source: ${url}`, '', '---', ''].join('\n')
return `${header}\n${await mdxToMarkdown(entry.body ?? '', await renderedExamples(entry))}\n` return `${header}\n${await mdxToMarkdown(entry.body ?? '', await renderedExamples(entry))}\n`
} }
// [...slug].md.ts and llms-full.txt.ts render the same pages in one build.
const pageCache = new Map<string, Promise<string>>()
/** A single docs page as a standalone markdown document. */
export function pageMarkdown(entry: CollectionEntry<'docs'>, url: string): Promise<string> {
const key = `${entry.id}\n${url}`
let cached = pageCache.get(key)
if (!cached) {
cached = buildPageMarkdown(entry, url)
pageCache.set(key, cached)
}
return cached
}
type MenuNode = { url?: string; children?: MenuNode[] }
/** Docs urls in sidebar (docs.json) order — the shared reading order of llms.txt and llms-full.txt. */
export function menuOrderedUrls(): string[] {
const normalize = (url: string) => {
const parts = url.split('/').filter(Boolean)
return parts.length ? `/${parts.join('/')}` : '/'
}
const walk = (nodes: MenuNode[]): string[] => nodes.flatMap((node) => [...(node.url ? [normalize(node.url)] : []), ...walk(node.children ?? [])])
return [...new Set(walk(docs.menu as MenuNode[]))]
}
/** Absolute in production, root-relative in dev — same rule as sitemap.xml.ts. */ /** Absolute in production, root-relative in dev — same rule as sitemap.xml.ts. */
export const baseUrl = () => (process.env.NODE_ENV === 'development' ? '' : site.docsUrl) export const baseUrl = () => (process.env.NODE_ENV === 'development' ? '' : site.docsUrl)
+4
View File
@@ -0,0 +1,4 @@
// The `.md` mirror of a docs page url; the mirror of `/` is `/index.md`.
// The same rule is hand-encoded in vercel.json's Link-header routes.
// Dependency-free so Vercel's middleware bundler can include it.
export const markdownUrlFromDocsUrl = (url: string) => (url === '/' ? '/index.md' : `${url.replace(/\/$/, '')}.md`)
+61
View File
@@ -0,0 +1,61 @@
// Renamed/moved docs pages; add an entry whenever a docs URL changes.
// Shared by astro.config.mjs (real HTTP redirects) and middleware.ts (which
// must let these urls fall through instead of rewriting them to `.md`).
type Redirect = { status: 301; destination: string }
export const redirects: Record<string, Redirect> = {
'/ui/base/markdown': { status: 301, destination: '/ui/base/prose' },
// @tabler/icons-eps is no longer maintained; PDF is the vector format to use.
'/icons/static-files/eps': { status: 301, destination: '/icons/static-files/pdf' },
// pre-Astro plural slugs, still present in the Google index and backlinks
...Object.fromEntries(
[
['alerts', 'alert'],
['avatars', 'avatar'],
['badges', 'badge'],
['buttons', 'button'],
['cards', 'card'],
['dropdowns', 'dropdown'],
['icons', 'icon'],
['modals', 'modal'],
['ribbons', 'ribbon'],
['spinners', 'spinner'],
['statuses', 'status'],
['steps', 'step'],
['tables', 'table'],
['tabs', 'tab'],
['timelines', 'timeline'],
['toasts', 'toast'],
['tooltips', 'tooltip'],
].map(([from, to]): [string, Redirect] => [`/ui/components/${from}`, { status: 301, destination: `/ui/components/${to}` }]),
),
// Components that need a third-party library moved to /ui/plugins/.
...Object.fromEntries(['autosize', 'chart', 'countup', 'dropzone', 'fullcalendar', 'inline-player', 'lightbox', 'range-slider', 'signature', 'vector-map', 'wysiwyg'].map((slug): [string, Redirect] => [`/ui/components/${slug}`, { status: 301, destination: `/ui/plugins/${slug}` }])),
// Pre-Astro plural urls for two of those pages, sent straight to the new home.
'/ui/components/charts': { status: 301, destination: '/ui/plugins/chart' },
'/ui/components/vector-maps': { status: 301, destination: '/ui/plugins/vector-map' },
// The form- prefix was redundant inside /ui/forms/.
'/ui/forms/form-elements': { status: 301, destination: '/ui/forms/elements' },
'/ui/forms/form-fieldset': { status: 301, destination: '/ui/forms/fieldset' },
'/ui/forms/form-floating': { status: 301, destination: '/ui/forms/floating-labels' },
'/ui/forms/form-helpers': { status: 301, destination: '/ui/forms/helpers' },
'/ui/forms/form-selectboxes': { status: 301, destination: '/ui/forms/select-group' },
'/ui/forms/form-image-check': { status: 301, destination: '/ui/forms/image-check' },
'/ui/forms/form-color-check': { status: 301, destination: '/ui/forms/color-check' },
'/ui/forms/form-select-tomselect': { status: 301, destination: '/ui/plugins/advanced-select' },
'/ui/forms/form-colorpicker': { status: 301, destination: '/ui/plugins/color-picker' },
'/ui/forms/form-datepicker': { status: 301, destination: '/ui/plugins/date-picker' },
'/ui/forms/form-input-mask': { status: 301, destination: '/ui/plugins/input-mask' },
'/ui/forms/form-validation': { status: 301, destination: '/ui/forms/validation' },
// Illustrations and Emails lost their "introduction" wrapper.
'/illustrations/introduction': { status: 301, destination: '/illustrations' },
'/illustrations/introduction/preview': { status: 301, destination: '/illustrations/preview' },
'/illustrations/introduction/contents': { status: 301, destination: '/illustrations/contents' },
'/illustrations/introduction/customization': { status: 301, destination: '/illustrations/customization' },
'/illustrations/introduction/license': { status: 301, destination: '/illustrations/license' },
'/emails/introduction': { status: 301, destination: '/emails' },
'/emails/introduction/contents': { status: 301, destination: '/emails/contents' },
'/emails/introduction/compiled-html': { status: 301, destination: '/emails/compiled-html' },
'/emails/introduction/source-html': { status: 301, destination: '/emails/source-html' },
}
+56
View File
@@ -0,0 +1,56 @@
// Vercel Routing Middleware (https://vercel.com/docs/routing-middleware):
// serves the markdown mirror of a docs page when the client prefers it via
// `Accept: text/markdown`. Runs only on Vercel deployments.
import type { MiddlewareHandler } from 'astro'
import { next, rewrite } from '@vercel/functions'
import { preferredFormat } from './lib/accept'
import { markdownUrlFromDocsUrl } from './lib/markdown-url'
import { redirects } from './lib/redirects'
// Astro picks this file up as its own middleware (`srcDir` is the project
// root) and requires an `onRequest` export; the real logic is Vercel-only.
export const onRequest: MiddlewareHandler = (_context, nextHandler) => nextHandler()
export const config = {
// extensionless paths outside the asset directories — the html docs pages
matcher: '/((?!(?:dist|preview|img|static|css|js)/)(?!.*\\.).*)',
}
const alternate = (path: string, type: string) => `<${path}>; rel="alternate"; type="${type}"`
export default function middleware(request: Request) {
const url = new URL(request.url)
// renamed pages fall through to their 301; negotiation reruns on the target
if (Object.hasOwn(redirects, url.pathname)) return next()
const format = preferredFormat(request.headers.get('accept'))
if (format === 'markdown') {
const htmlPath = url.pathname
url.pathname = markdownUrlFromDocsUrl(url.pathname)
return rewrite(url, {
headers: {
Link: alternate(htmlPath, 'text/html'),
Vary: 'Accept',
},
})
}
if (format === 'none') {
return new Response('Not acceptable. This page is available as text/html or text/markdown.\n', {
status: 406,
headers: {
'Content-Type': 'text/plain; charset=utf-8',
'Vary': 'Accept',
},
})
}
return next({
headers: {
Link: alternate(markdownUrlFromDocsUrl(url.pathname), 'text/markdown'),
Vary: 'Accept',
},
})
}
+2 -1
View File
@@ -19,14 +19,15 @@
"@astrojs/vercel": "^11.0.5", "@astrojs/vercel": "^11.0.5",
"@docsearch/js": "^4.7.0", "@docsearch/js": "^4.7.0",
"@tabler/core": "workspace:*", "@tabler/core": "workspace:*",
"@vercel/functions": "^3.9.5",
"astro": "^7.1.6", "astro": "^7.1.6",
"shiki": "^4.3.1" "shiki": "^4.3.1"
}, },
"devDependencies": { "devDependencies": {
"@astrojs/check": "^0.9.4", "@astrojs/check": "^0.9.4",
"@docsearch/css": "^4.7.0",
"@astrojs/markdown-satteri": "^0.3.4", "@astrojs/markdown-satteri": "^0.3.4",
"@astrojs/mdx": "^7.0.3", "@astrojs/mdx": "^7.0.3",
"@docsearch/css": "^4.7.0",
"@tabler/preview": "workspace:*", "@tabler/preview": "workspace:*",
"@types/node": "^26.1.1", "@types/node": "^26.1.1",
"js-beautify": "^2.0.3", "js-beautify": "^2.0.3",
+2 -1
View File
@@ -6,6 +6,7 @@ import type { GetStaticPaths } from 'astro'
import { getCollection, render } from 'astro:content' import { getCollection, render } from 'astro:content'
import DocsLayout from '@layouts/DocsLayout.astro' import DocsLayout from '@layouts/DocsLayout.astro'
import { docsUrlFromId } from '@lib/docs-pages' import { docsUrlFromId } from '@lib/docs-pages'
import { markdownUrlFromDocsUrl } from '@lib/markdown-url'
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const entries = await getCollection('docs') const entries = await getCollection('docs')
@@ -45,7 +46,7 @@ if (data.classnames) {
sourcePath={data.source} sourcePath={data.source}
toc={toc} toc={toc}
url={docsUrlFromId(entry.id)} url={docsUrlFromId(entry.id)}
markdownUrl={`/${entry.id}.md`} markdownUrl={markdownUrlFromDocsUrl(docsUrlFromId(entry.id))}
editPath={entry.filePath ? `docs/${entry.filePath}` : undefined} editPath={entry.filePath ? `docs/${entry.filePath}` : undefined}
> >
<Content /> <Content />
+40
View File
@@ -0,0 +1,40 @@
// https://llmstxt.org — the whole docs as one markdown file. Pages are the
// same markdown the `.md` mirrors serve, in sidebar order (home page first,
// pages missing from the sidebar tree last).
import type { APIRoute } from 'astro'
import { getCollection } from 'astro:content'
import { site } from '@shared/lib/site'
import { docsUrlFromId } from '@lib/docs-pages'
import { baseUrl, menuOrderedUrls, pageMarkdown } from '@lib/llms'
export const prerender = true
export const GET: APIRoute = async () => {
const menuRank = new Map(menuOrderedUrls().map((url, index) => [url, index]))
const rank = (url: string) => menuRank.get(url) ?? Infinity
const entries = (await getCollection('docs')).sort((a, b) => {
const [urlA, urlB] = [docsUrlFromId(a.id), docsUrlFromId(b.id)]
if (urlA === '/' || urlB === '/') return urlA === '/' ? -1 : 1
return rank(urlA) - rank(urlB) || urlA.localeCompare(urlB)
})
const base = baseUrl()
const pages = await Promise.all(entries.map((entry) => pageMarkdown(entry, `${base}${docsUrlFromId(entry.id)}`)))
const body = `# Tabler — full documentation
> ${site.description}
This is the complete documentation of ${site.docsUrl} as a single markdown file. A curated index of the same pages lives at ${site.docsUrl}/llms.txt.
---
${pages.join('\n\n---\n\n')}
`
return new Response(body, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
},
})
}
+3 -3
View File
@@ -8,6 +8,7 @@ import docs from '@data/docs.json'
import { site } from '@shared/lib/site' import { site } from '@shared/lib/site'
import { docsUrlFromId } from '@lib/docs-pages' import { docsUrlFromId } from '@lib/docs-pages'
import { baseUrl } from '@lib/llms' import { baseUrl } from '@lib/llms'
import { markdownUrlFromDocsUrl } from '@lib/markdown-url'
export const prerender = true export const prerender = true
@@ -28,8 +29,7 @@ export const GET: APIRoute = async () => {
const entry = byUrl.get(url) const entry = byUrl.get(url)
if (!entry || listed.has(url)) return null if (!entry || listed.has(url)) return null
listed.add(url) listed.add(url)
// `/` has no `.md` sibling — its mirror is `/index.md` return `- [${entry.data.title}](${base}${markdownUrlFromDocsUrl(url)}): ${entry.data.description}`
return `- [${entry.data.title}](${base}${url === '/' ? '/index' : url}.md): ${entry.data.description}`
} }
const pageUrls = (nodes: (MenuNode | undefined)[]) => nodes.flatMap((node) => [node?.url, ...(node?.children ?? []).map((child) => child.url)]).filter((url): url is string => typeof url === 'string' && url.startsWith('/')) const pageUrls = (nodes: (MenuNode | undefined)[]) => nodes.flatMap((node) => [node?.url, ...(node?.children ?? []).map((child) => child.url)]).filter((url): url is string => typeof url === 'string' && url.startsWith('/'))
@@ -85,7 +85,7 @@ export const GET: APIRoute = async () => {
Tabler is a free and open source dashboard UI kit built on Bootstrap. This file indexes the documentation at ${site.docsUrl}. Tabler is a free and open source dashboard UI kit built on Bootstrap. This file indexes the documentation at ${site.docsUrl}.
Every page is available as markdown by appending \`.md\` to its url, for example \`${site.docsUrl}/ui/components/button.md\`. Those files contain the same prose as the html page plus the markup of every example, as fenced code blocks. Every page is available as markdown by appending \`.md\` to its url, for example \`${site.docsUrl}/ui/components/button.md\`. Those files contain the same prose as the html page plus the markup of every example, as fenced code blocks. The whole documentation concatenated into one file is available at \`${site.docsUrl}/llms-full.txt\`.
The markup is taken from the rendered pages, so every example is plain html — the same markup the copy button on the page gives you. The markup is taken from the rendered pages, so every example is plain html — the same markup the copy button on the page gives you.
+1
View File
@@ -9,6 +9,7 @@ export const GET: APIRoute = () => {
const body = `Sitemap: ${sitemapUrl} const body = `Sitemap: ${sitemapUrl}
User-agent: * User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=yes
Disallow:${isProduction ? '' : ' /'} Disallow:${isProduction ? '' : ' /'}
` `
+22
View File
@@ -8,6 +8,28 @@
{ {
"source": "/(dist|preview|img|static|css|js)/(.*)", "source": "/(dist|preview|img|static|css|js)/(.*)",
"headers": [{ "key": "Cache-Control", "value": "public, max-age=3600, stale-while-revalidate=86400" }] "headers": [{ "key": "Cache-Control", "value": "public, max-age=3600, stale-while-revalidate=86400" }]
},
{
"source": "/(llms|llms-full)\\.txt",
"headers": [{ "key": "Cache-Control", "value": "public, max-age=3600, stale-while-revalidate=86400" }]
},
{
"source": "/:path([^.]+)\\.md",
"headers": [{ "key": "Cache-Control", "value": "public, max-age=3600, stale-while-revalidate=86400" }]
},
{
"source": "/:path((?!index$)[^.]+)\\.md",
"headers": [
{ "key": "Link", "value": "</:path>; rel=\"alternate\"; type=\"text/html\"" },
{ "key": "Vary", "value": "Accept" }
]
},
{
"source": "/index.md",
"headers": [
{ "key": "Link", "value": "</>; rel=\"alternate\"; type=\"text/html\"" },
{ "key": "Vary", "value": "Accept" }
]
} }
] ]
} }
+34 -31
View File
@@ -213,16 +213,19 @@ importers:
dependencies: dependencies:
'@astrojs/vercel': '@astrojs/vercel':
specifier: ^11.0.5 specifier: ^11.0.5
version: 11.0.5(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(next@16.2.10(@babel/core@7.29.7(supports-color@10.2.2))(@opentelemetry/api@1.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.102.0))(react@19.2.7)(supports-color@10.2.2)(ws@8.21.0) version: 11.0.5(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(next@16.2.10(@babel/core@7.29.7(supports-color@10.2.2))(@opentelemetry/api@1.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.102.0))(react@19.2.7)(supports-color@10.2.2)(ws@8.21.0)
'@docsearch/js': '@docsearch/js':
specifier: ^4.7.0 specifier: ^4.7.0
version: 4.7.0 version: 4.7.0
'@tabler/core': '@tabler/core':
specifier: workspace:* specifier: workspace:*
version: link:../core version: link:../core
'@vercel/functions':
specifier: ^3.9.5
version: 3.9.5(ws@8.21.0)
astro: astro:
specifier: ^7.1.6 specifier: ^7.1.6
version: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) version: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
shiki: shiki:
specifier: ^4.3.1 specifier: ^4.3.1
version: 4.3.1 version: 4.3.1
@@ -235,7 +238,7 @@ importers:
version: 0.3.4 version: 0.3.4
'@astrojs/mdx': '@astrojs/mdx':
specifier: ^7.0.3 specifier: ^7.0.3
version: 7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(supports-color@10.2.2) version: 7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(supports-color@10.2.2)
'@docsearch/css': '@docsearch/css':
specifier: ^4.7.0 specifier: ^4.7.0
version: 4.7.0 version: 4.7.0
@@ -262,7 +265,7 @@ importers:
version: link:../core version: link:../core
astro: astro:
specifier: ^7.1.6 specifier: ^7.1.6
version: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) version: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
devDependencies: devDependencies:
'@astrojs/check': '@astrojs/check':
specifier: ^0.9.4 specifier: ^0.9.4
@@ -272,7 +275,7 @@ importers:
version: 0.3.4 version: 0.3.4
'@astrojs/mdx': '@astrojs/mdx':
specifier: ^7.0.3 specifier: ^7.0.3
version: 7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(supports-color@5.5.0) version: 7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(supports-color@5.5.0)
'@tabler/icons': '@tabler/icons':
specifier: ^3.45.0 specifier: ^3.45.0
version: 3.45.0 version: 3.45.0
@@ -302,7 +305,7 @@ importers:
version: link:../core version: link:../core
astro: astro:
specifier: ^7.1.6 specifier: ^7.1.6
version: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) version: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
devDependencies: devDependencies:
'@astrojs/check': '@astrojs/check':
specifier: ^0.9.4 specifier: ^0.9.4
@@ -340,7 +343,7 @@ importers:
version: 1.14.3 version: 1.14.3
astro: astro:
specifier: ^7.1.3 specifier: ^7.1.3
version: 7.1.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) version: 7.1.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
js-beautify: js-beautify:
specifier: ^2.0.3 specifier: ^2.0.3
version: 2.0.3 version: 2.0.3
@@ -2088,15 +2091,15 @@ packages:
vue-router: vue-router:
optional: true optional: true
'@vercel/cli-config@0.2.2': '@vercel/cli-config@0.2.4':
resolution: {integrity: sha512-kAy35eymNzRBfmcqEViVQge0KJ59FYEKsPqGNCSJQ7M9HTuFGWd3qPcZos1A5cZpAWRBdiYe82Bcz9P7pIZvUQ==} resolution: {integrity: sha512-kZ5SojbrV06GHoU6QIWGwDXLov+s9rWZ7QqdqKfJfBGCNUieGfgaCjeeenNy8Y+QC0bwC0dZ2B4l5Hvdmrgpdw==}
'@vercel/cli-exec@1.0.1': '@vercel/cli-exec@1.0.1':
resolution: {integrity: sha512-g9XerViJ/paZujufXYcu5XYI2vU2rtB4sgdpjUHde5RnOkdmpu0ngH46LCFGHoPXO/C+qDPSczIHIRN+8Q2YKQ==} resolution: {integrity: sha512-g9XerViJ/paZujufXYcu5XYI2vU2rtB4sgdpjUHde5RnOkdmpu0ngH46LCFGHoPXO/C+qDPSczIHIRN+8Q2YKQ==}
engines: {node: '>= 18'} engines: {node: '>= 18'}
'@vercel/functions@3.9.1': '@vercel/functions@3.9.5':
resolution: {integrity: sha512-RhrIZvQ0Jfgeq0pCaeZ/E19OujpGEyB2BDO//6F91Z8VC5JJ5H4ckLLswaKnM7vOutRswU/MO6UQMGhtm7fA/Q==} resolution: {integrity: sha512-EUfqlb7AzoEh7URlMNAO4jbJiLWz9grDBHvfjKTDvEP9c8y3DqX3SWPvfaQkUjtkm3b83flhaUUMuewdHa+qmw==}
engines: {node: '>= 20'} engines: {node: '>= 20'}
peerDependencies: peerDependencies:
'@aws-sdk/credential-provider-web-identity': '*' '@aws-sdk/credential-provider-web-identity': '*'
@@ -2112,8 +2115,8 @@ packages:
engines: {node: '>=20'} engines: {node: '>=20'}
hasBin: true hasBin: true
'@vercel/oidc@3.8.2': '@vercel/oidc@3.8.5':
resolution: {integrity: sha512-nmVSeQ7tewCkqYBNB/MNL8aPB9sTvtjvqIE6+U17U4IuTyehuWVERDlWrSn0DVfiFAstRlRkGLHBlKHB2FyzbQ==} resolution: {integrity: sha512-RwXYtnt6za+5UO4IaLywN/6B95AlLqynPRUWRJxeJ/qufwkcLUbZNUxYtzT0uMpuraWhlNcGqPNGkTnZr4BGBw==}
engines: {node: '>= 20'} engines: {node: '>= 20'}
'@vercel/routing-utils@5.3.3': '@vercel/routing-utils@5.3.3':
@@ -5504,13 +5507,13 @@ snapshots:
hast-util-from-html: 2.0.3 hast-util-from-html: 2.0.3
satteri: 0.9.5 satteri: 0.9.5
'@astrojs/mdx@7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(supports-color@10.2.2)': '@astrojs/mdx@7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(supports-color@10.2.2)':
dependencies: dependencies:
'@astrojs/internal-helpers': 0.10.1 '@astrojs/internal-helpers': 0.10.1
'@astrojs/markdown-remark': 7.2.1(supports-color@10.2.2) '@astrojs/markdown-remark': 7.2.1(supports-color@10.2.2)
'@mdx-js/mdx': 3.1.1(supports-color@10.2.2) '@mdx-js/mdx': 3.1.1(supports-color@10.2.2)
acorn: 8.17.0 acorn: 8.17.0
astro: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) astro: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
es-module-lexer: 2.3.0 es-module-lexer: 2.3.0
estree-util-visit: 2.0.0 estree-util-visit: 2.0.0
hast-util-to-html: 9.0.5 hast-util-to-html: 9.0.5
@@ -5526,13 +5529,13 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@astrojs/mdx@7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(supports-color@5.5.0)': '@astrojs/mdx@7.0.3(@astrojs/markdown-satteri@0.3.4)(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(supports-color@5.5.0)':
dependencies: dependencies:
'@astrojs/internal-helpers': 0.10.1 '@astrojs/internal-helpers': 0.10.1
'@astrojs/markdown-remark': 7.2.1(supports-color@5.5.0) '@astrojs/markdown-remark': 7.2.1(supports-color@5.5.0)
'@mdx-js/mdx': 3.1.1(supports-color@5.5.0) '@mdx-js/mdx': 3.1.1(supports-color@5.5.0)
acorn: 8.17.0 acorn: 8.17.0
astro: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) astro: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
es-module-lexer: 2.3.0 es-module-lexer: 2.3.0
estree-util-visit: 2.0.0 estree-util-visit: 2.0.0
hast-util-to-html: 9.0.5 hast-util-to-html: 9.0.5
@@ -5559,14 +5562,14 @@ snapshots:
is-docker: 4.0.0 is-docker: 4.0.0
package-manager-detector: 1.7.0 package-manager-detector: 1.7.0
'@astrojs/vercel@11.0.5(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(next@16.2.10(@babel/core@7.29.7(supports-color@10.2.2))(@opentelemetry/api@1.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.102.0))(react@19.2.7)(supports-color@10.2.2)(ws@8.21.0)': '@astrojs/vercel@11.0.5(astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))(next@16.2.10(@babel/core@7.29.7(supports-color@10.2.2))(@opentelemetry/api@1.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.102.0))(react@19.2.7)(supports-color@10.2.2)(ws@8.21.0)':
dependencies: dependencies:
'@astrojs/internal-helpers': 0.10.2 '@astrojs/internal-helpers': 0.10.2
'@vercel/analytics': 1.6.1(next@16.2.10(@babel/core@7.29.7(supports-color@10.2.2))(@opentelemetry/api@1.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.102.0))(react@19.2.7) '@vercel/analytics': 1.6.1(next@16.2.10(@babel/core@7.29.7(supports-color@10.2.2))(@opentelemetry/api@1.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.102.0))(react@19.2.7)
'@vercel/functions': 3.9.1(ws@8.21.0) '@vercel/functions': 3.9.5(ws@8.21.0)
'@vercel/nft': 1.10.2(supports-color@10.2.2) '@vercel/nft': 1.10.2(supports-color@10.2.2)
'@vercel/routing-utils': 5.3.3 '@vercel/routing-utils': 5.3.3
astro: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) astro: 7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
esbuild: 0.28.1 esbuild: 0.28.1
tinyglobby: 0.2.17 tinyglobby: 0.2.17
transitivePeerDependencies: transitivePeerDependencies:
@@ -6870,7 +6873,7 @@ snapshots:
next: 16.2.10(@babel/core@7.29.7(supports-color@10.2.2))(@opentelemetry/api@1.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.102.0) next: 16.2.10(@babel/core@7.29.7(supports-color@10.2.2))(@opentelemetry/api@1.9.0)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(sass@1.102.0)
react: 19.2.7 react: 19.2.7
'@vercel/cli-config@0.2.2': '@vercel/cli-config@0.2.4':
dependencies: dependencies:
xdg-app-paths: 5.5.1 xdg-app-paths: 5.5.1
zod: 4.1.11 zod: 4.1.11
@@ -6879,9 +6882,9 @@ snapshots:
dependencies: dependencies:
execa: 5.1.1 execa: 5.1.1
'@vercel/functions@3.9.1(ws@8.21.0)': '@vercel/functions@3.9.5(ws@8.21.0)':
dependencies: dependencies:
'@vercel/oidc': 3.8.2 '@vercel/oidc': 3.8.5
optionalDependencies: optionalDependencies:
ws: 8.21.0 ws: 8.21.0
@@ -6904,9 +6907,9 @@ snapshots:
- rollup - rollup
- supports-color - supports-color
'@vercel/oidc@3.8.2': '@vercel/oidc@3.8.5':
dependencies: dependencies:
'@vercel/cli-config': 0.2.2 '@vercel/cli-config': 0.2.4
'@vercel/cli-exec': 1.0.1 '@vercel/cli-exec': 1.0.1
jose: 5.10.0 jose: 5.10.0
@@ -7138,7 +7141,7 @@ snapshots:
astring@1.9.0: {} astring@1.9.0: {}
astro@7.1.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0): astro@7.1.5(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0):
dependencies: dependencies:
'@astrojs/compiler-rs': 0.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) '@astrojs/compiler-rs': 0.3.1(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)
'@astrojs/internal-helpers': 0.10.2 '@astrojs/internal-helpers': 0.10.2
@@ -7187,7 +7190,7 @@ snapshots:
tinyglobby: 0.2.17 tinyglobby: 0.2.17
ultrahtml: 1.7.0 ultrahtml: 1.7.0
unifont: 0.7.4 unifont: 0.7.4
unstorage: 1.17.5(@vercel/functions@3.9.1(ws@8.21.0)) unstorage: 1.17.5(@vercel/functions@3.9.5(ws@8.21.0))
vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
vitefu: 1.1.3(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)) vitefu: 1.1.3(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))
xxhash-wasm: 1.1.0 xxhash-wasm: 1.1.0
@@ -7230,7 +7233,7 @@ snapshots:
- uploadthing - uploadthing
- yaml - yaml
astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.1(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0): astro@7.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@26.1.1)(@vercel/functions@3.9.5(ws@8.21.0))(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0):
dependencies: dependencies:
'@astrojs/compiler-rs': 0.3.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) '@astrojs/compiler-rs': 0.3.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)
'@astrojs/internal-helpers': 0.10.2 '@astrojs/internal-helpers': 0.10.2
@@ -7279,7 +7282,7 @@ snapshots:
tinyglobby: 0.2.17 tinyglobby: 0.2.17
ultrahtml: 1.7.0 ultrahtml: 1.7.0
unifont: 0.7.4 unifont: 0.7.4
unstorage: 1.17.5(@vercel/functions@3.9.1(ws@8.21.0)) unstorage: 1.17.5(@vercel/functions@3.9.5(ws@8.21.0))
vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0) vite: 8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)
vitefu: 1.1.3(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0)) vitefu: 1.1.3(vite@8.1.3(@types/node@26.1.1)(esbuild@0.28.1)(sass@1.102.0)(terser@5.49.0)(tsx@4.23.1)(yaml@2.9.0))
xxhash-wasm: 1.1.0 xxhash-wasm: 1.1.0
@@ -10568,7 +10571,7 @@ snapshots:
universalify@2.0.1: {} universalify@2.0.1: {}
unstorage@1.17.5(@vercel/functions@3.9.1(ws@8.21.0)): unstorage@1.17.5(@vercel/functions@3.9.5(ws@8.21.0)):
dependencies: dependencies:
anymatch: 3.1.3 anymatch: 3.1.3
chokidar: 5.0.0 chokidar: 5.0.0
@@ -10579,7 +10582,7 @@ snapshots:
ofetch: 1.5.1 ofetch: 1.5.1
ufo: 1.6.4 ufo: 1.6.4
optionalDependencies: optionalDependencies:
'@vercel/functions': 3.9.1(ws@8.21.0) '@vercel/functions': 3.9.5(ws@8.21.0)
update-browserslist-db@1.2.3(browserslist@4.28.7): update-browserslist-db@1.2.3(browserslist@4.28.7):
dependencies: dependencies: