diff --git a/apps/kb/astro.config.mjs b/apps/kb/astro.config.mjs index 019ad553395..7bae3070765 100644 --- a/apps/kb/astro.config.mjs +++ b/apps/kb/astro.config.mjs @@ -2,10 +2,13 @@ import { createRequire } from 'node:module' import path from 'node:path' +import { unified } from '@astrojs/markdown-remark' +import mdx from '@astrojs/mdx' import react from '@astrojs/react' import tailwindcss from '@tailwindcss/vite' import { defineConfig } from 'astro/config' +import rehypeAdmonitions from './src/lib/mdx/rehype-admonitions.js' import supabaseTheme from '../learn/lib/themes/supabase-2.json' with { type: 'json' } // Absolute dir of lodash-es, for the SSR-only lodash alias below (same fix @@ -40,7 +43,16 @@ const ssrLodashEs = { export default defineConfig({ base: '/kb', trailingSlash: 'ignore', - integrations: [react()], + integrations: [ + react(), + // rehype-admonitions is a custom rehype plugin and Astro's default pipeline is + // satteri, so .mdx gets its own unified processor. Plain .md stays on satteri. + mdx({ + processor: unified({ + rehypePlugins: [rehypeAdmonitions], + }), + }), + ], vite: { ssr: { noExternal: ['lodash'], diff --git a/apps/kb/package.json b/apps/kb/package.json index 4e440f7e8bb..36210f4b905 100644 --- a/apps/kb/package.json +++ b/apps/kb/package.json @@ -9,15 +9,19 @@ "dev": "astro dev --port 3008", "build": "astro build", "preview": "astro preview", - "astro": "astro" + "astro": "astro", + "test": "vitest --run" }, "dependencies": { + "@astrojs/markdown-remark": "7.2.4", + "@astrojs/mdx": "^7.0.7", "@astrojs/react": "^6.0.4", "astro": "^7.2.6", "lucide-react": "*", "react": "catalog:", "react-dom": "catalog:", - "ui": "workspace:*" + "ui": "workspace:*", + "ui-patterns": "workspace:*" }, "devDependencies": { "@tailwindcss/vite": "4.2.4", @@ -25,7 +29,8 @@ "@types/react-dom": "catalog:", "config": "workspace:*", "lodash-es": "catalog:", - "tailwindcss": "catalog:" + "tailwindcss": "catalog:", + "vitest": "catalog:" }, "allowScripts": { "esbuild": true diff --git a/apps/kb/src/content.config.ts b/apps/kb/src/content.config.ts index 245e1163529..d67a7e17b1f 100644 --- a/apps/kb/src/content.config.ts +++ b/apps/kb/src/content.config.ts @@ -8,7 +8,7 @@ import { TOPIC_NAMES } from './lib/topics' // src/pages/guides/[...slug].astro — dropping a new file in // src/content/guides doesn't need any per-file layout wiring. const guides = defineCollection({ - loader: glob({ pattern: '**/*.md', base: './src/content/guides' }), + loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/guides' }), schema: z.object({ title: z.string(), description: z.string(), diff --git a/apps/kb/src/content/guides/sample-guide.md b/apps/kb/src/content/guides/sample-guide.mdx similarity index 83% rename from apps/kb/src/content/guides/sample-guide.md rename to apps/kb/src/content/guides/sample-guide.mdx index 7aa9a1f9a8c..9f8b159eef6 100644 --- a/apps/kb/src/content/guides/sample-guide.md +++ b/apps/kb/src/content/guides/sample-guide.mdx @@ -44,6 +44,23 @@ And an ordered list with a nested list: > > > Nested blockquote: at vero eos et accusamus et iusto odio dignissimos. +GitHub-style alert blockquotes, rendered through the `Admonition` component: + +> [!NOTE] +> Useful information that users should know, even when skimming content. + +> [!TIP] +> Helpful advice for doing things better or more easily. + +> [!IMPORTANT] +> Key information users need to know to achieve their goal. + +> [!WARNING] +> Urgent info that needs immediate attention to avoid problems. + +> [!CAUTION] +> Advises about risks or negative outcomes of certain actions. + ###### Heading level 6 A fenced code block with a language tag: diff --git a/apps/kb/src/lib/mdx/rehype-admonitions.test.ts b/apps/kb/src/lib/mdx/rehype-admonitions.test.ts new file mode 100644 index 00000000000..8919031d5a1 --- /dev/null +++ b/apps/kb/src/lib/mdx/rehype-admonitions.test.ts @@ -0,0 +1,191 @@ +import { describe, expect, it } from 'vitest' + +import rehypeAdmonitions from './rehype-admonitions.js' + +// --- small helpers to build hast nodes by hand ----------------------- +// (Mirrors what remark-rehype actually produces for: +// > [!NOTE] +// > Lorem ipsum dolor... +// i.e. ONE blockquote containing ONE

