diff --git a/apps/ui-library/.gitignore b/apps/ui-library/.gitignore index 5c561252b650f..cde9a85b74111 100644 --- a/apps/ui-library/.gitignore +++ b/apps/ui-library/.gitignore @@ -38,4 +38,8 @@ next-env.d.ts .contentlayer # Auto-generated on every Vercel build by `pnpm build:llms` -> scripts/build-llms-txt.ts -public/llms.txt \ No newline at end of file +public/llms.txt + +# Generated page markdown, including the slug allowlist imported by middleware. +# Regenerated by `pnpm build:markdown` during predev and build. +public/markdown/ diff --git a/apps/ui-library/app/(app)/docs/[[...slug]]/page.tsx b/apps/ui-library/app/(app)/docs/[[...slug]]/page.tsx index aae43476baf5b..f075c729a2218 100644 --- a/apps/ui-library/app/(app)/docs/[[...slug]]/page.tsx +++ b/apps/ui-library/app/(app)/docs/[[...slug]]/page.tsx @@ -41,10 +41,17 @@ export async function generateMetadata(props: DocPageProps): Promise { return {} } + const markdownPath = `${process.env.NEXT_PUBLIC_BASE_PATH ?? '/library'}/docs/${doc.slugAsParams}.md` + const metadata: Metadata = { ...mainMetadata, title: doc.title, description: doc.description, + alternates: { + types: { + 'text/markdown': `https://supabase.com${markdownPath}`, + }, + }, openGraph: { ...mainMetadata.openGraph, title: doc.title, diff --git a/apps/ui-library/app/api/docs-md/[...slug]/route.ts b/apps/ui-library/app/api/docs-md/[...slug]/route.ts new file mode 100644 index 0000000000000..69fa269f7b0e9 --- /dev/null +++ b/apps/ui-library/app/api/docs-md/[...slug]/route.ts @@ -0,0 +1,43 @@ +import { promises as fs } from 'node:fs' +import path from 'node:path' +import { NextResponse } from 'next/server' + +export async function GET(_request: Request, { params }: { params: Promise<{ slug: string[] }> }) { + const { slug } = await params + const baseDir = path.join(process.cwd(), 'public/markdown/docs') + const filePath = path.join(baseDir, `${slug.join('/')}.md`) + + if (!filePath.startsWith(baseDir + path.sep) && filePath !== baseDir) { + return markdownNotFound(slug) + } + + try { + const content = await fs.readFile(filePath, 'utf-8') + return new NextResponse(content, { + headers: { + 'Content-Type': 'text/markdown; charset=utf-8', + 'Cache-Control': 'public, max-age=86400, stale-while-revalidate=3600', + Vary: 'Accept', + }, + }) + } catch { + return markdownNotFound(slug) + } +} + +function markdownNotFound(slug: string[]) { + const pagePath = slug.join('/') + const markdown = `# 404 - Page Not Found + +The page \`/library/docs/${pagePath}.md\` does not exist. + +See also: [Supabase Library](https://supabase.com/library/llms.txt) +` + return new NextResponse(markdown, { + status: 404, + headers: { + 'Content-Type': 'text/markdown; charset=utf-8', + 'Cache-Control': 'no-store', + }, + }) +} diff --git a/apps/ui-library/lib/install-command.ts b/apps/ui-library/lib/install-command.ts new file mode 100644 index 0000000000000..39185f6fa3a15 --- /dev/null +++ b/apps/ui-library/lib/install-command.ts @@ -0,0 +1,44 @@ +export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun' +export type ShadcnFramework = 'react' | 'vue' + +export function getShadcnFramework(name: string): ShadcnFramework { + return name.includes('vue') || name.includes('nuxtjs') ? 'vue' : 'react' +} + +export function getRegistryBaseUrl(env = process.env.NEXT_PUBLIC_VERCEL_TARGET_ENV): string { + if (env === 'production') { + // Special alias for production, added in https://github.com/shadcn-ui/ui/pull/8161 + return '@supabase' + } + if (env === 'preview') { + return `https://${process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL}` + } + return 'http://localhost:3004' +} + +export function getRegistryComponentPath( + name: string, + env = process.env.NEXT_PUBLIC_VERCEL_TARGET_ENV +): string { + if (env === 'production') { + return `/${name}` + } + return `${process.env.NEXT_PUBLIC_BASE_PATH ?? ''}/r/${name}.json` +} + +export function getInstallCommands( + name: string, + options?: { framework?: ShadcnFramework; production?: boolean } +): Record { + const framework = options?.framework ?? getShadcnFramework(name) + const env = options?.production ? 'production' : process.env.NEXT_PUBLIC_VERCEL_TARGET_ENV + const specifier = `${getRegistryBaseUrl(env)}${getRegistryComponentPath(name, env)}` + const cli = framework === 'vue' ? 'shadcn-vue@latest' : 'shadcn@latest' + + return { + npm: `npx ${cli} add ${specifier}`, + pnpm: `pnpm dlx ${cli} add ${specifier}`, + yarn: `yarn dlx ${cli} add ${specifier}`, + bun: `bunx --bun ${cli} add ${specifier}`, + } +} diff --git a/apps/ui-library/middleware.test.ts b/apps/ui-library/middleware.test.ts new file mode 100644 index 0000000000000..5c66568997472 --- /dev/null +++ b/apps/ui-library/middleware.test.ts @@ -0,0 +1,50 @@ +import assert from 'node:assert/strict' +import { describe, it } from 'node:test' +import { NextRequest } from 'next/server' + +import { middleware } from './middleware' + +const DOCS_URL = 'https://supabase.com/library/docs/nextjs/client' + +function request(url: string, headers: Record) { + return new NextRequest(new Request(url, { headers })) +} + +describe('middleware markdown negotiation', () => { + it('rewrites to the markdown route when Accept prefers markdown', () => { + const response = middleware(request(DOCS_URL, { accept: 'text/markdown' })) + + assert.equal( + response.headers.get('x-middleware-rewrite'), + 'https://supabase.com/library/api/docs-md/nextjs/client' + ) + }) + + it('406s when Accept rejects both html and markdown', () => { + const response = middleware(request(DOCS_URL, { accept: 'application/json' })) + + assert.equal(response.status, 406) + }) + + it('passes Server Action requests through untouched', () => { + // Server Actions POST to the page URL with `Accept: text/x-component`. + const response = middleware( + request(DOCS_URL, { + accept: 'text/x-component', + 'next-action': '7f1e0c0d5a1b2c3d4e5f60718293a4b5c6d7e8f900', + }) + ) + + assert.equal(response.status, 200) + assert.equal(response.headers.get('x-middleware-rewrite'), null) + }) + + it('serves html to browsers', () => { + const response = middleware( + request(DOCS_URL, { accept: 'text/html,application/xhtml+xml,*/*;q=0.8' }) + ) + + assert.equal(response.status, 200) + assert.equal(response.headers.get('x-middleware-rewrite'), null) + }) +}) diff --git a/apps/ui-library/middleware.ts b/apps/ui-library/middleware.ts new file mode 100644 index 0000000000000..6e89fd8590500 --- /dev/null +++ b/apps/ui-library/middleware.ts @@ -0,0 +1,50 @@ +import { negotiateMarkdown } from 'common/markdown-negotiation' +import { NextResponse, type NextRequest } from 'next/server' + +import MARKDOWN_SLUGS from '@/public/markdown/manifest.json' + +const BASE_PATH = process.env.NEXT_PUBLIC_BASE_PATH ?? '/library' +const DOCS_PATH = `${BASE_PATH}/docs` +const MARKDOWN_SLUG_SET = new Set(MARKDOWN_SLUGS) + +export function middleware(request: NextRequest) { + const url = new URL(request.url) + const { pathname } = url + + if (!pathname.startsWith(`${DOCS_PATH}/`)) { + return NextResponse.next() + } + + // Server Actions POST to the page URL with `Accept: text/x-component`, which + // matches none of the types this route negotiates and would 406. Let Next.js + // handle them. + if (request.headers.get('next-action')) { + return NextResponse.next() + } + + const isMdSuffix = pathname.endsWith('.md') + const slug = pathname.replace(`${DOCS_PATH}/`, '').replace(/\.md$/, '') + const decision = negotiateMarkdown( + { acceptHeader: request.headers.get('accept') ?? '' }, + { hasMarkdownVariant: MARKDOWN_SLUG_SET.has(slug), isMarkdownSuffix: isMdSuffix } + ) + + if (decision === 'not-acceptable') { + return new NextResponse('Not Acceptable', { + status: 406, + headers: { 'Cache-Control': 'no-store', Vary: 'Accept' }, + }) + } + + if (decision === 'markdown') { + const rewriteUrl = new URL(url) + rewriteUrl.pathname = `${BASE_PATH}/api/docs-md/${slug}` + return NextResponse.rewrite(rewriteUrl) + } + + return NextResponse.next() +} + +export const config = { + matcher: ['/docs/:path*'], +} diff --git a/apps/ui-library/next.config.mjs b/apps/ui-library/next.config.mjs index 24035a3e7cb55..54230c314b569 100644 --- a/apps/ui-library/next.config.mjs +++ b/apps/ui-library/next.config.mjs @@ -12,6 +12,9 @@ const nextConfig = { }, }, }, + outputFileTracingIncludes: { + '/api/docs-md/**/*': ['./public/markdown/docs/**/*'], + }, async redirects() { return [ ...(process.env.NEXT_PUBLIC_BASE_PATH?.length diff --git a/apps/ui-library/package.json b/apps/ui-library/package.json index 7c3873babad69..db1a5f1b20844 100644 --- a/apps/ui-library/package.json +++ b/apps/ui-library/package.json @@ -6,9 +6,13 @@ "scripts": { "preinstall": "npx only-allow pnpm", "dev": "next dev --port 3004", - "build": "pnpm run content:build && pnpm run build:registry && pnpm run build:llms && pnpm run build:app", + "predev": "pnpm run build:markdown", + "build": "pnpm run content:build && pnpm run build:registry && pnpm run build:markdown && pnpm run build:llms && pnpm run build:app", "build:registry": "rimraf -G public/r/* && tsx ./scripts/build-registry.mts && shadcn build public/r/registry.json && tsx scripts/clean-registry.ts", + "build:markdown": "tsx ./scripts/build-markdown.ts", "build:llms": "tsx ./scripts/build-llms-txt.ts", + "test:markdown": "tsx --test scripts/library-mdx-to-markdown.test.ts", + "test:middleware": "pnpm run build:markdown && tsx --test middleware.test.ts", "build:app": "next build --turbopack", "start": "next start", "lint": "eslint .", @@ -78,12 +82,21 @@ "@tanstack/react-start": "catalog:", "@types/common-tags": "^1.8.4", "@types/lodash": "^4.17.16", + "@types/mdast": "^3.0.15", "@types/react": "catalog:", "@types/react-dom": "catalog:", "@typescript/native": "catalog:", "config": "workspace:^", + "gray-matter": "^4.0.3", "lodash": "catalog:", + "mdast-util-from-markdown": "^1.3.1", + "mdast-util-gfm": "^2.0.2", + "mdast-util-mdx": "^2.0.1", + "mdast-util-mdx-jsx": "^2.1.4", + "mdast-util-to-markdown": "^1.5.0", "mdast-util-toc": "^6.1.1", + "micromark-extension-gfm": "^2.0.3", + "micromark-extension-mdxjs": "^1.0.1", "postcss": "catalog:", "react-dropzone": "^14.3.8", "react-router": "^7.13.2", diff --git a/apps/ui-library/scripts/build-llms-txt.ts b/apps/ui-library/scripts/build-llms-txt.ts index a3c533d2c38a1..9ef7647916d33 100644 --- a/apps/ui-library/scripts/build-llms-txt.ts +++ b/apps/ui-library/scripts/build-llms-txt.ts @@ -81,14 +81,14 @@ let content = `# Supabase Library Last updated: ${new Date().toISOString()} ## Overview -Library of components for your project. The components integrate with Supabase and are shadcn compatible. +Library of components for your project. The components integrate with Supabase and are shadcn compatible. Each docs page is also available as markdown for agents (append .md to the URL). ## Docs ` // Add documentation links for (const doc of docs) { - const url = `${BASE_URL}/${doc.path}` + const url = `${BASE_URL}/${doc.path}.md` content += `- [${doc.title}](${url})` if (doc.description) { content += `\n - ${doc.description}` diff --git a/apps/ui-library/scripts/build-markdown.ts b/apps/ui-library/scripts/build-markdown.ts new file mode 100644 index 0000000000000..447f6259a6199 --- /dev/null +++ b/apps/ui-library/scripts/build-markdown.ts @@ -0,0 +1,65 @@ +import fs from 'node:fs/promises' +import path from 'node:path' + +import { transformLibraryMdx } from './library-mdx-to-markdown' + +const CONTENT_DIR = path.join(process.cwd(), 'content', 'docs') +const OUTPUT_DIR = path.join(process.cwd(), 'public', 'markdown', 'docs') +const MANIFEST_PATH = path.join(process.cwd(), 'public', 'markdown', 'manifest.json') + +async function collectMdxFiles(dir: string): Promise { + const entries = await fs.readdir(dir, { withFileTypes: true }) + const files: string[] = [] + + for (const entry of entries) { + const fullPath = path.join(dir, entry.name) + if (entry.isDirectory()) { + files.push(...(await collectMdxFiles(fullPath))) + } else if (entry.name.endsWith('.mdx')) { + files.push(fullPath) + } + } + + return files.sort((a, b) => a.localeCompare(b)) +} + +async function generate() { + const sources = await collectMdxFiles(CONTENT_DIR) + const slugs: string[] = [] + + // Wipe first so pages that were renamed or deleted don't leave stale markdown + // behind — public/markdown is served directly, and the files outlive the manifest. + await fs.rm(OUTPUT_DIR, { recursive: true, force: true }) + await fs.mkdir(OUTPUT_DIR, { recursive: true }) + + for (const sourceFile of sources) { + const relativePath = path.relative(CONTENT_DIR, sourceFile) + const slug = relativePath.replace(/\.mdx$/, '').replace(/\\/g, '/') + const outPath = path.join(OUTPUT_DIR, `${slug}.md`) + const raw = await fs.readFile(sourceFile, 'utf8') + + let output: string + try { + output = transformLibraryMdx(raw) + } catch (err) { + throw new Error( + `Failed to process ${sourceFile}: ${err instanceof Error ? err.message : err}`, + { cause: err } + ) + } + + await fs.mkdir(path.dirname(outPath), { recursive: true }) + await fs.writeFile(outPath, output) + slugs.push(slug) + } + + await fs.mkdir(path.dirname(MANIFEST_PATH), { recursive: true }) + await fs.writeFile(MANIFEST_PATH, `${JSON.stringify(slugs, null, 2)}\n`) + + console.log(`Generated ${slugs.length} markdown files under public/markdown/docs/`) +} + +generate().catch((error) => { + console.error(error) + process.exit(1) +}) diff --git a/apps/ui-library/scripts/library-mdx-to-markdown.test.ts b/apps/ui-library/scripts/library-mdx-to-markdown.test.ts new file mode 100644 index 0000000000000..d8de6abd293a7 --- /dev/null +++ b/apps/ui-library/scripts/library-mdx-to-markdown.test.ts @@ -0,0 +1,98 @@ +import assert from 'node:assert/strict' +import { describe, it } from 'node:test' + +import { transformLibraryMdx } from './library-mdx-to-markdown' + +describe('transformLibraryMdx', () => { + it('lifts title and description into a markdown header', () => { + const output = transformLibraryMdx(`--- +title: Password-based Authentication +description: Password-based authentication block for Next.js +--- + +Hello world. +`) + + assert.match( + output, + /^# Password-based Authentication\n\nPassword-based authentication block for Next.js\n\nHello world.\n$/ + ) + }) + + it('replaces BlockItem with a production shadcn install command', () => { + const output = transformLibraryMdx(`--- +title: Auth +description: Auth block +--- + + +`) + + assert.match( + output, + /```bash\nnpx shadcn@latest add @supabase\/password-based-auth-nextjs\n```/ + ) + }) + + it('uses shadcn-vue for Vue and Nuxt blocks', () => { + const output = transformLibraryMdx(`--- +title: Dropzone +description: Vue dropzone +--- + + +`) + + assert.match(output, /npx shadcn-vue@latest add @supabase\/dropzone-vue/) + }) + + it('keeps usage copy and omits interactive previews', () => { + const output = transformLibraryMdx(`--- +title: Auth +description: Auth block +--- + + + +## Usage + +Set \`NEXT_PUBLIC_SUPABASE_URL\` in \`.env.local\`. + +This client is built for SSR. +`) + + assert.doesNotMatch(output, /BlockPreview/) + assert.match(output, /## Usage/) + assert.match(output, /NEXT_PUBLIC_SUPABASE_URL/) + assert.match(output, /Warning: This client is built for SSR\./) + }) + + it('rewrites library docs links to absolute markdown URLs', () => { + const output = transformLibraryMdx(`--- +title: Client +description: Client +--- + +See the [React client](/library/docs/react/client). +`) + + assert.match(output, /https:\/\/supabase\.com\/library\/docs\/react\/client\.md/) + }) + + it('rewrites documentation links nested inside components', () => { + const output = transformLibraryMdx(`--- +title: Auth +description: Auth block +--- + + +See the [React client](/library/docs/react/client) before installing. + +`) + + assert.match( + output, + /Note: See the \[React client\]\(https:\/\/supabase\.com\/library\/docs\/react\/client\.md\) before installing\./ + ) + }) +}) diff --git a/apps/ui-library/scripts/library-mdx-to-markdown.ts b/apps/ui-library/scripts/library-mdx-to-markdown.ts new file mode 100644 index 0000000000000..352435f490922 --- /dev/null +++ b/apps/ui-library/scripts/library-mdx-to-markdown.ts @@ -0,0 +1,109 @@ +import matter from 'gray-matter' +import type { Content, Parent, Root } from 'mdast' +import { fromMarkdown } from 'mdast-util-from-markdown' +import { gfmFromMarkdown, gfmToMarkdown } from 'mdast-util-gfm' +import { mdxFromMarkdown, mdxToMarkdown } from 'mdast-util-mdx' +import type { MdxJsxFlowElement, MdxJsxTextElement } from 'mdast-util-mdx-jsx' +import { toMarkdown } from 'mdast-util-to-markdown' +import { gfm } from 'micromark-extension-gfm' +import { mdxjs } from 'micromark-extension-mdxjs' +import { visit } from 'unist-util-visit' + +import { markdownSchema } from './markdown-schema' + +type JsxNode = MdxJsxFlowElement | MdxJsxTextElement +type ComponentHandler = (ctx: { + props: Record + children: string + node: JsxNode +}) => string + +const PARSE_OPTIONS = { + extensions: [mdxjs(), gfm()], + mdastExtensions: [mdxFromMarkdown(), gfmFromMarkdown()], +} +const SERIALIZE_OPTIONS = { + extensions: [mdxToMarkdown(), gfmToMarkdown()], + bullet: '-' as const, + listItemIndent: 'one' as const, +} + +const parseMdx = (source: string): Root => fromMarkdown(source, PARSE_OPTIONS) +const serializeMdx = (tree: Parent): string => toMarkdown(tree as Root, SERIALIZE_OPTIONS) + +const defaultHandler: ComponentHandler = ({ children }) => children + +const isJsx = (n: Content): n is JsxNode => + n.type === 'mdxJsxFlowElement' || n.type === 'mdxJsxTextElement' + +function propsFrom(node: JsxNode): Record { + const props: Record = {} + for (const attr of node.attributes) { + if (attr.type !== 'mdxJsxAttribute') continue + if (attr.value == null) props[attr.name] = true + else if (typeof attr.value === 'string') props[attr.name] = attr.value + else props[attr.name] = attr.value.value + } + return props +} + +function applySchema(parent: Parent, schema: Record): void { + for (const child of parent.children as Content[]) { + if ('children' in child) applySchema(child as Parent, schema) + } + const next: Content[] = [] + for (const child of parent.children as Content[]) { + if ( + child.type === 'mdxFlowExpression' || + child.type === 'mdxTextExpression' || + child.type === 'mdxjsEsm' + ) { + continue + } + if (isJsx(child)) { + const handler = schema[child.name ?? ''] ?? defaultHandler + const children = serializeMdx({ + type: 'root', + children: child.children as Root['children'], + }).trim() + const value = handler({ props: propsFrom(child), children, node: child }) + if (value) { + next.push({ type: 'html', value } as Content) + } + continue + } + next.push(child) + } + parent.children = next as Parent['children'] +} + +function rewriteLibraryLinks(tree: Root): void { + visit(tree, 'link', (node) => { + if (!node.url.startsWith('/')) return + if (node.url.startsWith('//')) return + + if (node.url.startsWith('/library/docs/')) { + const [pathname, hash] = node.url.split('#') + const withMd = pathname.endsWith('.md') ? pathname : `${pathname}.md` + node.url = `https://supabase.com${withMd}${hash ? `#${hash}` : ''}` + return + } + + node.url = `https://supabase.com${node.url}` + }) +} + +export function transformLibraryMdx(raw: string): string { + const { content, data } = matter(raw) + const tree = parseMdx(content) + rewriteLibraryLinks(tree) + applySchema(tree, markdownSchema) + const body = serializeMdx(tree).trim() + + const headerParts: string[] = [] + if (data.title) headerParts.push(`# ${String(data.title)}`) + if (data.description) headerParts.push(String(data.description)) + + const header = headerParts.join('\n\n') + return `${header ? `${header}\n\n${body}` : body}\n` +} diff --git a/apps/ui-library/scripts/markdown-schema.ts b/apps/ui-library/scripts/markdown-schema.ts new file mode 100644 index 0000000000000..f61f37a15277a --- /dev/null +++ b/apps/ui-library/scripts/markdown-schema.ts @@ -0,0 +1,129 @@ +import path from 'node:path' + +import { getInstallCommands } from '../lib/install-command' +import { generateRegistryTree, type RegistryNode } from '../lib/process-registry' + +type HandlerContext = { + props: Record + children: string +} + +type ComponentHandler = (ctx: HandlerContext) => string + +const omit: ComponentHandler = () => '' +const unwrap: ComponentHandler = ({ children }) => children + +function toAgentHref(href: string): string { + if (!href) return href + if (href.startsWith('/library/docs/')) { + const [pathname, hash] = href.split('#') + const withMd = pathname.endsWith('.md') ? pathname : `${pathname}.md` + return `https://supabase.com${withMd}${hash ? `#${hash}` : ''}` + } + if (href.startsWith('/') && !href.startsWith('//')) { + return `https://supabase.com${href}` + } + return href +} + +function BlockItem({ props }: HandlerContext): string { + const name = String(props.name ?? '') + if (!name) return '' + const command = getInstallCommands(name, { production: true }).npm + return ['Install this block:', '', '```bash', command, '```'].join('\n') +} + +function RegistryBlock({ props }: HandlerContext): string { + const itemName = String(props.itemName ?? '') + if (!itemName) return '' + + const registryPath = path.join(process.cwd(), 'public', 'r', `${itemName}.json`) + let listing = '' + try { + const tree = generateRegistryTree(registryPath) + listing = formatTree(tree) + } catch { + listing = '' + } + + const registryUrl = `https://supabase.com/library/r/${itemName}.json` + const parts = [listing, listing ? '' : null, `Full source: ${registryUrl}`].filter( + (part) => part !== null + ) + + return parts.join('\n').trim() +} + +function formatTree(nodes: RegistryNode[], indent = 0): string { + return nodes + .map((node) => { + const prefix = `${' '.repeat(indent)}- \`${node.name}${node.type === 'directory' ? '/' : ''}\`` + const children = node.children?.length ? `\n${formatTree(node.children, indent + 1)}` : '' + return `${prefix}${children}` + }) + .join('\n') +} + +function Callout({ props, children }: HandlerContext): string { + const type = String(props.type ?? 'note') + const label = type.charAt(0).toUpperCase() + type.slice(1) + return `${label}: ${children}`.trim() +} + +function AccordionTrigger({ children }: HandlerContext): string { + const title = children.trim() + return title ? `**${title}**` : '' +} + +function LinkedCard({ props, children }: HandlerContext): string { + const href = toAgentHref(String(props.href ?? '')) + const label = children.replace(/\s+/g, ' ').trim() + return href ? `- [${label || href}](${href})` : label +} + +function ComponentPreview({ props }: HandlerContext): string { + const description = String(props.description ?? '').trim() + return description +} + +function TanStackBeta(): string { + return 'Note: TanStack Start support is in beta. APIs may change.' +} + +function TanstackDBGenerator(): string { + return [ + 'This block is generated from your project schema.', + 'Open the HTML page to log in and generate an install command:', + 'https://supabase.com/library/docs/nextjs/tanstack-db', + ].join('\n') +} + +function Anchor({ props, children }: HandlerContext): string { + const href = toAgentHref(String(props.href ?? '')) + return href ? `[${children}](${href})` : children +} + +export const markdownSchema: Record = { + BlockItem, + RegistryBlock, + Callout, + Accordion: unwrap, + AccordionItem: unwrap, + AccordionTrigger, + AccordionContent: unwrap, + Card: unwrap, + LinkedCard, + ComponentPreview, + BlockPreview: omit, + DualRealtimeChat: omit, + DualRealtimeFlow: omit, + DualRealtimeMonaco: omit, + RealtimeMonaco: omit, + TanStackBeta, + TanstackDBGenerator, + CopyButton: omit, + svg: omit, + path: omit, + title: omit, + a: Anchor, +} diff --git a/apps/ui-library/turbo.jsonc b/apps/ui-library/turbo.jsonc index dfc1eabc693d9..48c543af28efa 100644 --- a/apps/ui-library/turbo.jsonc +++ b/apps/ui-library/turbo.jsonc @@ -25,7 +25,13 @@ "SUPABASE_MANAGEMENT_API_TOKEN", "OPENAI_API_KEY", ], - "outputs": [".next/**", "!.next/cache/**", "!.next/dev/**/*", ".contentlayer/**"], + "outputs": [ + ".next/**", + "!.next/cache/**", + "!.next/dev/**/*", + ".contentlayer/**", + "public/markdown/**", + ], }, }, } diff --git a/apps/ui-library/types/manifest.d.ts b/apps/ui-library/types/manifest.d.ts new file mode 100644 index 0000000000000..b5d056b02e2d0 --- /dev/null +++ b/apps/ui-library/types/manifest.d.ts @@ -0,0 +1,6 @@ +// public/markdown/manifest.json is generated by scripts/build-markdown.ts +// and gitignored, so it may not exist on disk when tsc runs. +declare module '@/public/markdown/manifest.json' { + const slugs: string[] + export = slugs +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b772ab3ff074b..eb78095c2ce11 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -596,7 +596,7 @@ importers: version: 7.29.7(supports-color@8.1.1) '@graphiql/toolkit': specifier: ^0.9.1 - version: 0.9.1(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0) + version: 0.9.1(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0) '@graphql-codegen/cli': specifier: 5.0.5 version: 5.0.5(@parcel/watcher@2.5.6)(@types/node@22.13.14)(encoding@0.1.13)(graphql-sock@1.0.1(graphql@16.11.0))(graphql@16.11.0)(supports-color@8.1.1)(typescript@6.0.2) @@ -677,7 +677,7 @@ importers: version: 13.2.2 graphiql: specifier: ^4.0.2 - version: 4.0.2(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 4.0.2(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) npm-run-all: specifier: ^4.1.5 version: 4.1.5 @@ -865,7 +865,7 @@ importers: dependencies: '@react-router/fs-routes': specifier: ^7.17.0 - version: 7.17.0(@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2) + version: 7.17.0(@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.33.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2) '@react-router/node': specifier: ^7.17.0 version: 7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) @@ -893,7 +893,7 @@ importers: devDependencies: '@react-router/dev': specifier: ^7.17.0 - version: 7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) + version: 7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.33.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) '@tailwindcss/vite': specifier: 4.2.4 version: 4.2.4(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0)) @@ -1634,6 +1634,9 @@ importers: '@types/lodash': specifier: ^4.17.16 version: 4.17.16 + '@types/mdast': + specifier: ^3.0.15 + version: 3.0.15 '@types/react': specifier: 'catalog:' version: 19.2.14 @@ -1646,12 +1649,36 @@ importers: config: specifier: workspace:^ version: link:../../packages/config + gray-matter: + specifier: ^4.0.3 + version: 4.0.3 lodash: specifier: ^4.18.1 version: 4.18.1 + mdast-util-from-markdown: + specifier: ^1.3.1 + version: 1.3.1(supports-color@8.1.1) + mdast-util-gfm: + specifier: ^2.0.2 + version: 2.0.2(supports-color@8.1.1) + mdast-util-mdx: + specifier: ^2.0.1 + version: 2.0.1(supports-color@8.1.1) + mdast-util-mdx-jsx: + specifier: ^2.1.4 + version: 2.1.4(supports-color@8.1.1) + mdast-util-to-markdown: + specifier: ^1.5.0 + version: 1.5.0 mdast-util-toc: specifier: ^6.1.1 version: 6.1.1 + micromark-extension-gfm: + specifier: ^2.0.3 + version: 2.0.3 + micromark-extension-mdxjs: + specifier: ^1.0.1 + version: 1.0.1 postcss: specifier: ^8.5.18 version: 8.5.22 @@ -9814,11 +9841,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -10730,6 +10752,7 @@ packages: configcat-common@9.3.1: resolution: {integrity: sha512-yVkIbluksD/kZfVyKjLIOpwLrq3/ZRM7Lwrsz89JmbpQ6VtbnelrTQynSPElTtKjrPRZx56v3IZYk3nWTnnM6A==} + deprecated: Official support for this package has ended. Please migrate to @configcat/sdk. For more information, see https://github.com/configcat/js-unified-sdk#getting-started configcat-js@9.5.1: resolution: {integrity: sha512-M7ZPMtS+wCJLsFwcMkXa/ka+r/uEbN5MYS1FEnnlM2cohvpR2vpvvSMe0fuhc83HDgXJari08LyRXay0k0S80g==} @@ -12861,9 +12884,6 @@ packages: htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} @@ -15331,9 +15351,6 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-manager-detector@1.3.0: - resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} - package-manager-detector@1.8.0: resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==} @@ -18971,14 +18988,14 @@ snapshots: '@antfu/install-pkg@1.1.0': dependencies: - package-manager-detector: 1.3.0 + package-manager-detector: 1.8.0 tinyexec: 1.2.4 '@antfu/ni@25.0.0': dependencies: ansis: 4.1.0 fzf: 0.5.2 - package-manager-detector: 1.3.0 + package-manager-detector: 1.8.0 tinyexec: 1.2.4 '@antfu/utils@9.2.1': {} @@ -19106,7 +19123,7 @@ snapshots: '@astrojs/internal-helpers@0.10.4': dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 '@types/mdast': 4.0.4 js-yaml: 4.3.1 picomatch: 4.0.5 @@ -19277,17 +19294,17 @@ snapshots: dependencies: '@aws-sdk/types': 3.973.8 '@aws-sdk/xml-builder': 3.972.22 - '@smithy/core': 3.23.17 + '@smithy/core': 3.31.1 '@smithy/node-config-provider': 4.3.14 '@smithy/property-provider': 4.2.14 '@smithy/protocol-http': 5.3.14 '@smithy/signature-v4': 5.3.14 '@smithy/smithy-client': 4.12.13 - '@smithy/types': 4.14.1 + '@smithy/types': 4.16.1 '@smithy/util-base64': 4.3.2 '@smithy/util-middleware': 4.2.14 '@smithy/util-retry': 4.3.8 - '@smithy/util-utf8': 4.2.2 + '@smithy/util-utf8': 4.4.16 tslib: 2.8.1 '@aws-sdk/credential-provider-cognito-identity@3.972.31': @@ -19553,7 +19570,7 @@ snapshots: '@aws-sdk/types@3.973.8': dependencies: - '@smithy/types': 4.14.1 + '@smithy/types': 4.16.1 tslib: 2.8.1 '@aws-sdk/util-arn-parser@3.972.3': @@ -19591,7 +19608,7 @@ snapshots: '@aws-sdk/xml-builder@3.972.22': dependencies: '@nodable/entities': 2.1.0 - '@smithy/types': 4.14.1 + '@smithy/types': 4.16.1 fast-xml-parser: 5.7.2 tslib: 2.8.1 @@ -20665,9 +20682,9 @@ snapshots: '@floating-ui/utils@0.2.9': {} - '@graphiql/plugin-doc-explorer@0.0.1(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@graphiql/plugin-doc-explorer@0.0.1(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@graphiql/react': 0.32.0(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@graphiql/react': 0.32.0(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@headlessui/react': 2.2.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6) graphql: 16.11.0 react: 19.2.6 @@ -20695,10 +20712,10 @@ snapshots: - immer - use-sync-external-store - '@graphiql/plugin-history@0.0.2(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@graphiql/plugin-history@0.0.2(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@graphiql/react': 0.32.0(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@graphiql/toolkit': 0.11.3(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0) + '@graphiql/react': 0.32.0(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@graphiql/toolkit': 0.11.3(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0) react: 19.2.6 react-compiler-runtime: 19.1.0-rc.1(react@19.2.6) react-dom: 19.2.6(react@19.2.6) @@ -20727,9 +20744,9 @@ snapshots: - immer - use-sync-external-store - '@graphiql/react@0.32.0(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@graphiql/react@0.32.0(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: - '@graphiql/toolkit': 0.11.3(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0) + '@graphiql/toolkit': 0.11.3(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0) '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -20797,23 +20814,23 @@ snapshots: transitivePeerDependencies: - '@types/node' - '@graphiql/toolkit@0.11.3(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)': + '@graphiql/toolkit@0.11.3(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)': dependencies: '@n1ru4l/push-pull-async-iterable-iterator': 3.2.0 graphql: 16.11.0 meros: 1.3.0(@types/node@22.13.14) optionalDependencies: - graphql-ws: 6.0.4(graphql@16.11.0)(ws@8.21.0) + graphql-ws: 6.0.4(graphql@16.11.0)(ws@8.21.3) transitivePeerDependencies: - '@types/node' - '@graphiql/toolkit@0.9.1(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)': + '@graphiql/toolkit@0.9.1(@types/node@22.13.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)': dependencies: '@n1ru4l/push-pull-async-iterable-iterator': 3.2.0 graphql: 16.11.0 meros: 1.3.0(@types/node@22.13.14) optionalDependencies: - graphql-ws: 6.0.4(graphql@16.11.0)(ws@8.21.0) + graphql-ws: 6.0.4(graphql@16.11.0)(ws@8.21.3) transitivePeerDependencies: - '@types/node' @@ -23916,7 +23933,7 @@ snapshots: - tsx - yaml - '@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0)': + '@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.33.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0)': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/generator': 7.29.0 @@ -23947,7 +23964,7 @@ snapshots: tinyglobby: 0.2.16 valibot: 1.4.2(typescript@6.0.2) vite: 7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) - vite-node: 3.2.4(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) + vite-node: 3.2.4(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.33.0)(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) optionalDependencies: '@react-router/serve': 7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2) typescript: 6.0.2 @@ -23974,9 +23991,9 @@ snapshots: optionalDependencies: typescript: 6.0.2 - '@react-router/fs-routes@7.17.0(@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2)': + '@react-router/fs-routes@7.17.0(@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.33.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2)': dependencies: - '@react-router/dev': 7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) + '@react-router/dev': 7.17.0(@react-router/serve@7.17.0(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.33.0)(react-router@7.18.2(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) minimatch: 9.0.7 optionalDependencies: typescript: 6.0.2 @@ -24923,11 +24940,11 @@ snapshots: dependencies: '@smithy/is-array-buffer': 4.2.2 '@smithy/protocol-http': 5.3.14 - '@smithy/types': 4.14.1 + '@smithy/types': 4.16.1 '@smithy/util-hex-encoding': 4.2.2 '@smithy/util-middleware': 4.2.14 '@smithy/util-uri-escape': 4.2.2 - '@smithy/util-utf8': 4.2.2 + '@smithy/util-utf8': 4.4.16 tslib: 2.8.1 '@smithy/smithy-client@4.12.13': @@ -27098,10 +27115,6 @@ snapshots: dependencies: acorn: 8.15.0 - acorn-import-attributes@1.9.5(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - acorn-import-attributes@1.9.5(acorn@8.18.0): dependencies: acorn: 8.18.0 @@ -27110,10 +27123,6 @@ snapshots: dependencies: acorn: 8.18.0 - acorn-jsx@5.3.2(acorn@8.14.1): - dependencies: - acorn: 8.14.1 - acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 @@ -27128,12 +27137,10 @@ snapshots: acorn-walk@8.3.4: dependencies: - acorn: 8.16.0 + acorn: 8.18.0 acorn@8.11.3: {} - acorn@8.14.1: {} - acorn@8.15.0: {} acorn@8.16.0: {} @@ -29163,7 +29170,7 @@ snapshots: esast-util-from-estree@2.0.0: dependencies: - '@types/estree-jsx': 1.0.1 + '@types/estree-jsx': 1.0.5 devlop: 1.1.0 estree-util-visit: 2.0.0 unist-util-position-from-estree: 2.0.0 @@ -29568,7 +29575,7 @@ snapshots: estree-util-visit@2.0.0: dependencies: - '@types/estree-jsx': 1.0.1 + '@types/estree-jsx': 1.0.5 '@types/unist': 3.0.3 estree-walker@2.0.2: {} @@ -30296,11 +30303,11 @@ snapshots: graceful-fs@4.2.11: {} - graphiql@4.0.2(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + graphiql@4.0.2(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - '@graphiql/plugin-doc-explorer': 0.0.1(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@graphiql/plugin-history': 0.0.2(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@graphiql/react': 0.32.0(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.0))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@graphiql/plugin-doc-explorer': 0.0.1(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@graphiql/plugin-history': 0.0.2(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@graphiql/react': 0.32.0(@codemirror/language@6.11.0)(@emotion/is-prop-valid@1.4.0)(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3))(graphql@16.11.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) graphql: 16.11.0 react: 19.2.6 react-compiler-runtime: 19.1.0-rc.1(react@19.2.6) @@ -30399,6 +30406,13 @@ snapshots: optionalDependencies: ws: 8.21.0 + graphql-ws@6.0.4(graphql@16.11.0)(ws@8.21.3): + dependencies: + graphql: 16.11.0 + optionalDependencies: + ws: 8.21.3 + optional: true + graphql@16.11.0: {} gray-matter@2.1.1: @@ -30521,7 +30535,7 @@ snapshots: hast-util-from-parse5@8.0.1: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 '@types/unist': 3.0.3 devlop: 1.1.0 hastscript: 8.0.0 @@ -30548,7 +30562,7 @@ snapshots: hast-util-parse-selector@4.0.0: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 hast-util-raw@9.0.1: dependencies: @@ -30623,7 +30637,7 @@ snapshots: hast-util-to-parse5@8.0.0: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 comma-separated-tokens: 2.0.3 devlop: 1.1.0 property-information: 6.3.0 @@ -30660,7 +30674,7 @@ snapshots: hastscript@8.0.0: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 comma-separated-tokens: 2.0.3 hast-util-parse-selector: 4.0.0 property-information: 6.3.0 @@ -30718,8 +30732,6 @@ snapshots: domutils: 3.2.2 entities: 7.0.1 - http-cache-semantics@4.1.1: {} - http-cache-semantics@4.2.0: {} http-errors@2.0.0: @@ -30842,8 +30854,8 @@ snapshots: import-in-the-middle@3.1.0: dependencies: - acorn: 8.16.0 - acorn-import-attributes: 1.9.5(acorn@8.16.0) + acorn: 8.18.0 + acorn-import-attributes: 1.9.5(acorn@8.18.0) cjs-module-lexer: 2.2.0 module-details-from-path: 1.0.4 @@ -31851,7 +31863,7 @@ snapshots: dependencies: '@npmcli/agent': 2.2.2(supports-color@8.1.1) cacache: 18.0.3 - http-cache-semantics: 4.1.1 + http-cache-semantics: 4.2.0 is-lambda: 1.0.1 minipass: 7.1.3 minipass-fetch: 3.0.5 @@ -32591,8 +32603,8 @@ snapshots: micromark-extension-mdxjs@1.0.1: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) micromark-extension-mdx-expression: 1.0.8 micromark-extension-mdx-jsx: 1.0.5 micromark-extension-mdx-md: 1.0.1 @@ -32602,8 +32614,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) micromark-extension-mdx-expression: 3.0.0 micromark-extension-mdx-jsx: 3.0.1 micromark-extension-mdx-md: 2.0.0 @@ -33990,8 +34002,6 @@ snapshots: package-json-from-dist@1.0.1: {} - package-manager-detector@1.3.0: {} - package-manager-detector@1.8.0: {} pako@0.2.9: {} @@ -35977,7 +35987,7 @@ snapshots: sirv@2.0.4: dependencies: '@polka/url': 1.0.0-next.25 - mrmime: 2.0.0 + mrmime: 2.0.1 totalist: 3.0.1 sirv@3.0.2: @@ -37048,7 +37058,7 @@ snapshots: unplugin@2.3.11: dependencies: '@jridgewell/remapping': 2.3.5 - acorn: 8.16.0 + acorn: 8.18.0 picomatch: 4.0.5 webpack-virtual-modules: 0.6.2 @@ -37314,27 +37324,6 @@ snapshots: dependencies: vite: 7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) - vite-node@3.2.4(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0): - dependencies: - cac: 6.7.14 - debug: 4.4.3(supports-color@8.1.1) - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - vite-node@3.2.4(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.33.0)(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0): dependencies: cac: 6.7.14 @@ -37691,7 +37680,7 @@ snapshots: webpack-bundle-analyzer@4.10.1: dependencies: '@discoveryjs/json-ext': 0.5.7 - acorn: 8.16.0 + acorn: 8.18.0 acorn-walk: 8.3.4 commander: 7.2.0 debounce: 1.2.1