diff --git a/alias.ts b/alias.ts index b128d0ad5..883a89000 100644 --- a/alias.ts +++ b/alias.ts @@ -140,7 +140,10 @@ const tsconfig = JSON.parse(raw) tsconfig.compilerOptions.paths = Object.fromEntries( Object.entries(alias) .filter(([key]) => !key.endsWith('.css')) - .map(([key, value]) => [key, [`./${relative(root, value)}`]]), + .map(([key, value]) => [ + key, + [`./${relative(root, value)}`], + ]), ) const newRaw = JSON.stringify(tsconfig, null, 2) if (newRaw !== raw) diff --git a/bump.config.ts b/bump.config.ts index 67d43ea5b..57773dec7 100644 --- a/bump.config.ts +++ b/bump.config.ts @@ -13,6 +13,11 @@ export default defineConfig({ */ execute: async (operation) => { await syncStarterVersion(operation.state.newVersion) - await x('pnpm', ['install', '--frozen-lockfile=false'], { nodeOptions: { stdio: 'inherit', cwd: process.cwd() } }) + await x('pnpm', ['install', '--frozen-lockfile=false'], { + nodeOptions: { + stdio: 'inherit', + cwd: process.cwd(), + }, + }) }, }) diff --git a/design/build-shadow-css.ts b/design/build-shadow-css.ts index 686056ef7..ce8772500 100644 --- a/design/build-shadow-css.ts +++ b/design/build-shadow-css.ts @@ -98,14 +98,19 @@ export async function buildShadowCss(options: BuildShadowCssOptions): Promise() - for (const file of [...files, ...designFiles]) { + for (const file of [ + ...files, + ...designFiles, + ]) { const content = await fs.readFile(file, 'utf-8') await generator.applyExtractors(content, file, tokens) } // Hand-written stylesheets may use `--at-apply`. Run each through the // configured transformers before merging them in the caller's order. - const userStylePaths = typeof userStylePath === 'string' ? [userStylePath] : (userStylePath ?? []) + const userStylePaths = typeof userStylePath === 'string' + ? [userStylePath] + : (userStylePath ?? []) const userStyles: string[] = [] for (const userStylePath of userStylePaths) { const userStyle = new MagicString(await fs.readFile(userStylePath, 'utf-8').catch(() => '')) diff --git a/design/design.ts b/design/design.ts index bb5289574..cabe72692 100644 --- a/design/design.ts +++ b/design/design.ts @@ -27,8 +27,12 @@ export function button({ variant = 'primary', size = 'md', class: extra }: Butto link: 'inline-flex items-center gap-1.5 color-active hover:underline underline-offset-2', } const sizeClass = size === 'sm' - ? (variant === 'primary' ? 'text-sm px-2.5! py-1!' : 'text-sm') - : size === 'lg' ? 'text-base px-4! py-2!' : '' + ? (variant === 'primary' + ? 'text-sm px-2.5! py-1!' + : 'text-sm') + : size === 'lg' + ? 'text-base px-4! py-2!' + : '' return cx(variantClass[variant], sizeClass, extra) } @@ -37,8 +41,12 @@ export type IconButtonSize = 'md' | 'sm' export interface IconButtonProps { variant?: IconButtonVariant, size?: IconButtonSize, class?: string } export function iconButton({ variant = 'outline', size = 'md', class: extra }: IconButtonProps = {}): string { - const base = variant === 'ghost' ? 'btn-icon' : 'btn-icon-square' - const sizeClass = size === 'sm' ? 'w-7! h-7! text-sm' : '' + const base = variant === 'ghost' + ? 'btn-icon' + : 'btn-icon-square' + const sizeClass = size === 'sm' + ? 'w-7! h-7! text-sm' + : '' return cx(base, sizeClass, extra) } diff --git a/design/dock-icon.ts b/design/dock-icon.ts index 8e77fe2ff..4065d1ae3 100644 --- a/design/dock-icon.ts +++ b/design/dock-icon.ts @@ -28,7 +28,9 @@ const ICONIFY_ID = /^(?:i-)?([\w-]+):([\w-]+)$/ * await dockIconSvg('ph:git-branch-duotone') // → '...' */ export async function dockIconSvg(name: string | { light: string, dark: string } | undefined): Promise { - const id = typeof name === 'string' ? name : name?.light + const id = typeof name === 'string' + ? name + : name?.light if (!id) return undefined const match = id.match(ICONIFY_ID) diff --git a/design/uno.config.ts b/design/uno.config.ts index 3c16e795f..c4725a1f7 100644 --- a/design/uno.config.ts +++ b/design/uno.config.ts @@ -44,17 +44,24 @@ export function createDesignConfig(options: CreateDesignConfigOptions = {}) { return defineConfig({ presets: [ presetAnthonyDesign({ primary: '#3a6a45' }), - ...(Array.isArray(base) ? base : [base]), + ...(Array.isArray(base) + ? base + : [base]), presetIcons({ scale: 1.1 }), ], - transformers: [transformerDirectives(), transformerVariantGroup()], + transformers: [ + transformerDirectives(), + transformerVariantGroup(), + ], /** * The shared class-helper builders (`design/design.ts`) assemble their class * chains at runtime, so every app scans that one file (it carries * `@unocss-include`) for extraction regardless of its own framework globs. */ content: { - filesystem: [fileURLToPath(new URL('./design.ts', import.meta.url))], + filesystem: [ + fileURLToPath(new URL('./design.ts', import.meta.url)), + ], /** * Restates UnoCSS's default pipeline exclude. Without it, `mergeConfigs` * leaves `exclude: []`, and UnoCSS 66.11 then treats every module as @@ -68,11 +75,17 @@ export function createDesignConfig(options: CreateDesignConfigOptions = {}) { * Wind leaves bare `border`/`border-b` at currentColor; restore the subtle * shared border color (matching `border-base`) for unqualified borders. */ - preflights: [{ getCSS: () => '*,::before,::after{border-color:#8882}' }], + preflights: [ + { + getCSS: () => '*,::before,::after{border-color:#8882}', + }, + ], theme: { // Stable palette for status marks and preview content that intentionally // keeps the default accent when the surrounding panel adopts a theme. - colors: { devframe: resolvePrimary('#3a6a45') }, + colors: { + devframe: resolvePrimary('#3a6a45'), + }, }, shortcuts: { /** Fixed semantic colors stay independent of the panel's primary accent. */ @@ -193,7 +206,9 @@ export function rewireBakedPrimaryColors(css: string, primaryRamp: Record assistant?.faqQuestions ?? []) @@ -58,7 +60,9 @@ async function copyConversation() { const text = messages.value .map((message) => { const content = message.parts.filter(isTextUIPart).map(part => part.text).join('\n') - return `${message.role === 'user' ? 'User' : 'Assistant'}:\n${content}` + return `${message.role === 'user' + ? 'User' + : 'Assistant'}:\n${content}` }) .join('\n\n') await navigator.clipboard.writeText(text) @@ -76,12 +80,23 @@ function toolMeta(part: ToolUIPart | DynamicToolUIPart) { const streaming = isToolStreaming(part) const input = part.input as Record | undefined if (name === 'search_docs') { - return { icon: 'i-lucide-text-search', text: streaming ? 'Searching the docs' : 'Searched the docs', suffix: input?.query } + return { + icon: 'i-lucide-text-search', + text: streaming ? 'Searching the docs' : 'Searched the docs', + suffix: input?.query, + } } if (name === 'get_page') { - return { icon: 'i-lucide-book-open', text: streaming ? 'Reading a page' : 'Read a page', suffix: input?.path } + return { + icon: 'i-lucide-book-open', + text: streaming ? 'Reading a page' : 'Read a page', + suffix: input?.path, + } + } + return { + icon: 'i-lucide-wrench', + text: name.replace(/_/g, ' '), } - return { icon: 'i-lucide-wrench', text: name.replace(/_/g, ' ') } } /** Live tool rows show while the answer streams; once done they collapse into one "Used N sources" row. */ @@ -100,8 +115,11 @@ function messageSources(message: UIMessage) { for (const part of message.parts) { if (isToolUIPart(part) && getToolName(part) === 'get_page') { const path = (part.input as { path?: string } | undefined)?.path - if (path) - paths.add(path.startsWith('/') ? path : `/${path}`) + if (path) { + paths.add(path.startsWith('/') + ? path + : `/${path}`) + } } } return [...paths] @@ -113,7 +131,9 @@ function messageToolCount(message: UIMessage) { function sourcesLabel(message: UIMessage) { const count = messageSources(message).length || messageToolCount(message) - return `Used ${count} source${count === 1 ? '' : 's'}` + return `Used ${count} source${count === 1 + ? '' + : 's'}` } diff --git a/docs/app/components/BrandAssetCard.vue b/docs/app/components/BrandAssetCard.vue index 4f70d3d19..a1a5f403c 100644 --- a/docs/app/components/BrandAssetCard.vue +++ b/docs/app/components/BrandAssetCard.vue @@ -28,7 +28,9 @@ async function copySvg(): Promise { function downloadSvg(): void { triggerDownload( - URL.createObjectURL(new Blob([withXmlns(props.svg)], { type: 'image/svg+xml;charset=utf-8' })), + URL.createObjectURL(new Blob([ + withXmlns(props.svg), + ], { type: 'image/svg+xml;charset=utf-8' })), `${props.file}.svg`, ) } diff --git a/docs/app/components/OgImage/OgImageDocs.satori.vue b/docs/app/components/OgImage/OgImageDocs.satori.vue index 750581f33..31d8df0d9 100644 --- a/docs/app/components/OgImage/OgImageDocs.satori.vue +++ b/docs/app/components/OgImage/OgImageDocs.satori.vue @@ -20,7 +20,9 @@ const { seo, docs } = useAppConfig() const site = useSiteConfig() const siteName = seo?.siteName || site.name || '' -const host = site.url ? site.url.replace(/^https?:\/\//, '').replace(/\/$/, '') : '' +const host = site.url + ? site.url.replace(/^https?:\/\//, '').replace(/\/$/, '') + : '' const accent = docs?.ogImage?.accent || '#fafafa' diff --git a/docs/app/components/global/DevToolsStack.vue b/docs/app/components/global/DevToolsStack.vue index dd1c366af..34c84f795 100644 --- a/docs/app/components/global/DevToolsStack.vue +++ b/docs/app/components/global/DevToolsStack.vue @@ -137,7 +137,9 @@ const activePart = computed(() => activePartId.value ? parts[activePartId.value] const activeGroup = computed(() => activePartId.value ? parts[activePartId.value].group : undefined) function togglePart(id: PartId) { - selectedPart.value = selectedPart.value === id ? undefined : id + selectedPart.value = selectedPart.value === id + ? undefined + : id } function partStateClass(id: PartId) { diff --git a/docs/app/components/global/DevframeEcosystemMap.vue b/docs/app/components/global/DevframeEcosystemMap.vue index 6af55b843..c85bd26d1 100644 --- a/docs/app/components/global/DevframeEcosystemMap.vue +++ b/docs/app/components/global/DevframeEcosystemMap.vue @@ -166,7 +166,9 @@ const nodes: EcosystemNode[] = [ source: 'devframe', emphasis: true, label: 'initDevframe()', - waypoints: [{ x: 70, y: 320 }], + waypoints: [ + { x: 70, y: 320 }, + ], }, { source: 'hub', emphasis: true, label: 'initHub()' }, ], @@ -309,7 +311,10 @@ const nodes: EcosystemNode[] = [ }, { id: 'nuxt-devtools', - linksFrom: [{ source: 'vite-devtools', emphasis: true }, 'vue-devtools'], + linksFrom: [ + { source: 'vite-devtools', emphasis: true }, + 'vue-devtools', + ], label: 'Nuxt DevTools', icon: 'i-logos-nuxt-icon', href: 'https://devtools.nuxt.com/guide/getting-started', @@ -325,14 +330,21 @@ const edges: EcosystemEdge[] = nodes.flatMap((node) => { if (!node.linksFrom) return [] - const links = Array.isArray(node.linksFrom) ? node.linksFrom : [node.linksFrom] + const links = Array.isArray(node.linksFrom) + ? node.linksFrom + : [node.linksFrom] return links.map(link => ({ - ...(typeof link === 'string' ? { source: link } : link), + ...(typeof link === 'string' + ? { source: link } + : link), target: node.id, })) }) -const rawLayoutNodes: LayoutNode[] = nodes.map(({ position, ...node }) => ({ ...node, ...position })) +const rawLayoutNodes: LayoutNode[] = nodes.map(({ position, ...node }) => ({ + ...node, + ...position, +})) const bounds = layoutBounds(rawLayoutNodes) const diagramWidth = bounds.width + diagramPadding.x * 2 const diagramHeight = bounds.height + diagramPadding.y * 2 @@ -384,7 +396,12 @@ function layoutBounds(layout: LayoutNode[]) { const right = Math.max(...layout.map(node => node.x + node.width / 2)) const top = Math.min(...layout.map(node => node.y - node.height / 2)) const bottom = Math.max(...layout.map(node => node.y + node.height / 2)) - return { left, top, width: right - left, height: bottom - top } + return { + left, + top, + width: right - left, + height: bottom - top, + } } function clipEdge(points: Point[], source: LayoutNode, target: LayoutNode): Point[] { @@ -400,8 +417,12 @@ function clipEdge(points: Point[], source: LayoutNode, target: LayoutNode): Poin function pointOnNodeBoundary(center: Point, toward: Point, node: LayoutNode): Point { const dx = toward.x - center.x const dy = toward.y - center.y - const scaleX = dx === 0 ? Number.POSITIVE_INFINITY : node.width / 2 / Math.abs(dx) - const scaleY = dy === 0 ? Number.POSITIVE_INFINITY : node.height / 2 / Math.abs(dy) + const scaleX = dx === 0 + ? Number.POSITIVE_INFINITY + : node.width / 2 / Math.abs(dx) + const scaleY = dy === 0 + ? Number.POSITIVE_INFINITY + : node.height / 2 / Math.abs(dy) const scale = Math.min(scaleX, scaleY) return { x: center.x + dx * scale, y: center.y + dy * scale } } @@ -425,9 +446,15 @@ function pointAlongPolyline(points: Point[], ratio: number, offset = 0): Point { continue } - const progress = segment.length === 0 ? 0 : distance / segment.length - const normalX = segment.length === 0 ? 0 : -segment.dy / segment.length - const normalY = segment.length === 0 ? 0 : segment.dx / segment.length + const progress = segment.length === 0 + ? 0 + : distance / segment.length + const normalX = segment.length === 0 + ? 0 + : -segment.dy / segment.length + const normalY = segment.length === 0 + ? 0 + : segment.dx / segment.length return { x: segment.previous.x + segment.dx * progress + normalX * offset, y: segment.previous.y + segment.dy * progress + normalY * offset, diff --git a/docs/app/components/global/DevframeMountExamples.vue b/docs/app/components/global/DevframeMountExamples.vue index 8ca51ce8e..1ca17ecfc 100644 --- a/docs/app/components/global/DevframeMountExamples.vue +++ b/docs/app/components/global/DevframeMountExamples.vue @@ -106,7 +106,9 @@ const selected = ref('hono') const current = computed(() => examples.find(example => example.id === selected.value)!) const colorMode = useColorMode() const highlighter = shallowRef() -const shikiTheme = computed(() => colorMode.value === 'dark' ? 'vitesse-dark' : 'vitesse-light') +const shikiTheme = computed(() => colorMode.value === 'dark' + ? 'vitesse-dark' + : 'vitesse-light') let disposed = false diff --git a/docs/app/components/global/EcosystemList.vue b/docs/app/components/global/EcosystemList.vue index bff254a15..db5c3a2b9 100644 --- a/docs/app/components/global/EcosystemList.vue +++ b/docs/app/components/global/EcosystemList.vue @@ -23,7 +23,12 @@ interface EcosystemPackage { const props = defineProps<{ packages: EcosystemPackage[] }>() -const categories: Category[] = ['All', 'Devframes', 'Hosts', 'Services'] +const categories: Category[] = [ + 'All', + 'Devframes', + 'Hosts', + 'Services', +] const route = useRoute() const router = useRouter() @@ -79,7 +84,9 @@ const searchPool = computed(() => { }) const counts = computed(() => { - const map = new Map([['All', searchPool.value.length]]) + const map = new Map([ + ['All', searchPool.value.length], + ]) for (const cat of categories.slice(1)) map.set(cat, searchPool.value.filter(pkg => pkg.category === cat).length) return map @@ -91,14 +98,19 @@ const visible = computed(() => { : searchPool.value.filter(pkg => pkg.category === category.value) // Community entries first: the official ones already have their own docs pages. return [...pool].sort((a, b) => { - if (!!a.official !== !!b.official) - return a.official ? 1 : -1 + if (!!a.official !== !!b.official) { + return a.official + ? 1 + : -1 + } return a.name.localeCompare(b.name) }) }) function href(pkg: EcosystemPackage) { - return pkg.url ?? (pkg.repo ? `https://github.com/${pkg.repo}` : undefined) + return pkg.url ?? (pkg.repo + ? `https://github.com/${pkg.repo}` + : undefined) } function isExternal(pkg: EcosystemPackage) { diff --git a/docs/app/components/global/GettingStartedWizard.vue b/docs/app/components/global/GettingStartedWizard.vue index aafc25dbe..85e483de5 100644 --- a/docs/app/components/global/GettingStartedWizard.vue +++ b/docs/app/components/global/GettingStartedWizard.vue @@ -65,9 +65,27 @@ const sections: WizardSection[] = [ hint: 'What do you expect your tool to work with?', icon: 'i-lucide-target', items: [ - { value: 'standalone', label: 'Standalone', icon: 'i-lucide-terminal', color: 'sky', description: 'A CLI or dev server with no host framework' }, - { value: 'framework', label: 'Specific framework', icon: 'i-lucide-shapes', color: 'violet', description: 'Specifically for frameworks like Vite, Next.js, Nuxt, etc.' }, - { value: 'all', label: 'All frameworks', icon: 'i-lucide-infinity', color: 'emerald', description: 'I want to support as many frameworks as possible' }, + { + value: 'standalone', + label: 'Standalone', + icon: 'i-lucide-terminal', + color: 'sky', + description: 'A CLI or dev server with no host framework', + }, + { + value: 'framework', + label: 'Specific framework', + icon: 'i-lucide-shapes', + color: 'violet', + description: 'Specifically for frameworks like Vite, Next.js, Nuxt, etc.', + }, + { + value: 'all', + label: 'All frameworks', + icon: 'i-lucide-infinity', + color: 'emerald', + description: 'I want to support as many frameworks as possible', + }, ], }, { @@ -76,8 +94,20 @@ const sections: WizardSection[] = [ hint: 'Where do you want to visualize data from?', icon: 'i-lucide-database', items: [ - { value: 'node', label: 'The node side', icon: 'i-lucide-server', color: 'indigo', description: 'Server state, build output, the filesystem, child processes' }, - { value: 'browser', label: 'The user\'s web app', icon: 'i-lucide-app-window', color: 'cyan', description: 'State living in the page you\'re developing' }, + { + value: 'node', + label: 'The node side', + icon: 'i-lucide-server', + color: 'indigo', + description: 'Server state, build output, the filesystem, child processes', + }, + { + value: 'browser', + label: 'The user\'s web app', + icon: 'i-lucide-app-window', + color: 'cyan', + description: 'State living in the page you\'re developing', + }, ], }, { @@ -86,10 +116,34 @@ const sections: WizardSection[] = [ hint: 'When is the data available?', icon: 'i-lucide-clock', items: [ - { value: 'dev', label: 'Development time', icon: 'i-lucide-code', color: 'blue', description: 'Live, over a running dev server' }, - { value: 'build', label: 'Production build time', icon: 'i-lucide-hammer', color: 'amber', description: 'Data from the production build' }, - { value: 'static', label: 'Statically available', icon: 'i-lucide-hard-drive', color: 'teal', description: 'Local filesystem, uploaded files, etc.' }, - { value: 'remote', label: 'Remotely', icon: 'i-lucide-cloud', color: 'sky', description: 'Over the web' }, + { + value: 'dev', + label: 'Development time', + icon: 'i-lucide-code', + color: 'blue', + description: 'Live, over a running dev server', + }, + { + value: 'build', + label: 'Production build time', + icon: 'i-lucide-hammer', + color: 'amber', + description: 'Data from the production build', + }, + { + value: 'static', + label: 'Statically available', + icon: 'i-lucide-hard-drive', + color: 'teal', + description: 'Local filesystem, uploaded files, etc.', + }, + { + value: 'remote', + label: 'Remotely', + icon: 'i-lucide-cloud', + color: 'sky', + description: 'Over the web', + }, ], }, { @@ -98,9 +152,27 @@ const sections: WizardSection[] = [ hint: 'How do you want to build the frontend view?', icon: 'i-lucide-palette', items: [ - { value: 'framework', label: 'A preferred framework', icon: 'i-lucide-component', color: 'green', description: 'Vue, React, Svelte, Solid...' }, - { value: 'webcomponents', label: 'Web Components', icon: 'i-lucide-box', color: 'orange', description: 'Use Web Components for renderering' }, - { value: 'nodeside', label: 'Build it on the node side', icon: 'i-lucide-braces', color: 'purple', description: 'Describe the UI as data instead of shipping a bundle' }, + { + value: 'framework', + label: 'A preferred framework', + icon: 'i-lucide-component', + color: 'green', + description: 'Vue, React, Svelte, Solid...', + }, + { + value: 'webcomponents', + label: 'Web Components', + icon: 'i-lucide-box', + color: 'orange', + description: 'Use Web Components for renderering', + }, + { + value: 'nodeside', + label: 'Build it on the node side', + icon: 'i-lucide-braces', + color: 'purple', + description: 'Describe the UI as data instead of shipping a bundle', + }, ], }, { @@ -109,11 +181,41 @@ const sections: WizardSection[] = [ hint: 'Any specific requirements?', icon: 'i-lucide-list-checks', items: [ - { value: 'agent', label: 'Exposed to coding agents', icon: 'i-lucide-bot', color: 'pink', description: 'Some functionality should be available to coding agents.' }, - { value: 'terminal', label: 'Sub process access', icon: 'i-lucide-square-terminal', color: 'amber', description: 'Need to spawn other child process from the node side' }, - { value: 'streaming', label: 'Streaming data', icon: 'i-lucide-radio', color: 'rose', description: 'Push chunk-style data from the node side to the browser side' }, - { value: 'deep-linking', label: 'Deep linking', icon: 'i-lucide-link', color: 'cyan', description: 'Shareable URLs into a specific view' }, - { value: 'overlay', label: 'User app overlay', icon: 'i-lucide-layers', color: 'fuchsia', description: 'I want to overlay a UI on top of the user\'s web app' }, + { + value: 'agent', + label: 'Exposed to coding agents', + icon: 'i-lucide-bot', + color: 'pink', + description: 'Some functionality should be available to coding agents.', + }, + { + value: 'terminal', + label: 'Sub process access', + icon: 'i-lucide-square-terminal', + color: 'amber', + description: 'Need to spawn other child process from the node side', + }, + { + value: 'streaming', + label: 'Streaming data', + icon: 'i-lucide-radio', + color: 'rose', + description: 'Push chunk-style data from the node side to the browser side', + }, + { + value: 'deep-linking', + label: 'Deep linking', + icon: 'i-lucide-link', + color: 'cyan', + description: 'Shareable URLs into a specific view', + }, + { + value: 'overlay', + label: 'User app overlay', + icon: 'i-lucide-layers', + color: 'fuchsia', + description: 'I want to overlay a UI on top of the user\'s web app', + }, ], }, ] @@ -294,7 +396,9 @@ function buildCopyPrompt(): string { '', 'Devframe is a framework-neutral foundation for building a devtool once and running it anywhere: mounted inside any host framework (Vite, Nuxt, Next.js, …), as a standalone CLI or a static build, or exposed to coding agents over MCP. A devframe pairs a node side with a browser side over type-safe RPC and shared state, and ships its UI as a built SPA.', '', - lines.length ? `What I want to build:\n${lines.join('\n')}` : 'I am just getting started and want a solid foundation.', + lines.length + ? `What I want to build:\n${lines.join('\n')}` + : 'I am just getting started and want a solid foundation.', '', 'Please help me design and implement this with Devframe. Relevant documentation:', ...docs, diff --git a/docs/app/components/global/UniversalDevToolsEcosystem.vue b/docs/app/components/global/UniversalDevToolsEcosystem.vue index 8ca2c63c0..89141e6c9 100644 --- a/docs/app/components/global/UniversalDevToolsEcosystem.vue +++ b/docs/app/components/global/UniversalDevToolsEcosystem.vue @@ -19,17 +19,72 @@ const frameworkOptions: Array<{ image?: string label: string }> = [ - { id: 'nuxt', icon: 'i-logos-nuxt-icon', label: 'Nuxt', description: 'Highlight capabilities for Nuxt DevTools' }, - { id: 'vue', icon: 'i-logos-vue', label: 'Vue', description: 'Highlight capabilities for Vue DevTools' }, - { id: 'next', icon: 'i-logos-nextjs-icon', label: 'Next.js', description: 'Highlight capabilities for Next.js DevTools' }, - { id: 'react', icon: 'i-logos-react', label: 'React', description: 'Highlight capabilities for React DevTools' }, - { id: 'hono', icon: 'i-logos-hono', label: 'Hono', description: 'Highlight capabilities for Hono DevTools' }, - { id: 'nitro', icon: 'i-unjs-nitro', label: 'Nitro', description: 'Highlight capabilities for Nitro DevTools' }, - { id: 'svelte', icon: 'i-logos-svelte-icon', label: 'Svelte', description: 'Highlight capabilities for Svelte DevTools' }, - { id: 'solid', icon: 'i-logos-solidjs-icon', label: 'Solid', description: 'Highlight capabilities for Solid DevTools' }, - { id: 'astro', icon: 'i-logos-astro-icon', label: 'Astro', description: 'Highlight capabilities for Astro DevTools' }, - { id: 'rsbuild', image: '/images/devframe/rsbuild.svg', label: 'Rsbuild', description: 'Highlight capabilities for Rsbuild DevTools' }, - { id: 'your', icon: 'i-twemoji-winking-face', label: 'Your DevTools?', description: 'Show every capability for your own DevTools' }, + { + id: 'nuxt', + icon: 'i-logos-nuxt-icon', + label: 'Nuxt', + description: 'Highlight capabilities for Nuxt DevTools', + }, + { + id: 'vue', + icon: 'i-logos-vue', + label: 'Vue', + description: 'Highlight capabilities for Vue DevTools', + }, + { + id: 'next', + icon: 'i-logos-nextjs-icon', + label: 'Next.js', + description: 'Highlight capabilities for Next.js DevTools', + }, + { + id: 'react', + icon: 'i-logos-react', + label: 'React', + description: 'Highlight capabilities for React DevTools', + }, + { + id: 'hono', + icon: 'i-logos-hono', + label: 'Hono', + description: 'Highlight capabilities for Hono DevTools', + }, + { + id: 'nitro', + icon: 'i-unjs-nitro', + label: 'Nitro', + description: 'Highlight capabilities for Nitro DevTools', + }, + { + id: 'svelte', + icon: 'i-logos-svelte-icon', + label: 'Svelte', + description: 'Highlight capabilities for Svelte DevTools', + }, + { + id: 'solid', + icon: 'i-logos-solidjs-icon', + label: 'Solid', + description: 'Highlight capabilities for Solid DevTools', + }, + { + id: 'astro', + icon: 'i-logos-astro-icon', + label: 'Astro', + description: 'Highlight capabilities for Astro DevTools', + }, + { + id: 'rsbuild', + image: '/images/devframe/rsbuild.svg', + label: 'Rsbuild', + description: 'Highlight capabilities for Rsbuild DevTools', + }, + { + id: 'your', + icon: 'i-twemoji-winking-face', + label: 'Your DevTools?', + description: 'Show every capability for your own DevTools', + }, ] const moduleGroups: Array<{ @@ -55,11 +110,34 @@ const moduleGroups: Array<{ modules: [ { image: '/images/devframe/vitest.svg', name: 'Vitest', theme: 'green' }, { image: '/images/devframe/oxc.svg', name: 'Oxlint', theme: 'blue' }, - { frameworks: 'nuxt vue astro svelte react solid', icon: 'i-ph-cube-duotone', name: 'Bundle analyzer', logoImage: '/images/devframe/vite.svg', theme: 'purple' }, - { frameworks: 'nuxt vue astro svelte react solid', icon: 'i-ph-magnifying-glass-duotone', name: 'Plugin analyzer', logoImage: '/images/devframe/vite.svg', theme: 'purple' }, - { frameworks: 'nuxt vue astro svelte react solid', icon: 'i-ph-sliders-horizontal-duotone', name: 'Vite config', logoImage: '/images/devframe/vite.svg', theme: 'purple' }, + { + frameworks: 'nuxt vue astro svelte react solid', + icon: 'i-ph-cube-duotone', + name: 'Bundle analyzer', + logoImage: '/images/devframe/vite.svg', + theme: 'purple', + }, + { + frameworks: 'nuxt vue astro svelte react solid', + icon: 'i-ph-magnifying-glass-duotone', + name: 'Plugin analyzer', + logoImage: '/images/devframe/vite.svg', + theme: 'purple', + }, + { + frameworks: 'nuxt vue astro svelte react solid', + icon: 'i-ph-sliders-horizontal-duotone', + name: 'Vite config', + logoImage: '/images/devframe/vite.svg', + theme: 'purple', + }, { image: '/images/devframe/rolldown.svg', name: 'Rolldown', theme: 'orange' }, - { frameworks: 'rsbuild nuxt', image: '/images/devframe/rsdoctor.svg', name: 'Rsdoctor', theme: 'blue' }, + { + frameworks: 'rsbuild nuxt', + image: '/images/devframe/rsdoctor.svg', + name: 'Rsdoctor', + theme: 'blue', + }, { frameworks: 'next', icon: 'i-logos-turbopack-icon', name: 'Turbopack' }, ], }, @@ -67,22 +145,111 @@ const moduleGroups: Array<{ id: 'frameworks', name: 'Framework-specific', modules: [ - { frameworks: 'nuxt vue astro', icon: 'i-carbon-assembly-cluster', name: 'Components', logo: 'i-logos-vue', theme: 'green' }, - { frameworks: 'nuxt vue astro', icon: 'i-carbon-network-4', name: 'Reactivity', logo: 'i-logos-vue', theme: 'green' }, - { frameworks: 'nuxt vue astro', icon: 'i-ph-signpost-duotone', name: 'Router', logo: 'i-logos-vue', theme: 'green' }, - { frameworks: 'nuxt vue astro', icon: 'i-icon-park-outline-pineapple', name: 'Pinia', logo: 'i-logos-vue', theme: 'green' }, - { frameworks: 'nuxt', icon: 'i-ph-shapes-duotone', name: 'Nuxt modules', logo: 'i-logos-nuxt-icon', theme: 'teal' }, - { frameworks: 'nuxt', icon: 'i-carbon-function', name: 'Auto imports', logo: 'i-logos-nuxt-icon', theme: 'teal' }, - { frameworks: 'nuxt', icon: 'i-carbon-volume-file-storage', name: 'File router', logo: 'i-logos-nuxt-icon', theme: 'teal' }, - { frameworks: 'nuxt nitro', icon: 'i-carbon-network-public', name: 'Server API', logo: 'i-unjs-nitro', theme: 'pink' }, + { + frameworks: 'nuxt vue astro', + icon: 'i-carbon-assembly-cluster', + name: 'Components', + logo: 'i-logos-vue', + theme: 'green', + }, + { + frameworks: 'nuxt vue astro', + icon: 'i-carbon-network-4', + name: 'Reactivity', + logo: 'i-logos-vue', + theme: 'green', + }, + { + frameworks: 'nuxt vue astro', + icon: 'i-ph-signpost-duotone', + name: 'Router', + logo: 'i-logos-vue', + theme: 'green', + }, + { + frameworks: 'nuxt vue astro', + icon: 'i-icon-park-outline-pineapple', + name: 'Pinia', + logo: 'i-logos-vue', + theme: 'green', + }, + { + frameworks: 'nuxt', + icon: 'i-ph-shapes-duotone', + name: 'Nuxt modules', + logo: 'i-logos-nuxt-icon', + theme: 'teal', + }, + { + frameworks: 'nuxt', + icon: 'i-carbon-function', + name: 'Auto imports', + logo: 'i-logos-nuxt-icon', + theme: 'teal', + }, + { + frameworks: 'nuxt', + icon: 'i-carbon-volume-file-storage', + name: 'File router', + logo: 'i-logos-nuxt-icon', + theme: 'teal', + }, + { + frameworks: 'nuxt nitro', + icon: 'i-carbon-network-public', + name: 'Server API', + logo: 'i-unjs-nitro', + theme: 'pink', + }, { frameworks: 'next', icon: 'i-logos-nextjs-icon', name: 'Next.js DevTools' }, - { frameworks: 'react astro next', icon: 'i-logos-react', name: 'React DevTools', theme: 'blue' }, - { frameworks: 'react astro next', icon: 'i-carbon-data-set', name: 'State management', logo: 'i-logos-react', theme: 'blue' }, - { frameworks: 'react astro next', icon: 'i-ph-signpost-duotone', name: 'Router', logo: 'i-logos-react', theme: 'blue' }, - { frameworks: 'svelte astro', icon: 'i-ph-signpost-duotone', name: 'File router', logo: 'i-logos-svelte-icon', theme: 'red' }, - { frameworks: 'svelte astro', icon: 'i-carbon-assembly-cluster', name: 'Components', logo: 'i-logos-svelte-icon', theme: 'red' }, - { frameworks: 'solid astro', icon: 'i-carbon-network-4', name: 'Reactivity', logo: 'i-logos-solidjs-icon', theme: 'blue' }, - { frameworks: 'astro', icon: 'i-carbon-page-scroll', name: 'Content', logo: 'i-logos-astro-icon', theme: 'orange' }, + { + frameworks: 'react astro next', + icon: 'i-logos-react', + name: 'React DevTools', + theme: 'blue', + }, + { + frameworks: 'react astro next', + icon: 'i-carbon-data-set', + name: 'State management', + logo: 'i-logos-react', + theme: 'blue', + }, + { + frameworks: 'react astro next', + icon: 'i-ph-signpost-duotone', + name: 'Router', + logo: 'i-logos-react', + theme: 'blue', + }, + { + frameworks: 'svelte astro', + icon: 'i-ph-signpost-duotone', + name: 'File router', + logo: 'i-logos-svelte-icon', + theme: 'red', + }, + { + frameworks: 'svelte astro', + icon: 'i-carbon-assembly-cluster', + name: 'Components', + logo: 'i-logos-svelte-icon', + theme: 'red', + }, + { + frameworks: 'solid astro', + icon: 'i-carbon-network-4', + name: 'Reactivity', + logo: 'i-logos-solidjs-icon', + theme: 'blue', + }, + { + frameworks: 'astro', + icon: 'i-carbon-page-scroll', + name: 'Content', + logo: 'i-logos-astro-icon', + theme: 'orange', + }, ], }, { @@ -110,7 +277,9 @@ const focusedModule = ref() const activeModule = computed(() => hoveredModule.value ?? focusedModule.value) function toggleFramework(framework: Framework) { - selectedFramework.value = selectedFramework.value === framework ? undefined : framework + selectedFramework.value = selectedFramework.value === framework + ? undefined + : framework } function moduleSupportsFramework(module: ModuleItem, framework: Framework) { diff --git a/docs/app/composables/useFilteredNavigation.ts b/docs/app/composables/useFilteredNavigation.ts index 3ad85579d..954f0fdc7 100644 --- a/docs/app/composables/useFilteredNavigation.ts +++ b/docs/app/composables/useFilteredNavigation.ts @@ -31,12 +31,16 @@ interface HeaderNavGroup { /** Logical top-level segment of a path, ignoring the active version `base`. */ function segmentOf(path: string, base: string): string { - const rel = base && path.startsWith(base) ? path.slice(base.length) : path + const rel = base && path.startsWith(base) + ? path.slice(base.length) + : path return rel.split('/').filter(Boolean)[0] ?? '' } function relOf(path: string, base: string): string { - return (base && path.startsWith(base) ? path.slice(base.length) : path) || '/' + return (base && path.startsWith(base) + ? path.slice(base.length) + : path) || '/' } export function useFilteredNavigation(): ComputedRef { @@ -53,13 +57,23 @@ export function useFilteredNavigation(): ComputedRef { const headerGroups = (appConfig.header?.nav ?? []) as HeaderNavGroup[] const groups = headerGroups.length ? headerGroups - : nav.map(item => ({ label: item.title, sections: [segmentOf(item.path, base)] })) + : nav.map(item => ({ + label: item.title, + sections: [ + segmentOf(item.path, base), + ], + })) const sidebarGroups = (appConfig as { docs?: { sidebarGroups?: Record } }) .docs ?.sidebarGroups const matched = groups.find(group => group.sections?.includes(seg)) - ?? (sidebarGroups?.[seg] ? { label: seg, sections: [seg] } : undefined) + ?? (sidebarGroups?.[seg] + ? { + label: seg, + sections: [seg], + } + : undefined) // A section reachable only through a manual tab (e.g. migrations, under the // version dropdown) still gets its own flat sidebar. if (!matched) { @@ -75,7 +89,9 @@ export function useFilteredNavigation(): ComputedRef { return nav // Single-section tab with configured groups: labeled subsections. - const groupsConfig = sections.length === 1 ? sidebarGroups?.[sections[0]!] : undefined + const groupsConfig = sections.length === 1 + ? sidebarGroups?.[sections[0]!] + : undefined if (groupsConfig) { // Index every page by base-relative path, preferring leaf pages over // section nodes (a section node carries the directory title). @@ -118,7 +134,10 @@ export function useFilteredNavigation(): ComputedRef { const node = nav.find(item => segmentOf(item.path, base) === sections[0]) const leftovers = (node?.children ?? []) .filter(child => !used.has(relOf(child.path, base))) - return [...grouped, ...leftovers] + return [ + ...grouped, + ...leftovers, + ] } // Single-section tab: that section's children as a flat tree. diff --git a/docs/app/pages/logos.vue b/docs/app/pages/logos.vue index 02b2c2482..d9b84aa80 100644 --- a/docs/app/pages/logos.vue +++ b/docs/app/pages/logos.vue @@ -23,7 +23,9 @@ useSeoMeta({ }) useHead({ - link: [{ rel: 'canonical', href: canonicalUrl }], + link: [ + { rel: 'canonical', href: canonicalUrl }, + ], }) defineOgImage('DocsSatori', { diff --git a/docs/content/1.guide/1.tutorial-server-data-inspector.md b/docs/content/1.guide/1.tutorial-server-data-inspector.md index e31785259..7556bb8c2 100644 --- a/docs/content/1.guide/1.tutorial-server-data-inspector.md +++ b/docs/content/1.guide/1.tutorial-server-data-inspector.md @@ -68,8 +68,12 @@ const dataInspectorFrame = defineDevframe({ handler: () => Object.entries(serverState).map(([key, value]) => ({ key, - type: Array.isArray(value) ? 'array' : typeof value, - length: Array.isArray(value) ? value.length : undefined, + type: Array.isArray(value) + ? 'array' + : typeof value, + length: Array.isArray(value) + ? value.length + : undefined, })), }) @@ -157,7 +161,9 @@ export function App() { {m.key} {' - '} {m.type} - {m.length != null ? ` (${m.length})` : ''} + {m.length != null + ? ` (${m.length})` + : ''} ))} @@ -236,7 +242,9 @@ export default defineConfig({ plugins: [ viteDevframeHub({ devframes: [dataInspectorFrame], - ui: createUi({ branding: { productName: 'My Devtools' } }), + ui: createUi({ + branding: { productName: 'My Devtools' } + }), }), ], }) diff --git a/docs/content/1.guide/10.standalone-cli.md b/docs/content/1.guide/10.standalone-cli.md index 1133dd052..2133fdd94 100644 --- a/docs/content/1.guide/10.standalone-cli.md +++ b/docs/content/1.guide/10.standalone-cli.md @@ -250,7 +250,9 @@ defineDevframe({ })) if (ctx.mode === 'dev') { - const version = await my.rpc.sharedState('version', { initialValue: { ts: 0 } }) + const version = await my.rpc.sharedState('version', { + initialValue: { ts: 0 } + }) const { default: chokidar } = await import('chokidar') const watcher = chokidar.watch(flags.config ?? [], { ignoreInitial: true }) watcher.on('change', () => { diff --git a/docs/content/1.guide/12.in-page-channel.md b/docs/content/1.guide/12.in-page-channel.md index 344a433b3..1d72e819b 100644 --- a/docs/content/1.guide/12.in-page-channel.md +++ b/docs/content/1.guide/12.in-page-channel.md @@ -77,7 +77,10 @@ import { MY_CHANNEL } from '../shared/protocol' const pageChannel = createPageScriptChannel({ name: MY_CHANNEL, functions: { - reset: { type: 'action', handler: async () => clearSelections() }, + reset: { + type: 'action', + handler: async () => clearSelections() + }, measure: { // request/response (the default `query` type) handler: (selector) => { const rect = document.querySelector(selector)!.getBoundingClientRect() @@ -133,7 +136,9 @@ The channel's shared-state layer mirrors [`rpc.sharedState`](/guide/shared-state ```ts // Page script (the authority): -const state = await channel.sharedState.get('state', { initialValue: { selections: [] } }) +const state = await channel.sharedState.get('state', { + initialValue: { selections: [] } +}) state.mutate((draft) => { draft.selections.push('.hero') }) @@ -191,7 +196,12 @@ Declaring a function `jsonSerializable: true` additionally enforces strict JSON The same app open in two tabs means two page scripts on one origin. Each page script carries a per-tab instance id (persisted in `sessionStorage`), and handshakes are targeted `postMessage`, so a dock panel always pairs with its own tab's page script. A panel can also pin explicitly: ```ts -connectPanelChannel({ name: MY_CHANNEL, instanceId, functions: {}, events: { flash: {} } }) +connectPanelChannel({ + name: MY_CHANNEL, + instanceId, + functions: {}, + events: { flash: {} } +}) ``` ## Custom transports @@ -201,7 +211,12 @@ Both endpoints accept a pre-established `MessagePort` that bypasses the handshak ```ts const { port1, port2 } = new MessageChannel() pageScript.addPanelPort(port1) -const panel = connectPanelChannel({ name: MY_CHANNEL, transport: port2, functions: {}, events: { flash: {} } }) +const panel = connectPanelChannel({ + name: MY_CHANNEL, + transport: port2, + functions: {}, + events: { flash: {} } +}) ``` ## When to use the in-page channel vs RPC diff --git a/docs/content/1.guide/13.transports.md b/docs/content/1.guide/13.transports.md index c8369a5fb..0e2447549 100644 --- a/docs/content/1.guide/13.transports.md +++ b/docs/content/1.guide/13.transports.md @@ -37,7 +37,11 @@ initDevframe(def, { base: '/__my-tool/', ws: false }) initDevframe(def, { base: '/__my-tool/', server, sse: false }) // Rename the SSE route. -initDevframe(def, { base: '/__my-tool/', server, sse: { route: '__events' } }) +initDevframe(def, { + base: '/__my-tool/', + server, + sse: { route: '__events' } +}) ``` `ws: false` + `sse: false` runs RPC-less (`backend: 'none'`); the SPA, discovery, and MCP routes still serve. The same options apply to `createDevServer`, `initHub`, and `cli.ws` / `cli.sse` defaults. diff --git a/docs/content/1.guide/14.security.md b/docs/content/1.guide/14.security.md index b17bfc347..443cf6f99 100644 --- a/docs/content/1.guide/14.security.md +++ b/docs/content/1.guide/14.security.md @@ -43,7 +43,9 @@ import { createInteractiveAuth } from 'devframe/recipes/interactive-auth' // The adapters gate with this layer by default. Construct it yourself only to // tune it (e.g. CI tokens) and hand it to `initDevframe` / `initHub` as `auth`. const auth = createInteractiveAuth(ctx, { - clientAuthTokens: process.env.CI ? [process.env.DEVFRAME_CI_TOKEN!] : undefined, + clientAuthTokens: process.env.CI + ? [process.env.DEVFRAME_CI_TOKEN!] + : undefined, }) ``` diff --git a/docs/content/1.guide/15.agent-native.md b/docs/content/1.guide/15.agent-native.md index 87d1e3fb6..28b96536b 100644 --- a/docs/content/1.guide/15.agent-native.md +++ b/docs/content/1.guide/15.agent-native.md @@ -19,8 +19,15 @@ import { defineRpcFunction } from 'devframe' export const getSessionSummary = defineRpcFunction({ name: 'rolldown-get-session-summary', type: 'query', - args: [v.object({ sessionId: v.string() })], - returns: v.object({ durationMs: v.number(), chunkCount: v.number() }), + args: [ + v.object({ + sessionId: v.string() + }) + ], + returns: v.object({ + durationMs: v.number(), + chunkCount: v.number() + }), agent: { description: 'Summarize a Rolldown build session. Safe to call freely.', title: 'Build summary', @@ -92,7 +99,9 @@ ctx.agent.registerResource({ name: 'Current Rolldown session', description: 'Markdown snapshot of the active build session.', mimeType: 'text/markdown', - read: () => ({ text: renderMarkdown(currentSession) }), + read: () => ({ + text: renderMarkdown(currentSession) + }), }) ``` diff --git a/docs/content/1.guide/16.hub.md b/docs/content/1.guide/16.hub.md index a48fcaf92..bdaed873b 100644 --- a/docs/content/1.guide/16.hub.md +++ b/docs/content/1.guide/16.hub.md @@ -38,7 +38,11 @@ ctx.commands.register({ title: 'Run build', agent: { description: 'Run the production build. Call after config or dependency changes to verify the app still builds.', - args: [v.object({ configFile: v.optional(v.string()) })], + args: [ + v.object({ + configFile: v.optional(v.string()) + }) + ], }, handler: (opts?: { configFile?: string }) => runBuild(opts), }) @@ -72,7 +76,14 @@ ctx.commands.register({ id: 'app:cache', title: 'Cache', children: [ - { id: 'app:cache:clear', title: 'Clear', keybindings: [{ key: 'Mod+Shift+K' }], handler: clearCache }, + { + id: 'app:cache:clear', + title: 'Clear', + keybindings: [ + { key: 'Mod+Shift+K' } + ], + handler: clearCache + }, ], }) ``` @@ -114,22 +125,38 @@ const launcher = ctx.docks.register({ async function runBuild() { const session = await ctx.terminals.startChildProcess( - { command: 'vite', args: ['build'] }, + { + command: 'vite', + args: ['build'] + }, { id: 'app:build-session', title: 'vite build' }, ) - launcher.update({ launcher: { title: 'Run build', command: 'app:build', status: 'loading', terminalSessionId: session.id } }) + launcher.update({ + launcher: { + title: 'Run build', + command: 'app:build', + status: 'loading', + terminalSessionId: session.id + } + }) // A child-process session keeps its `status` live: `running` → `stopped` on a // clean exit, `error` on a non-zero exit or spawn failure. Map it onto the // launcher and read the exit code from getResult(). const { exitCode } = await session.getResult() - launcher.update({ launcher: { - title: 'Run build', - command: 'app:build', - terminalSessionId: session.id, - status: exitCode === 0 ? 'success' : 'error', - error: exitCode === 0 ? undefined : `vite build exited ${exitCode}`, - } }) + launcher.update({ + launcher: { + title: 'Run build', + command: 'app:build', + terminalSessionId: session.id, + status: exitCode === 0 + ? 'success' + : 'error', + error: exitCode === 0 + ? undefined + : `vite build exited ${exitCode}`, + } + }) } ``` diff --git a/docs/content/1.guide/17.client-context.md b/docs/content/1.guide/17.client-context.md index 6a85e6c3e..f488b5772 100644 --- a/docs/content/1.guide/17.client-context.md +++ b/docs/content/1.guide/17.client-context.md @@ -95,7 +95,9 @@ import type { DockClientScriptContext } from '@devframes/hub/client' export default function setup(ctx: DockClientScriptContext) { const id = ctx.current.entryMeta.id ctx.current.events.on('entry:activated', () => { - startPicker({ onPick: () => ctx.docks.setActionActive(id, false) }) + startPicker({ + onPick: () => ctx.docks.setActionActive(id, false) + }) }) ctx.current.events.on('entry:deactivated', () => stopPicker()) } diff --git a/docs/content/1.guide/18.hub-initiate.md b/docs/content/1.guide/18.hub-initiate.md index d45fbdd1a..e8381b470 100644 --- a/docs/content/1.guide/18.hub-initiate.md +++ b/docs/content/1.guide/18.hub-initiate.md @@ -15,10 +15,17 @@ import { createTerminalsDevframe } from '@devframes/plugin-terminals' export const hub = initHub({ base: DEVFRAMES_HUB_BASE, // required: the conventional `/__devframes/` - devframes: [createInspectDevframe(), createTerminalsDevframe()], + devframes: [ + createInspectDevframe(), + createTerminalsDevframe() + ], ui: createUi(), configure(ctx) { - ctx.commands.register({ id: 'app:hello', title: 'Hello', handler: () => 'hi' }) + ctx.commands.register({ + id: 'app:hello', + title: 'Hello', + handler: () => 'hi' + }) }, }) ``` @@ -77,7 +84,9 @@ import { jsonRenderUiRenderer } from '@devframes/json-render-ui/hub' initHub({ ui: createUi(), - renderers: [jsonRenderUiRenderer()], + renderers: [ + jsonRenderUiRenderer() + ], }) ``` @@ -115,7 +124,10 @@ import { buildHub } from '@devframes/hub/build' await buildHub({ outDir: 'dist/__devframes', // corresponds to `base` at serve time - devframes: [createA11yDevframe(), createMessagesDevframe()], + devframes: [ + createA11yDevframe(), + createMessagesDevframe() + ], ui: createUi(), }) ``` diff --git a/docs/content/1.guide/19.services.md b/docs/content/1.guide/19.services.md index 97f9c0d91..e6d604e74 100644 --- a/docs/content/1.guide/19.services.md +++ b/docs/content/1.guide/19.services.md @@ -37,7 +37,10 @@ A consumer loads it with a types-only import (`import type {} from '@my-org/my-p ```ts ctx.services.whenAvailable('my-plugin:sources', (sources) => { - sources.register({ id: 'other-plugin:state', data: () => state }) + sources.register({ + id: 'other-plugin:state', + data: () => state + }) }) ``` @@ -64,7 +67,10 @@ export default function createOpenService(options?: OpenServiceOptions): Devfram options, setup(ctx, { options }) { // `ctx` is pre-scoped: this registers `devframes:service:open:open-in-editor` - ctx.rpc.register({ name: 'open-in-editor', handler: input => api.openInEditor(input) }) + ctx.rpc.register({ + name: 'open-in-editor', + handler: input => api.openInEditor(input) + }) return api // the node API served from ctx.services.get(package) }, } @@ -83,7 +89,13 @@ defineDevframe({ importMetaUrl: import.meta.url, // resolution base for the declared packages services: [ { package: '@devframes/service-open' }, - { package: '@devframes/service-shiki', version: '^1', options: { langs: ['vue'] } }, + { + package: '@devframes/service-shiki', + version: '^1', + options: { + langs: ['vue'] + } + }, ], }) ``` diff --git a/docs/content/1.guide/2.devframe-definition.md b/docs/content/1.guide/2.devframe-definition.md index 6180023cb..44b4e4de5 100644 --- a/docs/content/1.guide/2.devframe-definition.md +++ b/docs/content/1.guide/2.devframe-definition.md @@ -74,7 +74,9 @@ export default defineDevframe({ */ clientAssets: { package: `${pkg.name}--assets`, version: pkg.version }, /** Imported from `my-tool`'s own dependency graph. */ - services: [{ package: '@scope/my-service', version: pkg.version }], + services: [ + { package: '@scope/my-service', version: pkg.version } + ], setup(ctx) { /* … */ }, }) ``` @@ -219,7 +221,11 @@ import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' import { createBuild } from 'devframe/adapters/build' import { createCac } from 'devframe/adapters/cac' -const myDevframe = defineDevframe({ id: 'my-tool', name: 'My Tool', setup() {} }) +const myDevframe = defineDevframe({ + id: 'my-tool', + name: 'My Tool', + setup() {} +}) // 1. Standalone CLI: await createCac(myDevframe).parse() diff --git a/docs/content/1.guide/21.build-your-own-json-render-frontend.md b/docs/content/1.guide/21.build-your-own-json-render-frontend.md index cdeb92059..9c714d0e9 100644 --- a/docs/content/1.guide/21.build-your-own-json-render-frontend.md +++ b/docs/content/1.guide/21.build-your-own-json-render-frontend.md @@ -19,7 +19,9 @@ import type { JsonRenderDockRenderer } from '@devframes/json-render/hub' // a hub DockRenderer narrowed to the json-render dock entry const renderer: JsonRenderDockRenderer = async ({ entry, container, context }) => { // mount your framework's root into `container`, render `entry.view` - return { dispose() { /* unmount, unsubscribe */ } } + return { + dispose() { /* unmount, unsubscribe */ } + } } ``` diff --git a/docs/content/1.guide/23.hub-ui-onboard.md b/docs/content/1.guide/23.hub-ui-onboard.md index b27249a60..41f8cce6d 100644 --- a/docs/content/1.guide/23.hub-ui-onboard.md +++ b/docs/content/1.guide/23.hub-ui-onboard.md @@ -88,7 +88,13 @@ const onboarding = createOnboarding({ load('@devframes/hub/initiate'), load('@devframes/hub-ui'), ]) - const hub = initHub({ base: '/__devframes/', cwd, server: httpServer, ui: createUi(), devframes: [] }) + const hub = initHub({ + base: '/__devframes/', + cwd, + server: httpServer, + ui: createUi(), + devframes: [] + }) return hub.handler }, }) @@ -117,7 +123,9 @@ import type { Plugin } from 'vite' import { createOnboarding } from '@devframes/hub-ui-onboard' function hubOnboarding(): Plugin { - const onboarding = createOnboarding({ packages: ['@devframes/hub', '@devframes/hub-ui'] }) + const onboarding = createOnboarding({ + packages: ['@devframes/hub', '@devframes/hub-ui'] + }) return { name: 'hub-onboarding', apply: 'serve', @@ -127,7 +135,13 @@ function hubOnboarding(): Plugin { transformIndexHtml() { return onboarding.disabled ? [] - : [{ tag: 'script', attrs: { type: 'module', src: onboarding.scriptSrc }, injectTo: 'body' }] + : [ + { + tag: 'script', + attrs: { type: 'module', src: onboarding.scriptSrc }, + injectTo: 'body' + } + ] }, } } diff --git a/docs/content/1.guide/3.rpc.md b/docs/content/1.guide/3.rpc.md index 8ed1835fb..812082a9a 100644 --- a/docs/content/1.guide/3.rpc.md +++ b/docs/content/1.guide/3.rpc.md @@ -16,8 +16,15 @@ import * as v from 'valibot' // npm i valibot (or use zod / arktype) export const getModules = defineRpcFunction({ name: 'get-modules', // bare: the scope namespaces it to `my-tool:get-modules` type: 'query', - args: [v.object({ limit: v.number() })], - returns: v.array(v.object({ id: v.string(), size: v.number() })), + args: [ + v.object({ + limit: v.number() + }) + ], + returns: v.array(v.object({ + id: v.string(), + size: v.number() + })), setup: ctx => ({ handler: async ({ limit }) => { // `ctx` is the full DevframeNodeContext. @@ -72,7 +79,9 @@ defineDevframe({ watcher.on('change', (file) => { void my.rpc.broadcast({ method: 'on-file-changed', // -> my-tool:on-file-changed - args: [{ file }], + args: [ + { file } + ], }) }) }, @@ -149,9 +158,15 @@ defineRpcFunction({ name: 'build-meta', type: 'static', args: [], - returns: v.object({ version: v.string(), builtAt: v.number() }), + returns: v.object({ + version: v.string(), + builtAt: v.number() + }), setup: () => ({ - handler: async () => ({ version: '1.0.0', builtAt: Date.now() }), + handler: async () => ({ + version: '1.0.0', + builtAt: Date.now() + }), }), }) ``` @@ -165,7 +180,10 @@ defineRpcFunction({ setup: ctx => ({ handler: async (id: string) => loadSession(id), dump: { - inputs: [['session-a'], ['session-b']], + inputs: [ + ['session-a'], + ['session-b'] + ], fallback: { id: 'unknown', data: null }, }, }), @@ -193,8 +211,15 @@ Add an `agent` field to expose the function to coding agents over MCP: defineRpcFunction({ name: 'get-modules', type: 'query', - args: [v.object({ limit: v.number() })], - returns: v.array(v.object({ id: v.string(), size: v.number() })), + args: [ + v.object({ + limit: v.number() + }) + ], + returns: v.array(v.object({ + id: v.string(), + size: v.number() + })), agent: { description: 'List the N largest modules in the current build. Safe to call freely.', title: 'List modules', diff --git a/docs/content/1.guide/5.streaming.md b/docs/content/1.guide/5.streaming.md index 5aea18a35..6f66f1c20 100644 --- a/docs/content/1.guide/5.streaming.md +++ b/docs/content/1.guide/5.streaming.md @@ -44,8 +44,14 @@ export default defineDevframe({ name: 'start-chat', // -> my-tool:start-chat type: 'action', jsonSerializable: true, - args: [v.object({ prompt: v.string() })], - returns: v.object({ streamId: v.string() }), + args: [ + v.object({ + prompt: v.string() + }) + ], + returns: v.object({ + streamId: v.string() + }), handler: async ({ prompt }) => { const stream = channel.start() ;(async () => { @@ -131,8 +137,14 @@ In reverse: an RPC call allocates the id; events carry chunks. ctx.rpc.register(defineRpcFunction({ name: 'my-tool:upload-file', type: 'action', - args: [v.object({ name: v.string() })], - returns: v.object({ uploadId: v.string() }), + args: [ + v.object({ + name: v.string() + }) + ], + returns: v.object({ + uploadId: v.string() + }), handler: async ({ name }) => { const reader = channel.openInbound() diff --git a/docs/content/1.guide/8.json-render.md b/docs/content/1.guide/8.json-render.md index 7eace6675..f75f948be 100644 --- a/docs/content/1.guide/8.json-render.md +++ b/docs/content/1.guide/8.json-render.md @@ -30,8 +30,18 @@ export default defineDevframe({ spec: { root: 'root', elements: { - root: { type: 'Card', props: { title: 'Live metrics' }, children: ['count'] }, - count: { type: 'Text', props: { text: { $state: '/count' } }, children: [] }, + root: { + type: 'Card', + props: { title: 'Live metrics' }, + children: ['count'] + }, + count: { + type: 'Text', + props: { + text: { $state: '/count' } + }, + children: [] + }, }, state: { count: 0 }, }, @@ -40,7 +50,9 @@ export default defineDevframe({ // A structural change replaces the whole spec… view.update(nextSpec) // …while state travels as JSON-Pointer patches (only the changed path crosses the wire). - view.patchState([{ op: 'replace', path: '/count', value: 3 }]) + view.patchState([ + { op: 'replace', path: '/count', value: 3 } + ]) // Unregisters the shared state and its listeners. // view.dispose() @@ -125,7 +137,9 @@ import { toJsonRenderDockEntry } from '@devframes/json-render/hub' initHub({ ui: createUi(), - renderers: [jsonRenderUiRenderer()], + renderers: [ + jsonRenderUiRenderer() + ], configure(ctx) { ctx.docks.register(toJsonRenderDockEntry(view, { id: 'metrics', diff --git a/docs/content/1.guide/index.md b/docs/content/1.guide/index.md index eec8a3297..b31876e65 100644 --- a/docs/content/1.guide/index.md +++ b/docs/content/1.guide/index.md @@ -94,7 +94,10 @@ import { createTerminalsDevframe } from '@devframes/plugin-terminals' const hub = initHub({ base: DEVFRAMES_HUB_BASE, - devframes: [createDataInspectorDevframe(), createTerminalsDevframe()], + devframes: [ + createDataInspectorDevframe(), + createTerminalsDevframe() + ], ui: createUi(), }) diff --git a/docs/content/2.adapters/1.initiate.md b/docs/content/2.adapters/1.initiate.md index bef257003..631873c4c 100644 --- a/docs/content/2.adapters/1.initiate.md +++ b/docs/content/2.adapters/1.initiate.md @@ -31,17 +31,19 @@ import { defineConfig } from 'vite' import myDevframe from './my-tool' export default defineConfig({ - plugins: [{ - name: 'my-tool', - apply: 'serve', - configureServer(server) { - const devtools = initDevframe(myDevframe, { - base: '/__my-tool/', - server: server.httpServer ?? undefined, - }) - server.middlewares.use(devtools.nodeMiddleware) - }, - }], + plugins: [ + { + name: 'my-tool', + apply: 'serve', + configureServer(server) { + const devtools = initDevframe(myDevframe, { + base: '/__my-tool/', + server: server.httpServer ?? undefined, + }) + server.middlewares.use(devtools.nodeMiddleware) + }, + } + ], }) ``` diff --git a/docs/content/2.adapters/7.mcp.md b/docs/content/2.adapters/7.mcp.md index 7767de6a1..b28ee3c2a 100644 --- a/docs/content/2.adapters/7.mcp.md +++ b/docs/content/2.adapters/7.mcp.md @@ -65,7 +65,9 @@ Every shared-state key is exposed to agents by default, through the `devframe_st ```ts devframeViteBridge(myDevframe, { - mcp: { exposeSharedState: key => !key.startsWith('my-tool:private:') }, + mcp: { + exposeSharedState: key => !key.startsWith('my-tool:private:') + }, }) ``` @@ -88,13 +90,17 @@ devframeViteBridge(myDevframe, { ```ts devframeViteBridge(myDevframe, { mcp: { - resourceTemplates: [{ - uriTemplate: 'my-tool://module/{id}', - name: 'module', - mimeType: 'application/json', - list: ctx => listModules(ctx).map(id => ({ uri: `my-tool://module/${encodeURIComponent(id)}`, name: id })), - read: ({ id }, _uri, ctx) => ({ json: findModule(ctx, id) }), - }], + resourceTemplates: [ + { + uriTemplate: 'my-tool://module/{id}', + name: 'module', + mimeType: 'application/json', + list: ctx => listModules(ctx).map(id => ({ uri: `my-tool://module/${encodeURIComponent(id)}`, name: id })), + read: ({ id }, _uri, ctx) => ({ + json: findModule(ctx, id) + }), + } + ], }, }) ``` @@ -127,14 +133,23 @@ devframeViteBridge(myDevframe, { ```ts devframeViteBridge(myDevframe, { mcp: { - prompts: [{ - name: 'explain-module', - title: 'Explain a module', - arguments: [{ name: 'id', description: 'The module id.', required: true }], - get: ({ id }) => ({ - messages: [{ role: 'user', content: { type: 'text', text: `Read my-tool://module/${encodeURIComponent(id)} and explain what the module does.` } }], - }), - }], + prompts: [ + { + name: 'explain-module', + title: 'Explain a module', + arguments: [ + { name: 'id', description: 'The module id.', required: true } + ], + get: ({ id }) => ({ + messages: [ + { + role: 'user', + content: { type: 'text', text: `Read my-tool://module/${encodeURIComponent(id)} and explain what the module does.` } + } + ], + }), + } + ], }, }) ``` diff --git a/docs/content/3.frameworks/1.vite.md b/docs/content/3.frameworks/1.vite.md index a4b967127..908efdacf 100644 --- a/docs/content/3.frameworks/1.vite.md +++ b/docs/content/3.frameworks/1.vite.md @@ -16,7 +16,9 @@ import myDevframe from './my-tool' export default defineConfig({ /** Statically mounts the built SPA at `/__/`, with no RPC server: */ - plugins: [devframeVitePlugin(myDevframe)], + plugins: [ + devframeVitePlugin(myDevframe) + ], // Or bridge the RPC/WS backend into this dev server instead, so the // user app owns the SPA: // plugins: [devframeViteBridge(myDevframe)], @@ -59,7 +61,9 @@ import { viteDevframeHub } from '@devframes/vite/hub' import { defineConfig } from 'vite' export default defineConfig({ - plugins: [viteDevframeHub({ devframes: [] })], + plugins: [ + viteDevframeHub({ devframes: [] }) + ], }) ``` diff --git a/docs/content/3.frameworks/2.nuxt.md b/docs/content/3.frameworks/2.nuxt.md index 77fcce46a..6dffae659 100644 --- a/docs/content/3.frameworks/2.nuxt.md +++ b/docs/content/3.frameworks/2.nuxt.md @@ -58,7 +58,12 @@ Pass a devframe definition: import myDevframe from './src/my-tool' // defineDevframe(...) export export default defineNuxtConfig({ - modules: [['@devframes/nuxt/single', { devframe: myDevframe }]], + modules: [ + [ + '@devframes/nuxt/single', + { devframe: myDevframe } + ] + ], }) ``` @@ -75,14 +80,19 @@ On by default when `devframe` is set; disable it (browser side only) with `devMi ```ts [nuxt.config.ts] export default defineNuxtConfig({ - modules: [['@devframes/nuxt/single', { - devframe: myDevframe, - devMiddleware: { - port: 7777, - host: '0.0.0.0', - flags: { config: process.env.MY_CONFIG }, - }, - }]], + modules: [ + [ + '@devframes/nuxt/single', + { + devframe: myDevframe, + devMiddleware: { + port: 7777, + host: '0.0.0.0', + flags: { config: process.env.MY_CONFIG }, + }, + } + ] + ], }) ``` @@ -111,7 +121,9 @@ At build time it sets the `app.baseURL` / `vite.base` defaults, merges `{ devfra ```ts const rpc = await connectDevframe({ baseURL: config.public.devframe.baseURL }) -return { provide: { rpc } } +return { + provide: { rpc } +} ``` At runtime the SPA fetches `./__connection.json` and branches on `backend`: `websocket` in dev, `static` from a `createBuild` snapshot. @@ -122,7 +134,12 @@ At runtime the SPA fetches `./__connection.json` and branches on `backend`: `web ```ts [nuxt.config.ts] export default defineNuxtConfig({ - modules: [['@devframes/nuxt/hub', { devframes: [] }]], + modules: [ + [ + '@devframes/nuxt/hub', + { devframes: [] } + ] + ], }) ``` diff --git a/docs/content/3.frameworks/3.next.md b/docs/content/3.frameworks/3.next.md index f7ded548b..a29a00c8f 100644 --- a/docs/content/3.frameworks/3.next.md +++ b/docs/content/3.frameworks/3.next.md @@ -100,8 +100,15 @@ import { useRpc, useRpcStatus } from '@devframes/next/single/client' export function Panel() { const rpc = useRpc()?.scope('my-tool:') const { error } = useRpcStatus() - if (!rpc) - return

{error ? `connection failed: ${error.message}` : 'connecting…'}

+ if (!rpc) { + return ( +

+ {error + ? `connection failed: ${error.message}` + : 'connecting…'} +

+ ) + } // rpc.rpc.call('get-payload'), rpc.sharedState, … } ``` diff --git a/docs/content/5.add-ons/1.devframes/1.data-inspector.md b/docs/content/5.add-ons/1.devframes/1.data-inspector.md index d4953d625..519de033b 100644 --- a/docs/content/5.add-ons/1.devframes/1.data-inspector.md +++ b/docs/content/5.add-ons/1.devframes/1.data-inspector.md @@ -106,7 +106,13 @@ The target starts the inject endpoint: import { exposeDataInspector } from '@devframes/plugin-data-inspector/inject' await exposeDataInspector({ - sources: [{ id: 'app:store', title: 'App store', data: () => store }], + sources: [ + { + id: 'app:store', + title: 'App store', + data: () => store + } + ], }) ``` diff --git a/docs/content/5.add-ons/1.devframes/4.a11y.md b/docs/content/5.add-ons/1.devframes/4.a11y.md index 6ed566470..17eaf0551 100644 --- a/docs/content/5.add-ons/1.devframes/4.a11y.md +++ b/docs/content/5.add-ons/1.devframes/4.a11y.md @@ -34,7 +34,9 @@ The page script and the panel talk over the [in-page channel](/guide/in-page-cha The definition declares the page script as its dock [client script](/guide/client-context), so mounting by package name just works: ```ts -initHub({ devframes: ['@devframes/plugin-a11y'] }) +initHub({ + devframes: ['@devframes/plugin-a11y'] +}) ``` The hub serves the bundle same-origin and a client runtime imports it into the host page. Each scan also mirrors into the hub's messages feed: a summary plus one per rule. @@ -45,7 +47,9 @@ A host can also mount the module itself, for example a Vite host via `/@fs/`: import createA11yDevframe, { a11yClientScriptBundlePath } from '@devframes/plugin-a11y' await ctx.install(createA11yDevframe(), { - dock: { clientScript: { importFrom: `/@fs/${a11yClientScriptBundlePath}` } }, + dock: { + clientScript: { importFrom: `/@fs/${a11yClientScriptBundlePath}` } + }, }) ``` diff --git a/docs/content/5.add-ons/1.devframes/5.git.md b/docs/content/5.add-ons/1.devframes/5.git.md index c3b806073..5bcd4f975 100644 --- a/docs/content/5.add-ons/1.devframes/5.git.md +++ b/docs/content/5.add-ons/1.devframes/5.git.md @@ -33,7 +33,9 @@ pnpx @devframes/plugin-git build # static deploy → dist-static/ import { createGitDevframe } from '@devframes/plugin-git' import { createCac } from 'devframe/adapters/cac' -await createCac(createGitDevframe({ repoRoot: process.cwd() })).parse() +await createCac(createGitDevframe({ + repoRoot: process.cwd() +})).parse() ``` | Option | Default | Description | diff --git a/docs/content/5.add-ons/1.devframes/6.terminals.md b/docs/content/5.add-ons/1.devframes/6.terminals.md index 0fbe36653..2bd2a64e4 100644 --- a/docs/content/5.add-ons/1.devframes/6.terminals.md +++ b/docs/content/5.add-ons/1.devframes/6.terminals.md @@ -50,7 +50,12 @@ import { createTerminalsDevframe } from '@devframes/plugin-terminals' export default createTerminalsDevframe({ presets: [ - { id: 'dev', title: 'pnpm dev', command: 'pnpm', args: ['dev'] }, + { + id: 'dev', + title: 'pnpm dev', + command: 'pnpm', + args: ['dev'] + }, ], }) ``` diff --git a/docs/content/5.add-ons/2.services/1.open.md b/docs/content/5.add-ons/2.services/1.open.md index acb493780..19efd4ad3 100644 --- a/docs/content/5.add-ons/2.services/1.open.md +++ b/docs/content/5.add-ons/2.services/1.open.md @@ -15,7 +15,10 @@ Package: `@devframes/service-open` · Scope: `devframes:service:open` defineDevframe({ importMetaUrl: import.meta.url, services: [ - { package: '@devframes/service-open', options: { editor: 'code' } }, + { + package: '@devframes/service-open', + options: { editor: 'code' } + }, ], }) ``` diff --git a/docs/content/5.add-ons/2.services/2.git.md b/docs/content/5.add-ons/2.services/2.git.md index 5a73b2f1a..d9414d6f3 100644 --- a/docs/content/5.add-ons/2.services/2.git.md +++ b/docs/content/5.add-ons/2.services/2.git.md @@ -15,7 +15,12 @@ Package: `@devframes/service-git` · Scope: `devframes:service:git` defineDevframe({ importMetaUrl: import.meta.url, services: [ - { package: '@devframes/service-git', options: { cwd: process.cwd() } }, + { + package: '@devframes/service-git', + options: { + cwd: process.cwd() + } + }, ], }) ``` diff --git a/docs/content/5.add-ons/2.services/3.shiki.md b/docs/content/5.add-ons/2.services/3.shiki.md index 5bdd114a8..44e2c9087 100644 --- a/docs/content/5.add-ons/2.services/3.shiki.md +++ b/docs/content/5.add-ons/2.services/3.shiki.md @@ -15,7 +15,12 @@ Package: `@devframes/service-shiki` · Scope: `devframes:service:shiki` defineDevframe({ importMetaUrl: import.meta.url, services: [ - { package: '@devframes/service-shiki', options: { langs: ['vue', 'ts'] } }, + { + package: '@devframes/service-shiki', + options: { + langs: ['vue', 'ts'] + } + }, ], }) ``` diff --git a/docs/content/5.add-ons/2.services/index.md b/docs/content/5.add-ons/2.services/index.md index 8f2d2a0e7..4906d92f9 100644 --- a/docs/content/5.add-ons/2.services/index.md +++ b/docs/content/5.add-ons/2.services/index.md @@ -22,7 +22,13 @@ defineDevframe({ importMetaUrl: import.meta.url, // resolution base for the declared packages services: [ { package: '@devframes/service-open' }, - { package: '@devframes/service-shiki', version: '^1', options: { langs: ['vue'] } }, + { + package: '@devframes/service-shiki', + version: '^1', + options: { + langs: ['vue'] + } + }, ], }) ``` diff --git a/docs/content/6.errors/DF0019.md b/docs/content/6.errors/DF0019.md index e3955b9d9..d0c9a0e7f 100644 --- a/docs/content/6.errors/DF0019.md +++ b/docs/content/6.errors/DF0019.md @@ -18,7 +18,9 @@ defineRpcFunction({ name: 'my-plugin:summary', agent: { description: 'Returns a summary' }, jsonSerializable: false, // ✗ throws DF0019 - handler: () => ({ items: [1, 2, 3] }), + handler: () => ({ + items: [1, 2, 3] + }), }) ``` @@ -31,7 +33,9 @@ defineRpcFunction({ name: 'my-plugin:summary', jsonSerializable: true, agent: { description: 'Returns a summary' }, - handler: () => ({ items: [1, 2, 3] }), + handler: () => ({ + items: [1, 2, 3] + }), }) ``` diff --git a/docs/content/6.errors/DF0020.md b/docs/content/6.errors/DF0020.md index fee3bd260..08d6f6f73 100644 --- a/docs/content/6.errors/DF0020.md +++ b/docs/content/6.errors/DF0020.md @@ -25,7 +25,9 @@ defineRpcFunction({ name: 'my-plugin:graph', jsonSerializable: true, handler: () => ({ - nodes: new Map([['a', 1]]), // ✗ throws DF0020: type=Map, path="nodes" + nodes: new Map([ + ['a', 1] + ]), // ✗ throws DF0020: type=Map, path="nodes" }), }) ``` diff --git a/docs/content/6.errors/DF0021.md b/docs/content/6.errors/DF0021.md index 7876e43ed..7ddddcb51 100644 --- a/docs/content/6.errors/DF0021.md +++ b/docs/content/6.errors/DF0021.md @@ -16,7 +16,10 @@ description: 'RPC function "{name}" is already registered' Either give the second registration a distinct name, or pass `force: true` to overwrite the previous one (e.g. during HMR-driven re-registration). ```ts -ctx.rpc.register(defineRpcFunction({ name: 'my-plugin:fn', handler: () => 1 }), true /* force */) +ctx.rpc.register(defineRpcFunction({ + name: 'my-plugin:fn', + handler: () => 1 +}), true /* force */) ``` ## Source diff --git a/docs/content/6.errors/DF0026.md b/docs/content/6.errors/DF0026.md index fb10be9bb..8c5870334 100644 --- a/docs/content/6.errors/DF0026.md +++ b/docs/content/6.errors/DF0026.md @@ -19,7 +19,9 @@ Either widen the function's `dump.inputs` to cover the requested arguments, or p defineRpcFunction({ name: 'my-plugin:get', dump: { - inputs: [['known-id']], + inputs: [ + ['known-id'] + ], fallback: null, }, }) diff --git a/docs/content/6.errors/DF0038.md b/docs/content/6.errors/DF0038.md index d7462bb0f..865a9f3f0 100644 --- a/docs/content/6.errors/DF0038.md +++ b/docs/content/6.errors/DF0038.md @@ -17,7 +17,16 @@ description: 'JSON-render view "{id}" received invalid props on element "{key}": createJsonRenderView(ctx, { id: 'toolbar', /** ✗ throws DF0038: `variant` is not a Button variant */ - spec: { root: 'a', elements: { a: { type: 'Button', props: { variant: 'nope' }, children: [] } } }, + spec: { + root: 'a', + elements: { + a: { + type: 'Button', + props: { variant: 'nope' }, + children: [] + } + } + }, }) ``` diff --git a/docs/content/6.errors/DF0043.md b/docs/content/6.errors/DF0043.md index 41890c2ab..0641082df 100644 --- a/docs/content/6.errors/DF0043.md +++ b/docs/content/6.errors/DF0043.md @@ -16,7 +16,9 @@ Each declared `args` schema validates its argument before the handler runs, on e ```ts const greet = defineRpcFunction({ name: 'greet', - args: [v.string()], + args: [ + v.string() + ], returns: v.string(), handler: name => `hi ${name}`, }) diff --git a/docs/content/6.errors/DF0055.md b/docs/content/6.errors/DF0055.md index 99ab2d252..c79ce2457 100644 --- a/docs/content/6.errors/DF0055.md +++ b/docs/content/6.errors/DF0055.md @@ -16,7 +16,10 @@ description: 'This instance already owns its WebSocket transport ({tier}), so it ```ts import { initHub } from '@devframes/hub/initiate' -const hub = initHub({ base: '/__devframes/', ws: { sidecar: true } }) +const hub = initHub({ + base: '/__devframes/', + ws: { sidecar: true } +}) hub.attach(myServer) // ✗ throws DF0055: the side-car already serves `__ws` ``` diff --git a/docs/content/6.errors/DF0066.md b/docs/content/6.errors/DF0066.md index d5bb166db..360155cfb 100644 --- a/docs/content/6.errors/DF0066.md +++ b/docs/content/6.errors/DF0066.md @@ -25,7 +25,9 @@ Declare the service so its options join the pre-setup merge: on the devframe's ` ```ts initHub({ - services: [createShikiService({ themes })], // ✓ merges before setup + services: [ + createShikiService({ themes }) + ], // ✓ merges before setup devframes: [/* … */], }) ``` diff --git a/docs/content/6.errors/DF0081.md b/docs/content/6.errors/DF0081.md index 8b27e6401..f1dc58e86 100644 --- a/docs/content/6.errors/DF0081.md +++ b/docs/content/6.errors/DF0081.md @@ -20,7 +20,9 @@ ctx.agent.registerTool({ id: 'my-plugin:snapshot', description: 'Take a snapshot.', // The image block has no `mimeType`. - handler: () => withMcpContent({}, [{ type: 'image', data: png }]), + handler: () => withMcpContent({}, [ + { type: 'image', data: png } + ]), }) ``` diff --git a/docs/content/6.errors/DF0084.md b/docs/content/6.errors/DF0084.md index df6ab936a..e44797c3a 100644 --- a/docs/content/6.errors/DF0084.md +++ b/docs/content/6.errors/DF0084.md @@ -16,11 +16,15 @@ An entry in the `resourceTemplates` list of the MCP route options (or of `create ```ts initDevframe(myDevframe, { mcp: { - resourceTemplates: [{ - uriTemplate: 'my-tool://file/{+path}', // `+` is a level 2 operator → DF0084 - name: 'file', - read: ({ path }) => ({ text: readFileSync(path, 'utf8') }), - }], + resourceTemplates: [ + { + uriTemplate: 'my-tool://file/{+path}', // `+` is a level 2 operator → DF0084 + name: 'file', + read: ({ path }) => ({ + text: readFileSync(path, 'utf8') + }), + } + ], }, }) ``` @@ -30,7 +34,13 @@ initDevframe(myDevframe, { Use a plain `{name}` expression for each value. A value matches one URI segment, so a value with a `/` (such as a file path) comes in percent-encoded (`my-tool://file/src%2Fmain.ts`) and reaches `read` decoded (`src/main.ts`): ```ts -const template = { uriTemplate: 'my-tool://file/{path}', name: 'file', read: ({ path }) => ({ text: readFileSync(path, 'utf8') }) } +const template = { + uriTemplate: 'my-tool://file/{path}', + name: 'file', + read: ({ path }) => ({ + text: readFileSync(path, 'utf8') + }) +} ``` ## Source diff --git a/docs/content/6.errors/DF0085.md b/docs/content/6.errors/DF0085.md index 7e77a27c0..db1846337 100644 --- a/docs/content/6.errors/DF0085.md +++ b/docs/content/6.errors/DF0085.md @@ -17,8 +17,14 @@ Two entries in the `prompts` list of the MCP route options (or of `createMcpServ initDevframe(myDevframe, { mcp: { prompts: [ - { name: 'review', get: () => ({ messages: [] }) }, - { name: 'review', get: () => ({ messages: [] }) }, // same name → DF0085 + { + name: 'review', + get: () => ({ messages: [] }) + }, + { + name: 'review', + get: () => ({ messages: [] }) + }, // same name → DF0085 ], }, }) diff --git a/docs/content/6.errors/DF8000.md b/docs/content/6.errors/DF8000.md index 43a8c354a..e67ed4630 100644 --- a/docs/content/6.errors/DF8000.md +++ b/docs/content/6.errors/DF8000.md @@ -18,7 +18,9 @@ import { initHub } from '@devframes/hub/initiate' initHub({ base: '/__devframes/', - devframes: [defineDevframe({ id: '__mcp', /* … */ })], // ✗ throws DF8000 + devframes: [ + defineDevframe({ id: '__mcp', /* … */ }) + ], // ✗ throws DF8000 }) ``` diff --git a/docs/content/6.errors/DF8002.md b/docs/content/6.errors/DF8002.md index 79be99e55..37b74f7d6 100644 --- a/docs/content/6.errors/DF8002.md +++ b/docs/content/6.errors/DF8002.md @@ -15,10 +15,17 @@ description: 'initHub/buildHub received both devframes and context; the two asse ```ts // ✗ Bad -initHub({ base: '/__devframes/', devframes: [git], context: myCtx }) +initHub({ + base: '/__devframes/', + devframes: [git], + context: myCtx +}) // ✓ Good, declarative: -initHub({ base: '/__devframes/', devframes: [git] }) +initHub({ + base: '/__devframes/', + devframes: [git] +}) // ✓ Good, bring your own context: const ctx = await createHubContext({ host: myHost, cwd }) diff --git a/docs/content/6.errors/DF8003.md b/docs/content/6.errors/DF8003.md index 8e9269abc..3243039b4 100644 --- a/docs/content/6.errors/DF8003.md +++ b/docs/content/6.errors/DF8003.md @@ -16,7 +16,10 @@ description: 'connectionMeta() was called before initHub finished initializing.' ```ts import { initHub } from '@devframes/hub/initiate' -const hub = initHub({ base: '/__devframes/', devframes: [git] }) +const hub = initHub({ + base: '/__devframes/', + devframes: [git] +}) hub.connectionMeta() // ✗ throws DF8003: init is still in flight await hub.ready diff --git a/docs/content/6.errors/DF8004.md b/docs/content/6.errors/DF8004.md index c8e1f4aed..8e4d91322 100644 --- a/docs/content/6.errors/DF8004.md +++ b/docs/content/6.errors/DF8004.md @@ -18,7 +18,9 @@ import { initHub } from '@devframes/hub/initiate' initHub({ base: '/__devframes/', - devframes: [defineDevframe({ id: 'devframes:plugin:my-tool', /* … */ })], // ✗ throws DF8004 + devframes: [ + defineDevframe({ id: 'devframes:plugin:my-tool', /* … */ }) + ], // ✗ throws DF8004 }) // ✓ Good, route-safe id (letters, digits, `_`, `-`, `.`): diff --git a/docs/content/7.migrations/2.migration-0.9.md b/docs/content/7.migrations/2.migration-0.9.md index ad5d2f0dd..4be47a04b 100644 --- a/docs/content/7.migrations/2.migration-0.9.md +++ b/docs/content/7.migrations/2.migration-0.9.md @@ -218,7 +218,9 @@ The `devMiddleware` option is gone; bridge options flatten to the top level (`po import { viteDevBridge } from 'devframe/helpers/vite' export default defineConfig({ - plugins: [viteDevBridge(myDevframe, { devMiddleware: true })], + plugins: [ + viteDevBridge(myDevframe, { devMiddleware: true }) + ], }) ``` @@ -227,7 +229,9 @@ export default defineConfig({ import { devframeViteBridge } from '@devframes/vite/single' export default defineConfig({ - plugins: [devframeViteBridge(myDevframe)], + plugins: [ + devframeViteBridge(myDevframe) + ], }) ``` @@ -242,7 +246,9 @@ Each built-in devframe's `@devframes/plugin-/vite` export is removed. For import { a11yVitePlugin } from '@devframes/plugin-a11y/vite' export default defineConfig({ - plugins: [a11yVitePlugin()], + plugins: [ + a11yVitePlugin() + ], }) ``` @@ -252,7 +258,9 @@ import createA11yDevframe from '@devframes/plugin-a11y' import { createPluginFromDevframe } from '@vitejs/devtools-kit/node' export default defineConfig({ - plugins: [createPluginFromDevframe(createA11yDevframe())], + plugins: [ + createPluginFromDevframe(createA11yDevframe()) + ], }) ``` @@ -263,7 +271,9 @@ import createA11yDevframe from '@devframes/plugin-a11y' import { devframeVite } from '@devframes/vite/single' export default defineConfig({ - plugins: [devframeVite(createA11yDevframe())], + plugins: [ + devframeVite(createA11yDevframe()) + ], }) ``` @@ -295,10 +305,14 @@ Nuxt: register the module by its subpath: ```ts /** 0.8.x [nuxt.config.ts] */ -export default defineNuxtConfig({ modules: ['@devframes/nuxt'] }) +export default defineNuxtConfig({ + modules: ['@devframes/nuxt'] +}) /** 0.9 [nuxt.config.ts] */ -export default defineNuxtConfig({ modules: ['@devframes/nuxt/single'] }) +export default defineNuxtConfig({ + modules: ['@devframes/nuxt/single'] +}) ``` Next: helpers and the React RPC client move down a level: @@ -317,7 +331,11 @@ Next: helpers and the React RPC client move down a level: // Vite import { viteDevframeHub } from '@devframes/vite/hub' -export default defineConfig({ plugins: [viteDevframeHub({ devframes: [] })] }) +export default defineConfig({ + plugins: [ + viteDevframeHub({ devframes: [] }) + ] +}) ``` ```ts @@ -348,7 +366,9 @@ import { Client } from '@modelcontextprotocol/client' const client = new Client( { name: 'my-client', version: '1.0.0' }, - { versionNegotiation: { mode: 'auto' } }, + { + versionNegotiation: { mode: 'auto' } + }, ) await client.connect(transport) ``` diff --git a/docs/content/7.migrations/3.migration-0.8.md b/docs/content/7.migrations/3.migration-0.8.md index 560207b53..de34c63fb 100644 --- a/docs/content/7.migrations/3.migration-0.8.md +++ b/docs/content/7.migrations/3.migration-0.8.md @@ -25,9 +25,16 @@ import * as v from 'valibot' export const rename = defineRpcFunction({ name: 'devframes:plugin:terminals:rename', type: 'action', - args: [v.object({ id: v.string(), title: v.string() })], + args: [ + v.object({ + id: v.string(), + title: v.string() + }) + ], returns: v.void(), - setup: ctx => ({ handler: ({ id, title }) => { /* … */ } }), + setup: ctx => ({ + handler: ({ id, title }) => { /* … */ } + }), }) ``` @@ -39,9 +46,16 @@ import { s } from 'devframe/utils/simple-schema' export const rename = defineRpcFunction({ name: 'devframes:plugin:terminals:rename', type: 'action', - args: [s.object({ id: s.string(), title: s.string() })], + args: [ + s.object({ + id: s.string(), + title: s.string() + }) + ], returns: s.void(), - setup: ctx => ({ handler: ({ id, title }) => { /* … */ } }), + setup: ctx => ({ + handler: ({ id, title }) => { /* … */ } + }), }) ``` diff --git a/docs/content/8.references/10.interactive-auth.md b/docs/content/8.references/10.interactive-auth.md index 8ae7d25ed..38cb60687 100644 --- a/docs/content/8.references/10.interactive-auth.md +++ b/docs/content/8.references/10.interactive-auth.md @@ -15,7 +15,9 @@ import { createInteractiveAuth } from 'devframe/recipes/interactive-auth' import { attachWsRpcTransport } from 'devframe/rpc/transports/ws-server' const auth = createInteractiveAuth(ctx, { - clientAuthTokens: process.env.CI ? [process.env.DEVFRAME_CI_TOKEN!] : undefined, + clientAuthTokens: process.env.CI + ? [process.env.DEVFRAME_CI_TOKEN!] + : undefined, }) const { rpcGroup, onConnected, onDisconnected } = createContextRpcServer({ context: ctx, auth }) diff --git a/docs/content/8.references/8.utilities.md b/docs/content/8.references/8.utilities.md index 4fa18e6a2..b1938f262 100644 --- a/docs/content/8.references/8.utilities.md +++ b/docs/content/8.references/8.utilities.md @@ -69,7 +69,9 @@ import { structuredCloneStringify, } from 'devframe/utils/structured-clone' -const wire = structuredCloneStringify(new Map([['a', 1]])) +const wire = structuredCloneStringify(new Map([ + ['a', 1] +])) const value = structuredCloneParse>(wire) ``` @@ -127,7 +129,9 @@ The immutable state container behind `ctx.rpc.sharedState` ([Shared State](/guid ```ts import { createSharedState } from 'devframe/utils/shared-state' -const state = createSharedState({ initialValue: { count: 0 } }) +const state = createSharedState({ + initialValue: { count: 0 } +}) state.mutate((draft) => { draft.count += 1 }) diff --git a/docs/content/index.md b/docs/content/index.md index 4b5fba038..bbb527a47 100644 --- a/docs/content/index.md +++ b/docs/content/index.md @@ -195,10 +195,12 @@ A devframe's boundary is simply the Web Standard `Request` and `Response`. Any f import { devtools } from './devtools' export default defineConfig({ - plugins: [{ - name: 'my-tool', - configureServer: server => server.middlewares.use(devtools.nodeMiddleware), - }], + plugins: [ + { + name: 'my-tool', + configureServer: server => server.middlewares.use(devtools.nodeMiddleware), + } + ], }) ``` :: diff --git a/eslint.config.js b/eslint.config.js index b12e5775a..cecf7f53a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -30,7 +30,16 @@ export default antfu( * HTML, and Vue/Svelte `