mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Add llms-full.txt and AI-readability signals to the docs (#2911)
This commit is contained in:
1 parent
dbf2663efe
commit
73f7c2a80b
16 files changed
+341
-97
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@tabler/docs": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Added `Accept: text/markdown` content negotiation for docs pages, with q-value parsing and `406` responses.
|
||||||
@@ -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
@@ -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.
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
@@ -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`)
|
||||||
@@ -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' },
|
||||||
|
}
|
||||||
@@ -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
@@ -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",
|
||||||
|
|||||||
@@ -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 />
|
||||||
|
|||||||
@@ -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',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
|
|
||||||
|
|||||||
@@ -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 ? '' : ' /'}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
|||||||
@@ -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" }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
Generated
+34
-31
@@ -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:
|
||||||
|
|||||||
Reference in new issue
Block a user