whose text has an embedded +// newline, plus whitespace text nodes between elements.) + +function text(value: string): any { + return { type: 'text', value } +} + +function element(tagName: string, children: any[] = []): any { + return { type: 'element', tagName, properties: {}, children } +} + +function root(children: any[]): any { + return { type: 'root', children } +} + +function run(tree: any) { + const transform = rehypeAdmonitions() + transform(tree) + return tree +} + +// ----------------------------------------------------------------------- + +describe('rehypeAdmonitions', () => { + it('converts a marked blockquote into an mdxJsxFlowElement Admonition', () => { + const p = element('p', [text('[!NOTE]\nLorem ipsum dolor...')]) + const blockquote = element('blockquote', [text('\n'), p, text('\n')]) + const tree = root([blockquote]) + + run(tree) + + const [admonition] = tree.children + expect(admonition.type).toBe('mdxJsxFlowElement') + expect(admonition.name).toBe('Admonition') + expect(admonition.attributes).toEqual([ + { type: 'mdxJsxAttribute', name: 'type', value: 'note' }, + ]) + }) + + it('strips the marker from the paragraph text and keeps the remaining body as children', () => { + const p = element('p', [text('[!WARNING]\nSomething risky follows.')]) + const blockquote = element('blockquote', [text('\n'), p, text('\n')]) + const tree = root([blockquote]) + + run(tree) + + const admonition = tree.children[0] + const paragraph = admonition.children.find((c: any) => c.tagName === 'p') + expect(paragraph.children[0].value).toBe('Something risky follows.') + // the marker itself must be gone + expect(paragraph.children[0].value).not.toContain('[!WARNING]') + }) + + it('maps a GFM alert type to its Admonition type', () => { + const p = element('p', [text('[!TIP]\nUse the force.')]) + const blockquote = element('blockquote', [p]) + const tree = root([blockquote]) + + run(tree) + + expect(tree.children[0].attributes[0].value).toBe('success') + }) + + it('preserves additional paragraphs inside the blockquote as extra children', () => { + const firstP = element('p', [text('[!NOTE]\nFirst line.')]) + const secondP = element('p', [text('Second paragraph.')]) + const blockquote = element('blockquote', [text('\n'), firstP, text('\n'), secondP, text('\n')]) + const tree = root([blockquote]) + + run(tree) + + const admonition = tree.children[0] + const paragraphs = admonition.children.filter((c: any) => c.tagName === 'p') + expect(paragraphs).toHaveLength(2) + expect(paragraphs[0].children[0].value).toBe('First line.') + expect(paragraphs[1].children[0].value).toBe('Second paragraph.') + }) + + it('drops the first paragraph entirely if stripping the marker leaves it empty', () => { + // > [!NOTE] + // > + // > Body lives in its own paragraph + const firstP = element('p', [text('[!NOTE]')]) + const secondP = element('p', [text('Body lives in its own paragraph')]) + const blockquote = element('blockquote', [text('\n'), firstP, text('\n'), secondP, text('\n')]) + const tree = root([blockquote]) + + run(tree) + + const admonition = tree.children[0] + const paragraphs = admonition.children.filter((c: any) => c.tagName === 'p') + expect(paragraphs).toHaveLength(1) + expect(paragraphs[0].children[0].value).toBe('Body lives in its own paragraph') + }) + + it('leaves an ordinary blockquote (no marker) completely untouched', () => { + const p = element('p', [text('Just a normal quote, nothing special.')]) + const blockquote = element('blockquote', [text('\n'), p, text('\n')]) + const tree = root([blockquote]) + + run(tree) + + expect(tree.children[0]).toBe(blockquote) + expect(tree.children[0].type).toBe('element') + expect(tree.children[0].tagName).toBe('blockquote') + }) + + it('ignores a blockquote whose first child is not a

', () => { + const pre = element('pre', [text('[!NOTE]\nnot really a marker here')]) + const blockquote = element('blockquote', [pre]) + const tree = root([blockquote]) + + run(tree) + + expect(tree.children[0]).toBe(blockquote) + }) + + it('ignores a blockquote whose paragraph has no leading text node', () => { + const p = element('p', [element('code', [text('[!NOTE]')])]) + const blockquote = element('blockquote', [p]) + const tree = root([blockquote]) + + run(tree) + + expect(tree.children[0]).toBe(blockquote) + }) + + it('does not touch text that merely contains brackets without the "[!" marker shape', () => { + const p = element('p', [text('See [reference] for details.')]) + const blockquote = element('blockquote', [p]) + const tree = root([blockquote]) + + run(tree) + + expect(tree.children[0].tagName).toBe('blockquote') + }) + + it('requires a closing "]" to treat something as a marker', () => { + const p = element('p', [text('[!NOTE without a closing bracket')]) + const blockquote = element('blockquote', [p]) + const tree = root([blockquote]) + + run(tree) + + expect(tree.children[0].tagName).toBe('blockquote') + }) + + it('finds and converts blockquotes nested arbitrarily deep in the tree', () => { + const p = element('p', [text('[!DANGER]\nDeeply nested warning.')]) + const blockquote = element('blockquote', [p]) + const tree = root([element('div', [element('section', [blockquote])])]) + + run(tree) + + const nested = tree.children[0].children[0].children[0] + expect(nested.type).toBe('mdxJsxFlowElement') + expect(nested.attributes[0].value).toBe('danger') + }) + + it('converts multiple independent admonitions in the same document', () => { + const note = element('blockquote', [element('p', [text('[!NOTE]\nFirst.')])]) + const warning = element('blockquote', [element('p', [text('[!WARNING]\nSecond.')])]) + const tree = root([note, text('\n'), warning]) + + run(tree) + + const [first, , second] = tree.children + expect(first.attributes[0].value).toBe('note') + expect(second.attributes[0].value).toBe('danger') + }) + + it('trims leading whitespace/newlines around the marker before matching', () => { + const p = element('p', [text(' \n[!NOTE]\nIndented marker body.')]) + const blockquote = element('blockquote', [p]) + const tree = root([blockquote]) + + run(tree) + + const admonition = tree.children[0] + expect(admonition.attributes[0].value).toBe('note') + expect(admonition.children[0].children[0].value).toBe('Indented marker body.') + }) +}) diff --git a/apps/kb/src/lib/mdx/rehype-admonitions.ts b/apps/kb/src/lib/mdx/rehype-admonitions.ts new file mode 100644 index 00000000000..3bdcacf484d --- /dev/null +++ b/apps/kb/src/lib/mdx/rehype-admonitions.ts @@ -0,0 +1,143 @@ +import type { AdmonitionType } from 'ui-patterns/Admonition' + +/** + * rehype-admonitions + * + * Turns: + * + * > [!NOTE] + * > Lorem ipsum dolor... + * + * into: + * + * + *

Lorem ipsum dolor...

+ * + * + * The five official GFM alert types (github.com/.../basic-writing-and-formatting-syntax#alerts) + * are mapped to their closest Admonition type below — Admonition has no + * literal "tip"/"important" type, so TIP maps to the upbeat "success" + * treatment, and IMPORTANT/WARNING split across Admonition's two escalating + * severities ("warning" then "danger") so all five stay visually distinct. + * Anything else is passed through lowercased, so a marker that already + * spells out an Admonition type (e.g. "[!CAUTION]") still works verbatim. + * + * Notes on why this works on a *single* blockquote node: + * Because there's no blank line between the "> [!NOTE]" line and the + * "> Lorem ipsum..." line, remark/mdast merges them into ONE blockquote + * containing ONE

, whose text is "[!NOTE]\nLorem ipsum dolor...". + * So the plugin looks at the blockquote's first paragraph, peels the + * "[!TYPE]" marker off its leading text node, and uses whatever is left + * of the blockquote (the now-stripped paragraph + any other children) + * as the Admonition's children. + * + * No regex is used anywhere — just startsWith/indexOf/slice/trimStart. + * No runtime dependencies — just a manual tree walk. AST nodes are typed as + * `any` throughout (no hast/unist dependency) since the walk only ever reads + * a handful of duck-typed fields (type/tagName/children/value). + * + * Requires the MDX/rehype pipeline to preserve `mdxJsxFlowElement` nodes + * (this is the default in @mdx-js/mdx), and an `Admonition` component + * made available to your MDX content (via `useMDXComponents` / provider, + * or an explicit import in the .mdx file). + */ + +export default function rehypeAdmonitions() { + return function transformer(tree: any) { + walk(tree) + } +} + +function walk(node: any) { + if (!node || !Array.isArray(node.children)) return + + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i] + + if (child.type === 'element' && child.tagName === 'blockquote') { + const admonition = toAdmonition(child) + if (admonition) { + node.children[i] = admonition + walk(admonition) // keep walking in case content has nested cases + continue + } + } + + walk(child) + } +} + +function toAdmonition(blockquote: any) { + const children = blockquote.children + + // Find the first element child (skip the whitespace text nodes mdast + // inserts between the blockquote's children). + const pIndex = children.findIndex((c: any) => c.type === 'element') + const p = pIndex === -1 ? null : children[pIndex] + if (!p || p.tagName !== 'p') return null + + // Find the first text node inside that paragraph — this is where the + // "[!TYPE]" marker lives. + const textIndex = p.children.findIndex((c: any) => c.type === 'text') + if (textIndex === -1) return null + const textNode = p.children[textIndex] + + const marker = parseMarker(textNode.value) + if (!marker) return null + + // Strip the marker out of the paragraph's leading text node, leaving + // only the admonition body behind (e.g. "Lorem ipsum dolor..."). + if (marker.rest) { + textNode.value = marker.rest + } else { + p.children.splice(textIndex, 1) + } + + // If stripping the marker left the paragraph empty, drop the paragraph + // entirely so we don't render an empty

inside the Admonition. + const admonitionChildren = p.children.length + ? children + : children.filter((_: any, i: number) => i !== pIndex) + + return { + type: 'mdxJsxFlowElement', + name: 'Admonition', + attributes: [{ type: 'mdxJsxAttribute', name: 'type', value: toAdmonitionType(marker.type) }], + children: admonitionChildren, + } +} + +// GFM alert type -> Admonition type. See the module doc comment above. +const GFM_ALERT_TYPES: Record = { + NOTE: 'note', + TIP: 'success', + IMPORTANT: 'warning', + WARNING: 'danger', + CAUTION: 'caution', +} + +function toAdmonitionType(marker: string): AdmonitionType { + const mapped = GFM_ALERT_TYPES[marker] + if (mapped) return mapped + // Not one of the five GFM types — assume the marker already spells out an + // Admonition type verbatim (e.g. "[!CAUTION]"). Unlike the branch above, + // this isn't statically checked: an unrecognized marker just becomes + // whatever string this produces, valid Admonition type or not. + return marker.toLowerCase() as AdmonitionType +} + +// Parses a leading "[!TYPE]" marker off the start of a string, without +// using any regex. +function parseMarker(value: string) { + const trimmed = value.trimStart() + if (!trimmed.startsWith('[!')) return null + + const closeIndex = trimmed.indexOf(']') + if (closeIndex === -1) return null + + const type = trimmed.slice(2, closeIndex) + if (!type) return null + + const rest = trimmed.slice(closeIndex + 1).trimStart() + return { type, rest } +} diff --git a/apps/kb/src/pages/guides/[...slug].astro b/apps/kb/src/pages/guides/[...slug].astro index d6b5c5de931..2ff475f0e76 100644 --- a/apps/kb/src/pages/guides/[...slug].astro +++ b/apps/kb/src/pages/guides/[...slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content' +import { Admonition } from 'ui-patterns/Admonition' import GuideLayout from '../../layouts/GuideLayout.astro' @@ -17,5 +18,5 @@ const { Content } = await render(guide) --- - + diff --git a/apps/kb/src/styles/globals.css b/apps/kb/src/styles/globals.css index efb8df5e7bb..6fccde73f71 100644 --- a/apps/kb/src/styles/globals.css +++ b/apps/kb/src/styles/globals.css @@ -105,3 +105,7 @@ h6:not(.font-mono), --code-token-property: #15593b; --code-highlight-color: #1c1c1c; } + +.prose [role='alert'] { + margin: 1.25rem 0; +} diff --git a/package.json b/package.json index e1f7d90f0d2..0d18297f1da 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "test:prettier": "SORT_IMPORTS=false prettier --config prettier.config.mjs --cache --check '{apps,packages,blocks,examples,i18n}/**/*.{js,jsx,ts,tsx,css,md,mdx,json}'", "format": "SORT_IMPORTS=false prettier --config prettier.config.mjs --cache --write '{apps,packages,blocks,examples,i18n}/**/*.{js,jsx,ts,tsx,css,md,mdx,json}'", "test:docs": "turbo run test --filter=docs", + "test:kb": "turbo run test --filter=kb", "test:ui": "turbo run test --filter=ui", "test:ui-patterns": "turbo run test --filter=ui-patterns", "test:studio": "turbo run test --filter=studio", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c4b5fdff10a..aa3ecd83f0d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -729,12 +729,18 @@ importers: apps/kb: dependencies: + '@astrojs/markdown-remark': + specifier: 7.2.4 + version: 7.2.4(supports-color@8.1.1) + '@astrojs/mdx': + specifier: ^7.0.7 + version: 7.0.8(@astrojs/markdown-satteri@0.3.8)(astro@7.2.9(@astrojs/markdown-remark@7.2.4(supports-color@8.1.1))(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.3)(@types/node@22.13.14)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.4.5))(ioredis@5.10.1(supports-color@8.1.1))(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(supports-color@8.1.1) '@astrojs/react': specifier: ^6.0.4 version: 6.0.4(@types/node@22.13.14)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(esbuild@0.28.1)(jiti@2.7.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4)(supports-color@8.1.1)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) astro: specifier: ^7.2.6 - version: 7.2.9(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.3)(@types/node@22.13.14)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.4.5))(ioredis@5.10.1(supports-color@8.1.1))(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) + version: 7.2.9(@astrojs/markdown-remark@7.2.4(supports-color@8.1.1))(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.3)(@types/node@22.13.14)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.4.5))(ioredis@5.10.1(supports-color@8.1.1))(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) lucide-react: specifier: '*' version: 0.436.0(react@19.2.6) @@ -747,6 +753,9 @@ importers: ui: specifier: workspace:* version: link:../../packages/ui + ui-patterns: + specifier: workspace:* + version: link:../../packages/ui-patterns devDependencies: '@tailwindcss/vite': specifier: 4.2.4 @@ -766,6 +775,9 @@ importers: tailwindcss: specifier: 'catalog:' version: 4.2.4 + vitest: + specifier: 'catalog:' + version: 5.0.0(@opentelemetry/api@1.9.1)(@types/node@22.13.14)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(jsdom@28.1.0(@noble/hashes@1.8.0)(supports-color@8.1.1))(msw@2.11.3(@types/node@22.13.14)(typescript@7.0.2))(vite@8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) apps/learn: dependencies: @@ -3166,9 +3178,22 @@ packages: '@astrojs/internal-helpers@0.10.4': resolution: {integrity: sha512-nozZSy/mKYLqe4YrqbKtdOszedAfXYCtw3wZ0d+CAjz4GqQ4L9rl1ltIL5BlgwmYVinJg/RZ0MgGuWOdlyRZlA==} + '@astrojs/markdown-remark@7.2.4': + resolution: {integrity: sha512-MvspGMynWKAjTe4/lTUdmBPHIFKNVLTCF6UlyWGogTGzNrTvjD+D4n48k7h8swxsEPKHK2TwxkZO7uoaCv1Pow==} + '@astrojs/markdown-satteri@0.3.8': resolution: {integrity: sha512-n8ItpFTCmlDsVR5+rwDmehSf+jFCYLWmZiisZNGuF7xILqYhsVeBfcha4qgS2Seq3fAc9Tm58ZVrvqFQ6RQgRQ==} + '@astrojs/mdx@7.0.8': + resolution: {integrity: sha512-RNuwq2ccTSi7NX9YqlR0noaWoVdOrZuJvdfWXotAzdhMVB0b0zEMLnNU+xar7le0GwTMlTObD/QAu8jeHA/3nA==} + engines: {node: '>=22.12.0'} + peerDependencies: + '@astrojs/markdown-satteri': ^0.3.1 + astro: ^7.0.0 + peerDependenciesMeta: + '@astrojs/markdown-satteri': + optional: true + '@astrojs/prism@4.0.2': resolution: {integrity: sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA==} engines: {node: '>=22.12.0'} @@ -9821,6 +9846,9 @@ packages: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} + array-iterate@2.0.1: + resolution: {integrity: sha512-I1jXZMjAgCMmxT4qxXfPXa6SthSoE8h6gkSI9BGGNv8mP8G/v0blc+qFnZu6K42vTOiuME596QaLO0TP3Lk0xg==} + array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} @@ -12537,6 +12565,9 @@ packages: hast-util-from-html@2.0.1: resolution: {integrity: sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==} + hast-util-from-html@2.0.3: + resolution: {integrity: sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==} + hast-util-from-parse5@8.0.1: resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} @@ -12582,6 +12613,9 @@ packages: hast-util-to-text@4.0.0: resolution: {integrity: sha512-EWiE1FSArNBPUo1cKWtzqgnuRQwEeQbQtnFJRYV1hb1BWDgrAlBU0ExptvZMM/KSA82cDpm2sFGf3Dmc5Mza3w==} + hast-util-to-text@4.0.2: + resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} + hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} @@ -13854,6 +13888,9 @@ packages: mdast-util-definitions@5.1.2: resolution: {integrity: sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==} + mdast-util-definitions@6.0.0: + resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} + mdast-util-find-and-replace@2.2.2: resolution: {integrity: sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==} @@ -15097,6 +15134,9 @@ packages: resolution: {integrity: sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==} engines: {node: '>=18'} + parse-latin@7.0.0: + resolution: {integrity: sha512-mhHgobPPua5kZ98EF4HWiH167JWBfl4pvAIXXdbaVohtK7a6YBOy56kvhCqduqyo/f3yrHFWmqmiMg/BkBkYYQ==} + parse-ms@4.0.0: resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} engines: {node: '>=18'} @@ -16077,6 +16117,9 @@ packages: rehype-slug@6.0.0: resolution: {integrity: sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==} + rehype-stringify@10.0.1: + resolution: {integrity: sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==} + relay-runtime@12.0.0: resolution: {integrity: sha512-QU6JKr1tMsry22DXNy9Whsq5rmvwr3LSZiiWV/9+DFpuTWvp+WFhobWMc8TC4OjKFfNhEZy7mOiqUAn5atQtug==} @@ -16111,6 +16154,13 @@ packages: remark-rehype@11.1.1: resolution: {integrity: sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==} + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-smartypants@3.0.3: + resolution: {integrity: sha512-gCaK+ndZ0hYezlqFegHFCVh2CQemsi0Npdh1qVM9bxlUFknjkbP6VmojWhddOCrbK0PbbacmYLWfTULRiT1eWA==} + engines: {node: '>=16.0.0'} + remark-stringify@10.0.3: resolution: {integrity: sha512-koyOzCMYoUHudypbj4XpnAKFbkddRMYZHwghnxd7ue5210WzGw6kOBwauJTRUMq16jsovXx8dYNvSSWP89kZ3A==} @@ -16211,9 +16261,18 @@ packages: resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} engines: {node: '>=4'} + retext-latin@4.0.0: + resolution: {integrity: sha512-hv9woG7Fy0M9IlRQloq/N6atV82NxLGveq+3H2WOi79dtIYWN8OaxogDm77f8YnVXJL2VD3bbqowu5E3EMhBYA==} + retext-smartypants@6.2.0: resolution: {integrity: sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ==} + retext-stringify@4.0.0: + resolution: {integrity: sha512-rtfN/0o8kL1e+78+uxPTqu1Klt0yPzKuQ2BfWwwfgIUSayyzxpM1PJzkKt4V8803uB9qSy32MvI7Xep9khTpiA==} + + retext@9.0.0: + resolution: {integrity: sha512-sbMDcpHCNjvlheSgMfEcVrZko3cDzdbe1x/e7G66dFp0Ff7Mldvi2uv6JkJQzdRcvLYE8CA8Oe8siQx8ZOgTcA==} + retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -17489,6 +17548,9 @@ packages: unist-util-is@6.0.0: resolution: {integrity: sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==} + unist-util-modify-children@4.0.0: + resolution: {integrity: sha512-+tdN5fGNddvsQdIzUF3Xx82CU9sMM+fA0dLgR9vOmT0oPT2jH+P1nd5lSqfCfXAw+93NhcXNY2qqvTUtE4cQkw==} + unist-util-position-from-estree@1.1.2: resolution: {integrity: sha512-poZa0eXpS+/XpoQwGwl79UUdea4ol2ZuCYguVaJS4qzIOMDzbqz8a3erUCOmubSZkaOuGamb3tX790iwOIROww==} @@ -17519,12 +17581,18 @@ packages: unist-util-stringify-position@4.0.0: resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + unist-util-visit-children@3.0.0: + resolution: {integrity: sha512-RgmdTfSBOg04sdPcpTSD1jzoNBjt9a80/ZCzp5cI9n1qPzLZWF9YdvWGN2zmTumP1HWhXKdUWexjy/Wy/lJ7tA==} + unist-util-visit-parents@5.1.3: resolution: {integrity: sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==} unist-util-visit-parents@6.0.1: resolution: {integrity: sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==} + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + unist-util-visit@4.1.2: resolution: {integrity: sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==} @@ -18608,7 +18676,7 @@ snapshots: '@apm-js-collab/code-transformer-bundler-plugins@0.5.0': dependencies: '@apm-js-collab/code-transformer': 0.15.0 - es-module-lexer: 2.1.0 + es-module-lexer: 2.3.2 magic-string: 0.30.21 module-details-from-path: 1.0.4 @@ -18731,12 +18799,34 @@ snapshots: '@types/hast': 3.0.5 '@types/mdast': 4.0.4 js-yaml: 4.3.1 - picomatch: 4.0.5 + picomatch: 4.0.7 retext-smartypants: 6.2.0 shiki: 4.2.0 smol-toml: 1.8.0 unified: 11.0.5 + '@astrojs/markdown-remark@7.2.4(supports-color@8.1.1)': + dependencies: + '@astrojs/internal-helpers': 0.10.4 + '@astrojs/prism': 4.0.2 + github-slugger: 2.0.0 + hast-util-from-html: 2.0.3 + hast-util-to-text: 4.0.2 + mdast-util-definitions: 6.0.0 + rehype-raw: 7.0.0 + rehype-stringify: 10.0.1 + remark-gfm: 4.0.1(supports-color@8.1.1) + remark-parse: 11.0.0(supports-color@8.1.1) + remark-rehype: 11.1.2 + remark-smartypants: 3.0.3 + unified: 11.0.5 + unist-util-remove-position: 5.0.0 + unist-util-visit: 5.1.0 + unist-util-visit-parents: 6.0.2 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + '@astrojs/markdown-satteri@0.3.8': dependencies: '@astrojs/internal-helpers': 0.10.4 @@ -18744,6 +18834,28 @@ snapshots: github-slugger: 2.0.0 satteri: 0.10.5 + '@astrojs/mdx@7.0.8(@astrojs/markdown-satteri@0.3.8)(astro@7.2.9(@astrojs/markdown-remark@7.2.4(supports-color@8.1.1))(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.3)(@types/node@22.13.14)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.4.5))(ioredis@5.10.1(supports-color@8.1.1))(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(supports-color@8.1.1)': + dependencies: + '@astrojs/internal-helpers': 0.10.4 + '@astrojs/markdown-remark': 7.2.4(supports-color@8.1.1) + '@mdx-js/mdx': 3.1.1(supports-color@8.1.1) + acorn: 8.18.0 + astro: 7.2.9(@astrojs/markdown-remark@7.2.4(supports-color@8.1.1))(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.3)(@types/node@22.13.14)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.4.5))(ioredis@5.10.1(supports-color@8.1.1))(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) + es-module-lexer: 2.3.2 + estree-util-visit: 2.0.0 + hast-util-to-html: 9.0.5 + piccolore: 0.1.3 + rehype-raw: 7.0.0 + remark-gfm: 4.0.1(supports-color@8.1.1) + remark-smartypants: 3.0.3 + source-map: 0.7.6 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + optionalDependencies: + '@astrojs/markdown-satteri': 0.3.8 + transitivePeerDependencies: + - supports-color + '@astrojs/prism@4.0.2': dependencies: prismjs: 1.30.0 @@ -22363,7 +22475,7 @@ snapshots: '@parcel/watcher-wasm@2.5.6': dependencies: is-glob: 4.0.3 - picomatch: 4.0.5 + picomatch: 4.0.7 '@parcel/watcher-win32-arm64@2.5.6': optional: true @@ -22379,7 +22491,7 @@ snapshots: detect-libc: 2.1.2 is-glob: 4.0.3 node-addon-api: 7.1.0 - picomatch: 4.0.5 + picomatch: 4.0.7 optionalDependencies: '@parcel/watcher-android-arm64': 2.5.6 '@parcel/watcher-darwin-arm64': 2.5.6 @@ -23492,10 +23604,10 @@ snapshots: '@rollup/pluginutils': 5.1.4(rollup@4.60.3) commondir: 1.0.1 estree-walker: 2.0.2 - fdir: 6.5.0(picomatch@4.0.5) + fdir: 6.5.0(picomatch@4.0.7) is-reference: 1.2.1 magic-string: 0.30.21 - picomatch: 4.0.5 + picomatch: 4.0.7 optionalDependencies: rollup: 4.60.3 @@ -25871,7 +25983,7 @@ snapshots: glob: 13.0.6 graceful-fs: 4.2.11 node-gyp-build: 4.8.4 - picomatch: 4.0.5 + picomatch: 4.0.7 resolve-from: 5.0.0 transitivePeerDependencies: - encoding @@ -25956,6 +26068,16 @@ snapshots: msw: 2.11.3(@types/node@22.13.14)(typescript@6.0.2) vite: 8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) + '@vitest/mocker@5.0.0(msw@2.11.3(@types/node@22.13.14)(typescript@7.0.2))(vite@8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.0 + estree-walker: 3.0.3 + magic-string: 1.2.3 + optionalDependencies: + msw: 2.11.3(@types/node@22.13.14)(typescript@7.0.2) + vite: 8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) + '@vitest/pretty-format@5.0.0': dependencies: tinyrainbow: 3.1.1 @@ -26533,6 +26655,8 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 + array-iterate@2.0.1: {} + array-union@2.1.0: {} array.prototype.findlast@1.2.5: @@ -26624,7 +26748,7 @@ snapshots: astring@1.9.0: {} - astro@7.2.9(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.3)(@types/node@22.13.14)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.4.5))(ioredis@5.10.1(supports-color@8.1.1))(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0): + astro@7.2.9(@astrojs/markdown-remark@7.2.4(supports-color@8.1.1))(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.3)(@types/node@22.13.14)(aws4fetch@1.0.20)(db0@0.3.4(@electric-sql/pglite@0.4.5))(ioredis@5.10.1(supports-color@8.1.1))(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0): dependencies: '@astrojs/compiler-rs': 0.4.0(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.3) '@astrojs/internal-helpers': 0.10.4 @@ -26680,6 +26804,7 @@ snapshots: yargs-parser: 22.0.0 zod: 4.4.3 optionalDependencies: + '@astrojs/markdown-remark': 7.2.4(supports-color@8.1.1) sharp: 0.35.4(@types/node@22.13.14) transitivePeerDependencies: - '@azure/app-configuration' @@ -28350,7 +28475,7 @@ snapshots: esast-util-from-js@2.0.1: dependencies: - '@types/estree-jsx': 1.0.1 + '@types/estree-jsx': 1.0.5 acorn: 8.18.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.2 @@ -28768,7 +28893,7 @@ snapshots: estree-util-visit@1.2.1: dependencies: - '@types/estree-jsx': 1.0.1 + '@types/estree-jsx': 1.0.5 '@types/unist': 2.0.8 estree-util-visit@2.0.0: @@ -29074,6 +29199,10 @@ snapshots: optionalDependencies: picomatch: 4.0.5 + fdir@6.5.0(picomatch@4.0.7): + optionalDependencies: + picomatch: 4.0.7 + fetch-blob@3.2.0: dependencies: node-domexception: 1.0.0 @@ -29725,6 +29854,15 @@ snapshots: vfile: 6.0.3 vfile-message: 4.0.2 + hast-util-from-html@2.0.3: + dependencies: + '@types/hast': 3.0.5 + devlop: 1.1.0 + hast-util-from-parse5: 8.0.1 + parse5: 7.3.0 + vfile: 6.0.3 + vfile-message: 4.0.2 + hast-util-from-parse5@8.0.1: dependencies: '@types/hast': 3.0.5 @@ -29758,7 +29896,7 @@ snapshots: hast-util-raw@9.0.1: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 '@types/unist': 3.0.3 '@ungap/structured-clone': 1.2.0 hast-util-from-parse5: 8.0.1 @@ -29852,6 +29990,13 @@ snapshots: hast-util-is-element: 3.0.0 unist-util-find-after: 5.0.0 + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + hast-util-whitespace@3.0.0: dependencies: '@types/hast': 3.0.4 @@ -30050,7 +30195,7 @@ snapshots: impound@1.1.6(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.60.3)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.33.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1)): dependencies: '@jridgewell/trace-mapping': 0.3.31 - es-module-lexer: 2.1.0 + es-module-lexer: 2.3.2 pathe: 2.0.3 unplugin: 3.3.0(esbuild@0.28.1)(rolldown@1.2.3)(rollup@4.60.3)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.33.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1)) unplugin-utils: 0.3.2 @@ -31098,6 +31243,12 @@ snapshots: '@types/unist': 2.0.8 unist-util-visit: 4.1.2 + mdast-util-definitions@6.0.0: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + unist-util-visit: 5.1.0 + mdast-util-find-and-replace@2.2.2: dependencies: '@types/mdast': 3.0.15 @@ -32247,6 +32398,33 @@ snapshots: transitivePeerDependencies: - '@types/node' + msw@2.11.3(@types/node@22.13.14)(typescript@7.0.2): + dependencies: + '@bundled-es-modules/cookie': 2.0.1 + '@bundled-es-modules/statuses': 1.0.1 + '@inquirer/confirm': 5.1.21(@types/node@22.13.14) + '@mswjs/interceptors': 0.39.7 + '@open-draft/deferred-promise': 2.2.0 + '@types/cookie': 0.6.0 + '@types/statuses': 2.0.5 + graphql: 16.11.0 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.7.0 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.0 + type-fest: 4.30.0 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 7.0.2 + transitivePeerDependencies: + - '@types/node' + optional: true + muggle-string@0.4.1: {} mustache@4.2.0: {} @@ -33182,6 +33360,15 @@ snapshots: index-to-position: 0.1.2 type-fest: 4.30.0 + parse-latin@7.0.0: + dependencies: + '@types/nlcst': 2.0.3 + '@types/unist': 3.0.3 + nlcst-to-string: 4.0.0 + unist-util-modify-children: 4.0.0 + unist-util-visit-children: 3.0.0 + vfile: 6.0.3 + parse-ms@4.0.0: {} parse-numeric-range@1.3.0: {} @@ -34236,7 +34423,7 @@ snapshots: rehype-raw@7.0.0: dependencies: - '@types/hast': 3.0.4 + '@types/hast': 3.0.5 hast-util-raw: 9.0.1 vfile: 6.0.3 @@ -34266,6 +34453,12 @@ snapshots: hast-util-to-string: 3.0.0 unist-util-visit: 5.1.0 + rehype-stringify@10.0.1: + dependencies: + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + unified: 11.0.5 + relay-runtime@12.0.0(encoding@0.1.13): dependencies: '@babel/runtime': 7.26.10 @@ -34347,6 +34540,21 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + remark-smartypants@3.0.3: + dependencies: + retext: 9.0.0 + retext-smartypants: 6.2.0 + unified: 11.0.5 + unist-util-visit: 5.1.0 + remark-stringify@10.0.3: dependencies: '@types/mdast': 3.0.15 @@ -34445,12 +34653,31 @@ snapshots: ret@0.2.2: {} + retext-latin@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + parse-latin: 7.0.0 + unified: 11.0.5 + retext-smartypants@6.2.0: dependencies: '@types/nlcst': 2.0.3 nlcst-to-string: 4.0.0 unist-util-visit: 5.1.0 + retext-stringify@4.0.0: + dependencies: + '@types/nlcst': 2.0.3 + nlcst-to-string: 4.0.0 + unified: 11.0.5 + + retext@9.0.0: + dependencies: + '@types/nlcst': 2.0.3 + retext-latin: 4.0.0 + retext-stringify: 4.0.0 + unified: 11.0.5 + retry@0.12.0: {} rettime@0.7.0: {} @@ -34503,7 +34730,7 @@ snapshots: rollup-plugin-visualizer@7.0.1(rolldown@1.2.3)(rollup@4.60.3): dependencies: open: 11.0.0 - picomatch: 4.0.5 + picomatch: 4.0.7 source-map: 0.7.6 yargs: 18.0.0 optionalDependencies: @@ -36005,6 +36232,11 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-modify-children@4.0.0: + dependencies: + '@types/unist': 3.0.3 + array-iterate: 2.0.1 + unist-util-position-from-estree@1.1.2: dependencies: '@types/unist': 2.0.8 @@ -36049,6 +36281,10 @@ snapshots: dependencies: '@types/unist': 3.0.3 + unist-util-visit-children@3.0.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-visit-parents@5.1.3: dependencies: '@types/unist': 2.0.8 @@ -36059,6 +36295,11 @@ snapshots: '@types/unist': 3.0.3 unist-util-is: 6.0.0 + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.0 + unist-util-visit@4.1.2: dependencies: '@types/unist': 2.0.8 @@ -36396,7 +36637,7 @@ snapshots: vite-node@6.0.0(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0): dependencies: cac: 7.0.0 - es-module-lexer: 2.1.0 + es-module-lexer: 2.3.2 obug: 2.1.1 pathe: 2.0.3 vite: 8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) @@ -36517,6 +36758,31 @@ snapshots: transitivePeerDependencies: - msw + vitest@5.0.0(@opentelemetry/api@1.9.1)(@types/node@22.13.14)(@vitest/coverage-v8@5.0.0)(@vitest/ui@5.0.0)(jsdom@28.1.0(@noble/hashes@1.8.0)(supports-color@8.1.1))(msw@2.11.3(@types/node@22.13.14)(typescript@7.0.2))(vite@8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)): + dependencies: + '@types/chai': 5.2.2 + '@vitest/mocker': 5.0.0(msw@2.11.3(@types/node@22.13.14)(typescript@7.0.2))(vite@8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + chai: 6.2.2 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 1.2.3 + obug: 2.1.4 + picomatch: 4.0.7 + std-env: 4.2.0 + tinybench: 6.1.4 + tinyexec: 1.3.0 + tinyglobby: 0.2.17 + vite: 8.2.1(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@types/node': 22.13.14 + '@vitest/coverage-v8': 5.0.0(vitest@5.0.0) + '@vitest/ui': 5.0.0(vitest@5.0.0) + jsdom: 28.1.0(@noble/hashes@1.8.0)(supports-color@8.1.1) + transitivePeerDependencies: + - msw + vscode-languageserver-types@3.17.5: {} vue-bundle-renderer@2.3.2: @@ -36655,7 +36921,7 @@ snapshots: browserslist: 4.28.8 chrome-trace-event: 1.0.4 enhanced-resolve: 5.20.1 - es-module-lexer: 2.1.0 + es-module-lexer: 2.3.2 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1