@veluai/velu 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
- var cn=Object.defineProperty;var j=(e,t)=>()=>(e&&(t=e(e=0)),t);var Pe=(e,t)=>{for(var n in t)cn(e,n,{get:t[n],enumerable:!0})};var rt={};Pe(rt,{initProject:()=>mn});import D from"node:fs/promises";import X from"node:path";import{fileURLToPath as un}from"node:url";async function mn(e,t){try{if((await D.readdir(e)).length>0)throw new Error(`Directory "${t}" already exists and is not empty. Choose a different name or remove the folder first.`)}catch(i){if(i.code!=="ENOENT")throw i}await D.mkdir(e,{recursive:!0}),await D.cp(fn,e,{recursive:!0});let n=X.join(e,"velu.json"),r=JSON.parse(await D.readFile(n,"utf-8"));r.name=t,await D.writeFile(n,JSON.stringify(r,null,2)+`
3
- `,"utf-8");let o=await nt(e);console.log(`[velu] created ${t}/`);for(let i of o)console.log(` ${i}`);console.log(""),console.log("Next steps:"),console.log(` cd ${t}`),console.log(" velu dev")}async function nt(e,t=e,n=[]){let r=await D.readdir(e,{withFileTypes:!0});for(let o of r){let i=X.join(e,o.name);o.isDirectory()?await nt(i,t,n):n.push(X.relative(t,i).split(X.sep).join("/"))}return n.sort()}var pn,fn,ot=j(()=>{pn=X.dirname(un(import.meta.url)),fn=X.resolve(pn,"..","templates","starter")});import dn from"node:fs/promises";import Ce from"node:path";function st(e){if(!e.favicon)return null;let t=Ce.extname(e.favicon).toLowerCase();return{url:Ee+t,type:yn[t]||""}}function te(e){if(typeof e=="string"){let t=e.trim();return t?{light:t,dark:t,href:"/"}:null}if(e&&typeof e=="object"){let t=(e.light??e.dark)?.trim?.(),n=(e.dark??e.light)?.trim?.();return!t||!n?null:{light:t,dark:n,href:e.href?.trim?.()||"/"}}return null}function Fe(e){if(!e||typeof e!="object")return null;let t=[];if(e.socials&&typeof e.socials=="object")for(let[r,o]of Object.entries(e.socials))typeof o!="string"||!o.trim()||t.push({kind:vn[r]??r,href:o.trim()});let n=Array.isArray(e.links)?e.links.filter(r=>r&&typeof r=="object").map(r=>({title:(r.header??r.title??"").trim(),items:(Array.isArray(r.items)?r.items:[]).filter(o=>o&&o.label).map(o=>({label:o.label,href:o.href??"#"}))})).filter(r=>r.title||r.items.length):[];return!t.length&&!n.length?null:{socials:t,links:n}}function _e(e){return/^(https?:)?\/\//.test(e)||/^(mailto|tel):/.test(e)}function Ne(e){if(!e||typeof e!="object")return null;let t=(Array.isArray(e.links)?e.links:[]).filter(o=>o&&typeof o.href=="string"&&o.href.trim()).map(o=>({label:o.label??"",href:o.href.trim(),icon:o.icon??null,external:_e(o.href.trim())})),n=null,r=e.primary;if(r&&typeof r=="object"&&typeof r.href=="string"&&r.href.trim()){let o=r.href.trim();n=r.type==="github"?{kind:"github",label:r.label??"GitHub",href:o,external:_e(o)}:{kind:"button",label:r.label??"",href:o,external:_e(o)}}return!t.length&&!n?null:{links:t,primary:n}}function at(e){if(e==null)return{options:[...it],display:"header"};if(typeof e!="object")return{options:[],display:"header"};let t=e.display==="toc"?"toc":"header",n=Array.isArray(e.options)?e.options:it,r=[];for(let o of n)typeof o=="string"?bn.has(o)&&r.push(o):o&&typeof o=="object"&&o.title&&o.href&&r.push({title:String(o.title),description:o.description?String(o.description):"",href:String(o.href),icon:typeof o.icon=="string"?o.icon:void 0});return{options:r,display:t}}function z(e){if(!e||typeof e!="object")return{server:null,proxy:!0,languages:void 0};let t=e.playground||{};return{server:typeof e.server=="string"?e.server.trim():null,proxy:t.proxy!==!1&&t.display!=="none",languages:Array.isArray(e.examples?.languages)?e.examples.languages:void 0}}function xn(e){return!e||typeof e!="object"?{metatags:{},indexing:"navigable"}:{metatags:e.metatags&&typeof e.metatags=="object"?e.metatags:{},indexing:e.indexing==="all"?"all":"navigable"}}function Ie(e={},t){let n=e.colors?.primary??gn;return{name:e.name??t??"docs",url:typeof e.url=="string"&&e.url.trim()?e.url.trim().replace(/\/+$/,""):null,seo:xn(e.seo),thumbnails:e.thumbnails&&typeof e.thumbnails=="object"&&typeof e.thumbnails.background=="string"?{background:e.thumbnails.background}:null,colors:{primary:n,light:e.colors?.light??n,dark:e.colors?.dark??n},favicon:e.favicon??null,api:z(e.api),logo:te(e.logo),footer:Fe(e.footer),navbar:Ne(e.navbar),font:{family:e.font?.family??hn},navigation:e.navigation??null}}async function lt(e){let t=Ce.join(e,"velu.json"),n;try{n=await dn.readFile(t,"utf-8")}catch(o){throw o.code==="ENOENT"?new Error(`No velu.json found in ${e}. Run \`velu init <name>\` to scaffold one.`):o}let r;try{r=JSON.parse(n)}catch(o){throw new Error(`velu.json is not valid JSON: ${o.message}`)}return Ie(r,Ce.basename(e))}function ct(e){let{colors:t,font:n}=e;return[":root:root {",` --accent-color: ${t.light};`,` --font-sans: "${n.family}", sans-serif;`,"}",':root:root[data-theme="dark"] {',` --accent-color: ${t.dark};`,"}"].join(`
4
- `)}var gn,hn,me,de,Ee,yn,vn,bn,it,Y=j(()=>{gn="#dc143c",hn="Google Sans Flex",me="/@velu-logo-light",de="/@velu-logo-dark",Ee="/@velu-favicon",yn={".svg":"image/svg+xml",".ico":"image/x-icon",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif"};vn={twitter:"x","x-twitter":"x"};bn=new Set(["copy","assistant","view","download-pdf","download-spec","chatgpt","claude","perplexity","grok","aistudio","devin","windsurf","mcp","add-mcp","cursor","vscode","devin-mcp"]),it=["copy","view","chatgpt","claude"]});import{visit as $n}from"unist-util-visit";import{toString as wn}from"mdast-util-to-string";import Sn from"github-slugger";import{valueToEstree as kn}from"estree-util-value-to-estree";function ne(){return e=>{let t=new Sn,n=[];$n(e,"heading",a=>{let s=wn(a);n.push({depth:a.depth,id:t.slug(s),label:s})});let r={children:[]},o=[{node:r,depth:0}];for(let a of n){for(;o.length>1&&o[o.length-1].depth>=a.depth;)o.pop();let s={id:a.id,label:a.label},l=o[o.length-1].node;l.children||(l.children=[]),l.children.push(s),o.push({node:s,depth:a.depth})}let i=r.children;e.children.unshift({type:"mdxjsEsm",value:"",data:{estree:{type:"Program",sourceType:"module",body:[{type:"ExportNamedDeclaration",specifiers:[],declaration:{type:"VariableDeclaration",kind:"const",declarations:[{type:"VariableDeclarator",id:{type:"Identifier",name:"toc"},init:kn(i)}]}}]}}})}}var Re=j(()=>{});import jn from"github-slugger";import An from"iso-639-1";function Tn(e){let t=String(e).toLowerCase();return An.getNativeName(t)||e}function ge(e){return new jn().slug(String(e??""))}function Ln(e){let t=String(e).replace(/^\/+|\/+$/g,"").split("/").filter(Boolean);return t[t.length-1]==="index"&&t.pop(),"/"+t.join("/")}function ut(e){let t=String(e).split("#")[0].split("?")[0];try{t=decodeURI(t)}catch{}return t.startsWith("/")||(t="/"+t),t.length>1&&(t=t.replace(/\/+$/,"")),t||"/"}function U(e){let t={kind:"root",children:re(e??{})};return mt(t.children),t}function re(e){let t=Array.isArray(e.anchors)?e.anchors.map(Fn):[];if(Array.isArray(e.products))return[...t,...e.products.map(Pn)];if(Array.isArray(e.versions))return[...t,...e.versions.map(_n)];if(Array.isArray(e.languages))return[...t,...e.languages.map(Cn)];if(Array.isArray(e.tabs))return[...t,...e.tabs.map(En)];let n=[...t];return Array.isArray(e.groups)&&n.push(...e.groups.map(pt)),Array.isArray(e.pages)&&n.push(...e.pages.map(ft)),n}function Pn(e){return{kind:"product",label:e.name??e.product,slug:ge(e.product),icon:e.icon,color:e.color,default:!!e.default,children:re(e)}}function _n(e){return{kind:"version",label:e.version,slug:ge(e.version),default:!!e.default,children:re(e)}}function Cn(e){let t=String(e.language);return{kind:"language",code:t,label:Tn(t),slug:ge(t),default:!!e.default,children:re(e)}}function En(e){return{kind:"tab",label:e.tab,slug:ge(e.tab),icon:e.icon,href:e.href,children:re(e)}}function Fn(e){return{kind:"anchor",label:e.anchor,icon:e.icon,href:e.href,color:e.color}}function pt(e){let t=(e.pages??[]).map(ft);return e.root&&t.unshift({kind:"page",pagePath:e.root}),{kind:"group",label:e.group,icon:e.icon,expanded:!!e.expanded,root:e.root,children:t}}function ft(e){return typeof e=="string"?{kind:"page",pagePath:e}:e&&e.apiPage?{kind:"page",pagePath:e.apiPage,label:e.label,method:e.method,api:!0}:pt(e)}function mt(e){for(let t of On){let n=e.filter(r=>r.kind===t);n.length&&!n.some(r=>r.default)&&(n[0].default=!0)}for(let t of e)t.children&&mt(t.children)}function K(e){let t=[],n=(r,o,i)=>{if(r.kind==="page"){t.push({pagePath:r.pagePath,url:Nn(r.pagePath,o),ctx:{...o},ancestors:i,node:r});return}let a=o;r.kind==="product"?a={...o,product:r.default?null:r.slug}:r.kind==="version"?a={...o,version:r.default?null:r.slug}:r.kind==="language"&&(a={...o,language:r.default?null:r.slug});let s=r.kind==="root"?i:[...i,r];for(let l of r.children??[])n(l,a,s)};return n(e,{product:null,version:null,language:null},[]),t}function Nn(e,t){let n=[t.product,t.version,t.language].filter(Boolean),r=Ln(e).split("/").filter(Boolean);return"/"+[...n,...r].join("/")}var On,B=j(()=>{On=["product","version","language"]});import In from"node:fs";import dt from"node:path";function M(e,t){let n=[],r=[],o=new Set;for(let i of K(e)){if(i.node?.api){o.add(i.url);continue}if(o.has(i.url)){n.push(`duplicate URL "${i.url}" (page "${i.pagePath}") \u2014 keeping the first occurrence`);continue}o.add(i.url);let a=i.pagePath.replace(/^\/+|\/+$/g,""),s=dt.join(t,...a.split("/"))+".mdx",l=In.existsSync(s);l||n.push(`page "${i.pagePath}" \u2192 ${dt.relative(t,s)} not found`),r.push({pagePath:i.pagePath,url:i.url,fileAbsPath:s,exists:l})}return{pageEntries:r,warnings:n}}var oe=j(()=>{B()});import Rn from"@apidevtools/swagger-parser";async function zn(e){return Rn.dereference(e)}function G(e){return!e||typeof e!="object"?e||{}:Array.isArray(e.allOf)?e.allOf.reduce((t,n)=>{let r=G(n);return{...t,...r,properties:{...t.properties||{},...r.properties||{}},required:[...t.required||[],...r.required||[]]}},{...e,allOf:void 0}):Array.isArray(e.oneOf)&&e.oneOf.length?G(e.oneOf[0]):Array.isArray(e.anyOf)&&e.anyOf.length?G(e.anyOf[0]):e}function he(e){let t=G(e);if(!t||typeof t!="object")return"any";if(Array.isArray(t.enum)&&t.enum.length)return`enum<${typeof t.enum[0]}>`;if(t.type==="array")return`${he(t.items||{})}[]`;let n=t.type||(t.properties?"object":"any");return t.format?`${n}<${t.format}>`:n}function ie(e,t=0){let n=G(e);if(!n||typeof n!="object")return null;if(n.example!==void 0)return n.example;if(n.default!==void 0)return n.default;if(Array.isArray(n.enum)&&n.enum.length)return n.enum[0];if(t>=Mn)return n.type==="object"?{}:null;switch(n.type){case"object":{let r={};for(let[o,i]of Object.entries(n.properties||{}))r[o]=ie(i,t+1);return r}case"array":return[ie(n.items||{},t+1)];case"integer":case"number":return 0;case"boolean":return!0;default:return Bn(n)}}function Bn(e){switch(e.format){case"date-time":return"2024-01-01T00:00:00Z";case"date":return"2024-01-01";case"email":return"user@example.com";case"uuid":return"3fa85f64-5717-4562-b3fc-2c963f66afa6";case"uri":case"url":return"https://example.com";default:return"<string>"}}function ht(e){let t=G(e);if(!t||t.type!=="object"||!t.properties)return t&&(t.type||t.items)?[{name:"body",type:he(t),required:!1,description:t.description||""}]:[];let n=new Set(t.required||[]);return Object.entries(t.properties).map(([r,o])=>{let i=G(o);return{name:r,type:he(i),required:n.has(r),description:i.description||"",enum:Array.isArray(i.enum)?i.enum:void 0,deprecated:i.deprecated||void 0}})}function Gn(e){let t=e.schema||{};return{name:e.name,in:e.in,required:e.in==="path"?!0:!!e.required,type:he(t),description:e.description||"",enum:Array.isArray(t.enum)?t.enum:void 0,example:ie(t),deprecated:e.deprecated||void 0}}function yt(e){if(!e||typeof e!="object")return null;let t=Object.keys(e),n=t.find(r=>/json/i.test(r))||t[0];return n?{contentType:n,media:e[n]}:null}function Jn(e){if(!e)return null;let t=yt(e.content);if(!t)return null;let n=t.media.schema||{};return{required:!!e.required,description:e.description||"",contentType:t.contentType,fields:ht(n),example:t.media.example??ie(n)}}function Vn(e){return!e||typeof e!="object"?[]:Object.entries(e).map(([t,n])=>{let r=yt(n?.content),o=r?.media?.schema||{};return{status:t,description:n?.description||"",contentType:r?.contentType||null,fields:r?ht(o):[],example:r?r.media.example??ie(o):null}})}function qn(e,t){if(!Array.isArray(e)||!t)return[];let n=[],r=new Set;for(let o of e)for(let i of Object.keys(o||{})){let a=t[i];!a||r.has(i)||(r.add(i),n.push(Hn(i,a)))}return n.filter(Boolean)}function Hn(e,t){return t.type==="http"&&/bearer/i.test(t.scheme||"")?{name:"Authorization",in:"header",required:!0,type:"string",prefix:"Bearer",description:t.description||"Bearer authentication token."}:t.type==="http"&&/basic/i.test(t.scheme||"")?{name:"Authorization",in:"header",required:!0,type:"string",prefix:"Basic",description:t.description||"Basic authentication credentials."}:t.type==="apiKey"?{name:t.name||e,in:t.in||"header",required:!0,type:"string",description:t.description||"API key."}:t.type==="oauth2"||t.type==="openIdConnect"?{name:"Authorization",in:"header",required:!0,type:"string",prefix:"Bearer",description:t.description||"OAuth 2.0 access token."}:{name:e,in:"header",required:!0,type:"string",description:t.description||""}}function gt(e){return String(e).replace(/\{[^}]+\}/g,t=>t.slice(1,-1)).replace(/[^a-zA-Z0-9]+/g,"-").replace(/^-+|-+$/g,"").toLowerCase()}function Dn(e){let{method:t,path:n,op:r,sharedParams:o,servers:i,schemes:a}=e,s=[...o||[],...r.parameters||[]],l={path:[],query:[],header:[],cookie:[]};for(let u of s)u&&l[u.in]&&l[u.in].push(Gn(u));let p=r.security??e.globalSecurity;return{id:r.operationId?gt(r.operationId):`${t}-${gt(n)}`,method:t.toUpperCase(),path:n,title:r.summary||r.operationId||`${t.toUpperCase()} ${n}`,description:r.description||r.summary||"",tags:Array.isArray(r.tags)&&r.tags.length?r.tags:["API"],deprecated:r.deprecated||!1,auth:qn(p,a),parameters:l,body:Jn(r.requestBody),responses:Vn(r.responses),servers:(i||[]).map(u=>u.url).filter(Boolean)}}function Xn(e,t,n,r,o,i,a){let s={};e.openapi?s.openapi=e.openapi:e.swagger?s.swagger=e.swagger:s.openapi="3.0.0",s.info=e.info||{title:"API Reference",version:"1.0.0"};let l=(r.servers||i||[]).filter(Boolean);l.length&&(s.servers=l);let p={};Array.isArray(o)&&o.length&&(p.parameters=o),p[n]=r,s.paths={[t]:p};let u=r.security??e.security;if(a&&Array.isArray(u)&&u.length){let c={};for(let b of u)for(let d of Object.keys(b||{}))a[d]&&(c[d]=a[d]);Object.keys(c).length&&(e.swagger?s.securityDefinitions=c:s.components={securitySchemes:c})}return s}function Yn(e){let t=[],n=[],r=e.components?.securitySchemes||e.securityDefinitions||{},o=e.security||[],i=e.servers||(e.host?[{url:`https://${e.host}${e.basePath||""}`}]:[]);for(let[a,s]of Object.entries(e.paths||{})){if(!s||typeof s!="object")continue;let l=s.parameters||[],p=s.servers||i;for(let u of Un){let c=s[u];!c||typeof c!="object"||(t.push(Dn({method:u,path:a,op:c,sharedParams:l,servers:c.servers||p,globalSecurity:o,schemes:r})),n.push(Xn(e,a,u,c,l,c.servers||p,r)))}}return{operations:t,segments:n}}async function vt(e){let t=await zn(e),n=t.servers||(t.host?[{url:`https://${t.host}${t.basePath||""}`}]:[]),{operations:r,segments:o}=Yn(t);return{title:t.info?.title||"API Reference",version:t.info?.version||"",servers:n.map(i=>i.url).filter(Boolean),operations:r,segments:o}}var Un,Mn,bt=j(()=>{Un=["get","post","put","patch","delete","options","head","trace"],Mn=6});function Kn(e,{server:t}={}){let r=`${(t||e.servers?.[0]||"").replace(/\/+$/,"")}${e.path}`,o={};for(let a of e.auth||[])a.in==="header"&&(o[a.name]=a.prefix?`${a.prefix} <token>`:"<token>");for(let a of e.parameters?.header||[])o[a.name]||(o[a.name]=String(a.example??`<${a.type}>`));let i=!!e.body;return i&&(o["Content-Type"]=e.body.contentType||"application/json"),{method:e.method,url:r,headers:o,body:i?e.body.example??{}:null}}function Wn(e){let t=`curl --request ${e.method} \\
2
+ var un=Object.defineProperty;var j=(e,t)=>()=>(e&&(t=e(e=0)),t);var Pe=(e,t)=>{for(var n in t)un(e,n,{get:t[n],enumerable:!0})};var ot={};Pe(ot,{initProject:()=>dn});import D from"node:fs/promises";import X from"node:path";import{fileURLToPath as pn}from"node:url";async function dn(e,t){try{if((await D.readdir(e)).length>0)throw new Error(`Directory "${t}" already exists and is not empty. Choose a different name or remove the folder first.`)}catch(i){if(i.code!=="ENOENT")throw i}await D.mkdir(e,{recursive:!0}),await D.cp(mn,e,{recursive:!0});let n=X.join(e,"velu.json"),r=JSON.parse(await D.readFile(n,"utf-8"));r.name=t,await D.writeFile(n,JSON.stringify(r,null,2)+`
3
+ `,"utf-8");let o=await rt(e);console.log(`[velu] created ${t}/`);for(let i of o)console.log(` ${i}`);console.log(""),console.log("Next steps:"),console.log(` cd ${t}`),console.log(" velu dev")}async function rt(e,t=e,n=[]){let r=await D.readdir(e,{withFileTypes:!0});for(let o of r){let i=X.join(e,o.name);o.isDirectory()?await rt(i,t,n):n.push(X.relative(t,i).split(X.sep).join("/"))}return n.sort()}var fn,mn,it=j(()=>{fn=X.dirname(pn(import.meta.url)),mn=X.resolve(fn,"..","templates","starter")});import gn from"node:fs/promises";import Ce from"node:path";function at(e){if(!e.favicon)return null;let t=Ce.extname(e.favicon).toLowerCase();return{url:Ee+t,type:vn[t]||""}}function te(e){if(typeof e=="string"){let t=e.trim();return t?{light:t,dark:t,href:"/"}:null}if(e&&typeof e=="object"){let t=(e.light??e.dark)?.trim?.(),n=(e.dark??e.light)?.trim?.();return!t||!n?null:{light:t,dark:n,href:e.href?.trim?.()||"/"}}return null}function Fe(e){if(!e||typeof e!="object")return null;let t=[];if(e.socials&&typeof e.socials=="object")for(let[r,o]of Object.entries(e.socials))typeof o!="string"||!o.trim()||t.push({kind:bn[r]??r,href:o.trim()});let n=Array.isArray(e.links)?e.links.filter(r=>r&&typeof r=="object").map(r=>({title:(r.header??r.title??"").trim(),items:(Array.isArray(r.items)?r.items:[]).filter(o=>o&&o.label).map(o=>({label:o.label,href:o.href??"#"}))})).filter(r=>r.title||r.items.length):[];return!t.length&&!n.length?null:{socials:t,links:n}}function _e(e){return/^(https?:)?\/\//.test(e)||/^(mailto|tel):/.test(e)}function Ne(e){if(!e||typeof e!="object")return null;let t=(Array.isArray(e.links)?e.links:[]).filter(o=>o&&typeof o.href=="string"&&o.href.trim()).map(o=>({label:o.label??"",href:o.href.trim(),icon:o.icon??null,external:_e(o.href.trim())})),n=null,r=e.primary;if(r&&typeof r=="object"&&typeof r.href=="string"&&r.href.trim()){let o=r.href.trim();n=r.type==="github"?{kind:"github",label:r.label??"GitHub",href:o,external:_e(o)}:{kind:"button",label:r.label??"",href:o,external:_e(o)}}return!t.length&&!n?null:{links:t,primary:n}}function lt(e){if(e==null)return{options:[...st],display:"header"};if(typeof e!="object")return{options:[],display:"header"};let t=e.display==="toc"?"toc":"header",n=Array.isArray(e.options)?e.options:st,r=[];for(let o of n)typeof o=="string"?xn.has(o)&&r.push(o):o&&typeof o=="object"&&o.title&&o.href&&r.push({title:String(o.title),description:o.description?String(o.description):"",href:String(o.href),icon:typeof o.icon=="string"?o.icon:void 0});return{options:r,display:t}}function z(e){if(!e||typeof e!="object")return{server:null,proxy:!0,languages:void 0};let t=e.playground||{};return{server:typeof e.server=="string"?e.server.trim():null,proxy:t.proxy!==!1&&t.display!=="none",languages:Array.isArray(e.examples?.languages)?e.examples.languages:void 0}}function $n(e){return!e||typeof e!="object"?{metatags:{},indexing:"navigable"}:{metatags:e.metatags&&typeof e.metatags=="object"?e.metatags:{},indexing:e.indexing==="all"?"all":"navigable"}}function Ie(e){if(!e||typeof e!="object")return null;let t=typeof e.apiBase=="string"&&e.apiBase.trim()?e.apiBase.trim().replace(/\/+$/,""):null;if(!t)return null;let n=typeof e.host=="string"&&e.host.trim()?e.host.trim():null;return{apiBase:t,host:n}}function Re(e={},t){let n=e.colors?.primary??hn;return{name:e.name??t??"docs",url:typeof e.url=="string"&&e.url.trim()?e.url.trim().replace(/\/+$/,""):null,seo:$n(e.seo),assistant:Ie(e.assistant),thumbnails:e.thumbnails&&typeof e.thumbnails=="object"&&typeof e.thumbnails.background=="string"?{background:e.thumbnails.background}:null,colors:{primary:n,light:e.colors?.light??n,dark:e.colors?.dark??n},favicon:e.favicon??null,api:z(e.api),logo:te(e.logo),footer:Fe(e.footer),navbar:Ne(e.navbar),font:{family:e.font?.family??yn},navigation:e.navigation??null}}async function ct(e){let t=Ce.join(e,"velu.json"),n;try{n=await gn.readFile(t,"utf-8")}catch(o){throw o.code==="ENOENT"?new Error(`No velu.json found in ${e}. Run \`velu init <name>\` to scaffold one.`):o}let r;try{r=JSON.parse(n)}catch(o){throw new Error(`velu.json is not valid JSON: ${o.message}`)}return Re(r,Ce.basename(e))}function ut(e){let{colors:t,font:n}=e;return[":root:root {",` --accent-color: ${t.light};`,` --font-sans: "${n.family}", sans-serif;`,"}",':root:root[data-theme="dark"] {',` --accent-color: ${t.dark};`,"}"].join(`
4
+ `)}var hn,yn,fe,me,Ee,vn,bn,xn,st,Y=j(()=>{hn="#dc143c",yn="Google Sans Flex",fe="/@velu-logo-light",me="/@velu-logo-dark",Ee="/@velu-favicon",vn={".svg":"image/svg+xml",".ico":"image/x-icon",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif"};bn={twitter:"x","x-twitter":"x"};xn=new Set(["copy","assistant","view","download-pdf","download-spec","chatgpt","claude","perplexity","grok","aistudio","devin","windsurf","mcp","add-mcp","cursor","vscode","devin-mcp"]),st=["copy","view","chatgpt","claude"]});import{visit as wn}from"unist-util-visit";import{toString as Sn}from"mdast-util-to-string";import kn from"github-slugger";import{valueToEstree as jn}from"estree-util-value-to-estree";function ne(){return e=>{let t=new kn,n=[];wn(e,"heading",a=>{let s=Sn(a);n.push({depth:a.depth,id:t.slug(s),label:s})});let r={children:[]},o=[{node:r,depth:0}];for(let a of n){for(;o.length>1&&o[o.length-1].depth>=a.depth;)o.pop();let s={id:a.id,label:a.label},l=o[o.length-1].node;l.children||(l.children=[]),l.children.push(s),o.push({node:s,depth:a.depth})}let i=r.children;e.children.unshift({type:"mdxjsEsm",value:"",data:{estree:{type:"Program",sourceType:"module",body:[{type:"ExportNamedDeclaration",specifiers:[],declaration:{type:"VariableDeclaration",kind:"const",declarations:[{type:"VariableDeclarator",id:{type:"Identifier",name:"toc"},init:jn(i)}]}}]}}})}}var Ue=j(()=>{});import An from"github-slugger";import On from"iso-639-1";function Ln(e){let t=String(e).toLowerCase();return On.getNativeName(t)||e}function de(e){return new An().slug(String(e??""))}function Pn(e){let t=String(e).replace(/^\/+|\/+$/g,"").split("/").filter(Boolean);return t[t.length-1]==="index"&&t.pop(),"/"+t.join("/")}function pt(e){let t=String(e).split("#")[0].split("?")[0];try{t=decodeURI(t)}catch{}return t.startsWith("/")||(t="/"+t),t.length>1&&(t=t.replace(/\/+$/,"")),t||"/"}function U(e){let t={kind:"root",children:re(e??{})};return dt(t.children),t}function re(e){let t=Array.isArray(e.anchors)?e.anchors.map(Nn):[];if(Array.isArray(e.products))return[...t,...e.products.map(_n)];if(Array.isArray(e.versions))return[...t,...e.versions.map(Cn)];if(Array.isArray(e.languages))return[...t,...e.languages.map(En)];if(Array.isArray(e.tabs))return[...t,...e.tabs.map(Fn)];let n=[...t];return Array.isArray(e.groups)&&n.push(...e.groups.map(ft)),Array.isArray(e.pages)&&n.push(...e.pages.map(mt)),n}function _n(e){return{kind:"product",label:e.name??e.product,slug:de(e.product),icon:e.icon,color:e.color,default:!!e.default,children:re(e)}}function Cn(e){return{kind:"version",label:e.version,slug:de(e.version),default:!!e.default,children:re(e)}}function En(e){let t=String(e.language);return{kind:"language",code:t,label:Ln(t),slug:de(t),default:!!e.default,children:re(e)}}function Fn(e){return{kind:"tab",label:e.tab,slug:de(e.tab),icon:e.icon,href:e.href,children:re(e)}}function Nn(e){return{kind:"anchor",label:e.anchor,icon:e.icon,href:e.href,color:e.color}}function ft(e){let t=(e.pages??[]).map(mt);return e.root&&t.unshift({kind:"page",pagePath:e.root}),{kind:"group",label:e.group,icon:e.icon,expanded:!!e.expanded,root:e.root,children:t}}function mt(e){return typeof e=="string"?{kind:"page",pagePath:e}:e&&e.apiPage?{kind:"page",pagePath:e.apiPage,label:e.label,method:e.method,api:!0}:ft(e)}function dt(e){for(let t of Tn){let n=e.filter(r=>r.kind===t);n.length&&!n.some(r=>r.default)&&(n[0].default=!0)}for(let t of e)t.children&&dt(t.children)}function K(e){let t=[],n=(r,o,i)=>{if(r.kind==="page"){t.push({pagePath:r.pagePath,url:In(r.pagePath,o),ctx:{...o},ancestors:i,node:r});return}let a=o;r.kind==="product"?a={...o,product:r.default?null:r.slug}:r.kind==="version"?a={...o,version:r.default?null:r.slug}:r.kind==="language"&&(a={...o,language:r.default?null:r.slug});let s=r.kind==="root"?i:[...i,r];for(let l of r.children??[])n(l,a,s)};return n(e,{product:null,version:null,language:null},[]),t}function In(e,t){let n=[t.product,t.version,t.language].filter(Boolean),r=Pn(e).split("/").filter(Boolean);return"/"+[...n,...r].join("/")}var Tn,B=j(()=>{Tn=["product","version","language"]});import Rn from"node:fs";import gt from"node:path";function M(e,t){let n=[],r=[],o=new Set;for(let i of K(e)){if(i.node?.api){o.add(i.url);continue}if(o.has(i.url)){n.push(`duplicate URL "${i.url}" (page "${i.pagePath}") \u2014 keeping the first occurrence`);continue}o.add(i.url);let a=i.pagePath.replace(/^\/+|\/+$/g,""),s=gt.join(t,...a.split("/"))+".mdx",l=Rn.existsSync(s);l||n.push(`page "${i.pagePath}" \u2192 ${gt.relative(t,s)} not found`),r.push({pagePath:i.pagePath,url:i.url,fileAbsPath:s,exists:l})}return{pageEntries:r,warnings:n}}var oe=j(()=>{B()});import Un from"@apidevtools/swagger-parser";async function Bn(e){return Un.dereference(e)}function G(e){return!e||typeof e!="object"?e||{}:Array.isArray(e.allOf)?e.allOf.reduce((t,n)=>{let r=G(n);return{...t,...r,properties:{...t.properties||{},...r.properties||{}},required:[...t.required||[],...r.required||[]]}},{...e,allOf:void 0}):Array.isArray(e.oneOf)&&e.oneOf.length?G(e.oneOf[0]):Array.isArray(e.anyOf)&&e.anyOf.length?G(e.anyOf[0]):e}function ge(e){let t=G(e);if(!t||typeof t!="object")return"any";if(Array.isArray(t.enum)&&t.enum.length)return`enum<${typeof t.enum[0]}>`;if(t.type==="array")return`${ge(t.items||{})}[]`;let n=t.type||(t.properties?"object":"any");return t.format?`${n}<${t.format}>`:n}function ie(e,t=0){let n=G(e);if(!n||typeof n!="object")return null;if(n.example!==void 0)return n.example;if(n.default!==void 0)return n.default;if(Array.isArray(n.enum)&&n.enum.length)return n.enum[0];if(t>=zn)return n.type==="object"?{}:null;switch(n.type){case"object":{let r={};for(let[o,i]of Object.entries(n.properties||{}))r[o]=ie(i,t+1);return r}case"array":return[ie(n.items||{},t+1)];case"integer":case"number":return 0;case"boolean":return!0;default:return Gn(n)}}function Gn(e){switch(e.format){case"date-time":return"2024-01-01T00:00:00Z";case"date":return"2024-01-01";case"email":return"user@example.com";case"uuid":return"3fa85f64-5717-4562-b3fc-2c963f66afa6";case"uri":case"url":return"https://example.com";default:return"<string>"}}function yt(e){let t=G(e);if(!t||t.type!=="object"||!t.properties)return t&&(t.type||t.items)?[{name:"body",type:ge(t),required:!1,description:t.description||""}]:[];let n=new Set(t.required||[]);return Object.entries(t.properties).map(([r,o])=>{let i=G(o);return{name:r,type:ge(i),required:n.has(r),description:i.description||"",enum:Array.isArray(i.enum)?i.enum:void 0,deprecated:i.deprecated||void 0}})}function Jn(e){let t=e.schema||{};return{name:e.name,in:e.in,required:e.in==="path"?!0:!!e.required,type:ge(t),description:e.description||"",enum:Array.isArray(t.enum)?t.enum:void 0,example:ie(t),deprecated:e.deprecated||void 0}}function vt(e){if(!e||typeof e!="object")return null;let t=Object.keys(e),n=t.find(r=>/json/i.test(r))||t[0];return n?{contentType:n,media:e[n]}:null}function Vn(e){if(!e)return null;let t=vt(e.content);if(!t)return null;let n=t.media.schema||{};return{required:!!e.required,description:e.description||"",contentType:t.contentType,fields:yt(n),example:t.media.example??ie(n)}}function qn(e){return!e||typeof e!="object"?[]:Object.entries(e).map(([t,n])=>{let r=vt(n?.content),o=r?.media?.schema||{};return{status:t,description:n?.description||"",contentType:r?.contentType||null,fields:r?yt(o):[],example:r?r.media.example??ie(o):null}})}function Hn(e,t){if(!Array.isArray(e)||!t)return[];let n=[],r=new Set;for(let o of e)for(let i of Object.keys(o||{})){let a=t[i];!a||r.has(i)||(r.add(i),n.push(Dn(i,a)))}return n.filter(Boolean)}function Dn(e,t){return t.type==="http"&&/bearer/i.test(t.scheme||"")?{name:"Authorization",in:"header",required:!0,type:"string",prefix:"Bearer",description:t.description||"Bearer authentication token."}:t.type==="http"&&/basic/i.test(t.scheme||"")?{name:"Authorization",in:"header",required:!0,type:"string",prefix:"Basic",description:t.description||"Basic authentication credentials."}:t.type==="apiKey"?{name:t.name||e,in:t.in||"header",required:!0,type:"string",description:t.description||"API key."}:t.type==="oauth2"||t.type==="openIdConnect"?{name:"Authorization",in:"header",required:!0,type:"string",prefix:"Bearer",description:t.description||"OAuth 2.0 access token."}:{name:e,in:"header",required:!0,type:"string",description:t.description||""}}function ht(e){return String(e).replace(/\{[^}]+\}/g,t=>t.slice(1,-1)).replace(/[^a-zA-Z0-9]+/g,"-").replace(/^-+|-+$/g,"").toLowerCase()}function Xn(e){let{method:t,path:n,op:r,sharedParams:o,servers:i,schemes:a}=e,s=[...o||[],...r.parameters||[]],l={path:[],query:[],header:[],cookie:[]};for(let u of s)u&&l[u.in]&&l[u.in].push(Jn(u));let p=r.security??e.globalSecurity;return{id:r.operationId?ht(r.operationId):`${t}-${ht(n)}`,method:t.toUpperCase(),path:n,title:r.summary||r.operationId||`${t.toUpperCase()} ${n}`,description:r.description||r.summary||"",tags:Array.isArray(r.tags)&&r.tags.length?r.tags:["API"],deprecated:r.deprecated||!1,auth:Hn(p,a),parameters:l,body:Vn(r.requestBody),responses:qn(r.responses),servers:(i||[]).map(u=>u.url).filter(Boolean)}}function Yn(e,t,n,r,o,i,a){let s={};e.openapi?s.openapi=e.openapi:e.swagger?s.swagger=e.swagger:s.openapi="3.0.0",s.info=e.info||{title:"API Reference",version:"1.0.0"};let l=(r.servers||i||[]).filter(Boolean);l.length&&(s.servers=l);let p={};Array.isArray(o)&&o.length&&(p.parameters=o),p[n]=r,s.paths={[t]:p};let u=r.security??e.security;if(a&&Array.isArray(u)&&u.length){let c={};for(let b of u)for(let d of Object.keys(b||{}))a[d]&&(c[d]=a[d]);Object.keys(c).length&&(e.swagger?s.securityDefinitions=c:s.components={securitySchemes:c})}return s}function Kn(e){let t=[],n=[],r=e.components?.securitySchemes||e.securityDefinitions||{},o=e.security||[],i=e.servers||(e.host?[{url:`https://${e.host}${e.basePath||""}`}]:[]);for(let[a,s]of Object.entries(e.paths||{})){if(!s||typeof s!="object")continue;let l=s.parameters||[],p=s.servers||i;for(let u of Mn){let c=s[u];!c||typeof c!="object"||(t.push(Xn({method:u,path:a,op:c,sharedParams:l,servers:c.servers||p,globalSecurity:o,schemes:r})),n.push(Yn(e,a,u,c,l,c.servers||p,r)))}}return{operations:t,segments:n}}async function bt(e){let t=await Bn(e),n=t.servers||(t.host?[{url:`https://${t.host}${t.basePath||""}`}]:[]),{operations:r,segments:o}=Kn(t);return{title:t.info?.title||"API Reference",version:t.info?.version||"",servers:n.map(i=>i.url).filter(Boolean),operations:r,segments:o}}var Mn,zn,xt=j(()=>{Mn=["get","post","put","patch","delete","options","head","trace"],zn=6});function Wn(e,{server:t}={}){let r=`${(t||e.servers?.[0]||"").replace(/\/+$/,"")}${e.path}`,o={};for(let a of e.auth||[])a.in==="header"&&(o[a.name]=a.prefix?`${a.prefix} <token>`:"<token>");for(let a of e.parameters?.header||[])o[a.name]||(o[a.name]=String(a.example??`<${a.type}>`));let i=!!e.body;return i&&(o["Content-Type"]=e.body.contentType||"application/json"),{method:e.method,url:r,headers:o,body:i?e.body.example??{}:null}}function Zn(e){let t=`curl --request ${e.method} \\
5
5
  --url ${e.url}`;for(let[n,r]of Object.entries(e.headers))t+=` \\
6
6
  --header '${n}: ${r}'`;return e.body!=null&&(t+=` \\
7
- --data '${JSON.stringify(e.body)}'`),t}function Zn(e){let t=[` method: '${e.method}'`];if(Object.keys(e.headers).length){let n=Object.entries(e.headers).map(([r,o])=>` '${r}': '${o}'`).join(`,
7
+ --data '${JSON.stringify(e.body)}'`),t}function Qn(e){let t=[` method: '${e.method}'`];if(Object.keys(e.headers).length){let n=Object.entries(e.headers).map(([r,o])=>` '${r}': '${o}'`).join(`,
8
8
  `);t.push(` headers: {
9
9
  ${n}
10
- }`)}return e.body!=null&&t.push(` body: JSON.stringify(${Ue(e.body," ")})`),[`const res = await fetch('${e.url}', {`,t.join(`,
10
+ }`)}return e.body!=null&&t.push(` body: JSON.stringify(${Me(e.body," ")})`),[`const res = await fetch('${e.url}', {`,t.join(`,
11
11
  `),"});","const data = await res.json();"].join(`
12
- `)}function Qn(e){let t=["import requests","",`url = "${e.url}"`];if(Object.keys(e.headers).length){let r=Object.entries(e.headers).map(([o,i])=>` "${o}": "${i}"`).join(`,
12
+ `)}function er(e){let t=["import requests","",`url = "${e.url}"`];if(Object.keys(e.headers).length){let r=Object.entries(e.headers).map(([o,i])=>` "${o}": "${i}"`).join(`,
13
13
  `);t.push(`headers = {
14
14
  ${r}
15
- }`)}let n=["url"];return e.body!=null&&(t.push(`payload = ${Ue(e.body,"")}`),n.push("json=payload")),Object.keys(e.headers).length&&n.push("headers=headers"),t.push("",`response = requests.${e.method.toLowerCase()}(${n.join(", ")})`,"print(response.json())"),t.join(`
16
- `)}function er(e){let t=e.method.charAt(0)+e.method.slice(1).toLowerCase(),n=["require 'net/http'","require 'json'","",`uri = URI("${e.url}")`,"http = Net::HTTP.new(uri.host, uri.port)","http.use_ssl = true",`request = Net::HTTP::${t}.new(uri)`];for(let[r,o]of Object.entries(e.headers))n.push(`request['${r}'] = '${o}'`);return e.body!=null&&n.push(`request.body = ${Ue(e.body,"")}.to_json`),n.push("","response = http.request(request)","puts response.body"),n.join(`
17
- `)}function $t(e,{server:t,languages:n=Me}={}){let r=Kn(e,{server:t});return n.filter(o=>xt[o]).map(o=>({key:o,label:tr[o],language:nr[o],code:xt[o](r)}))}var Ue,xt,tr,nr,Me,wt=j(()=>{Ue=(e,t)=>JSON.stringify(e,null,2).split(`
15
+ }`)}let n=["url"];return e.body!=null&&(t.push(`payload = ${Me(e.body,"")}`),n.push("json=payload")),Object.keys(e.headers).length&&n.push("headers=headers"),t.push("",`response = requests.${e.method.toLowerCase()}(${n.join(", ")})`,"print(response.json())"),t.join(`
16
+ `)}function tr(e){let t=e.method.charAt(0)+e.method.slice(1).toLowerCase(),n=["require 'net/http'","require 'json'","",`uri = URI("${e.url}")`,"http = Net::HTTP.new(uri.host, uri.port)","http.use_ssl = true",`request = Net::HTTP::${t}.new(uri)`];for(let[r,o]of Object.entries(e.headers))n.push(`request['${r}'] = '${o}'`);return e.body!=null&&n.push(`request.body = ${Me(e.body,"")}.to_json`),n.push("","response = http.request(request)","puts response.body"),n.join(`
17
+ `)}function wt(e,{server:t,languages:n=ze}={}){let r=Wn(e,{server:t});return n.filter(o=>$t[o]).map(o=>({key:o,label:nr[o],language:rr[o],code:$t[o](r)}))}var Me,$t,nr,rr,ze,St=j(()=>{Me=(e,t)=>JSON.stringify(e,null,2).split(`
18
18
  `).map((n,r)=>r===0?n:t+n).join(`
19
- `);xt={curl:Wn,javascript:Zn,python:Qn,ruby:er},tr={curl:"cURL",javascript:"JavaScript",python:"Python",ruby:"Ruby"},nr={curl:"bash",javascript:"javascript",python:"python",ruby:"ruby"},Me=["curl","javascript","python","ruby"]});import rr from"node:path";function St(e,t){if(!t||typeof t!="object")return e;let n=z(t);return{server:t.server!=null?n.server:e?.server??null,proxy:t.playground!=null?n.proxy:e?.proxy!==!1,languages:t.examples?.languages!=null?n.languages:e?.languages}}function or(e,t){return/^https?:\/\//.test(e)?e:rr.resolve(t,e.replace(/^\/+/,""))}function ir(e,{base:t,api:n,ops:r}){let o=n?.server,i=n?.languages||Me,a={proxy:n?.proxy!==!1,server:o??null},s=new Map;for(let p of e){let u=p.op.tags?.[0]||"API";s.has(u)||s.set(u,[]),s.get(u).push(p)}let l=[];for(let[p,u]of s){let c=u.map(({op:b,segment:d})=>{let $=`${t}/${ze(p)}/${b.id}`;return r[$]={operation:b,samples:$t(b,{server:o||b.servers?.[0],languages:i}),segment:d,title:b.title,description:b.description,method:b.method,api:a},{apiPage:$,label:b.title,method:b.method}});l.push({group:p,pages:c})}return l}async function kt(e,{targetDir:t,base:n,api:r,ops:o}){let i=Array.isArray(e)?e:[e],a=[];for(let s of i){let{operations:l,segments:p,servers:u}=await vt(or(s,t));l.forEach((c,b)=>{!c.servers?.length&&u?.length&&(c.servers=u),a.push({op:c,segment:p[b]})})}return ir(a,{base:n,api:r,ops:o})}async function jt(e,{targetDir:t,api:n,ops:r,baseHint:o}){if(!e||typeof e!="object")return e;if(typeof e.tab=="string"&&e.openapi){let a=ze(e.tab),s=St(n,e.api),l=await kt(e.openapi,{targetDir:t,base:a,api:s,ops:r}),{openapi:p,api:u,...c}=e;return{...c,groups:[...c.groups||[],...l]}}if(typeof e.group=="string"&&e.openapi){let a=ze(e.group),s=St(n,e.api),l=await kt(e.openapi,{targetDir:t,base:a,api:s,ops:r}),{openapi:p,api:u,...c}=e,b=l.flatMap(d=>d.pages);return{...c,pages:[...c.pages||[],...b]}}let i={...e};for(let a of["products","versions","languages","tabs","groups"])Array.isArray(e[a])&&(i[a]=await Promise.all(e[a].map(s=>jt(s,{targetDir:t,api:n,ops:r,baseHint:o}))));return i}async function ye(e,{targetDir:t,api:n}={}){let r={};return!e||typeof e!="object"?{nav:e,ops:r}:{nav:await jt(e,{targetDir:t,api:n,ops:r}),ops:r}}var ze,Be=j(()=>{Y();bt();wt();ze=e=>String(e??"").replace(/\{[^}]+\}/g,t=>t.slice(1,-1)).replace(/[^a-zA-Z0-9]+/g,"-").replace(/^-+|-+$/g,"").toLowerCase()||"x"});import sr from"node:fs";import se from"node:path";function Tt(e){return{name:"velu-site",resolveId(t){return t===Ot?At:null},async load(t){return t!==At?null:ar(e)}}}async function ar(e){let t={};try{t=JSON.parse(sr.readFileSync(se.join(e,"velu.json"),"utf-8"))}catch{}let n=z(t.api),r=t.navigation??{},o={};try{let x=await ye(t.navigation??{},{targetDir:e,api:n});r=x.nav,o=x.ops}catch(x){console.warn(`[velu] openapi: ${x.message}`)}let i=U(r),{pageEntries:a,warnings:s}=M(i,e);for(let x of s)console.warn(`[velu] nav: ${x}`);let l=te(t.logo),p={name:t.name??se.basename(e),logo:l?{light:me,dark:de,href:l.href,mono:l.light===l.dark}:null,footer:Fe(t.footer),navbar:Ne(t.navbar),contextual:at(t.contextual)},u=[],c=[],b=0;for(let x of a){if(!x.exists)continue;let y=JSON.stringify(x.fileAbsPath.split(se.sep).join("/")),f=JSON.stringify(se.relative(e,x.fileAbsPath).split(se.sep).join("/")),g=`__p${b++}`;u.push(`import * as ${g} from ${y};`),c.push(` ${JSON.stringify(x.url)}: { Component: ${g}.default, frontmatter: ${g}.frontmatter, toc: ${g}.toc, relPath: ${f} },`)}let d=new Set(a.filter(x=>x.exists).map(x=>x.url));for(let x of a)!x.exists&&!d.has(x.url)&&c.push(` ${JSON.stringify(x.url)}: { missing: true },`);let $=[],m=[],L=[],h=!1,w=0;for(let x of K(i)){if(!x.node?.api)continue;let y=o[x.pagePath];if(!y)continue;h=!0;let f=`__op${w}`,g=`__samples${w}`,v=`__api${w}`;w+=1,$.push(`const ${f} = ${JSON.stringify(y.operation)};`),$.push(`const ${g} = ${JSON.stringify(y.samples)};`),L.push(`{ id: ${JSON.stringify(y.operation.id)}, method: ${JSON.stringify(y.operation.method)}, title: ${JSON.stringify(y.operation.title)}, url: ${JSON.stringify(x.url)}, operation: ${f}, samples: ${g}, api: ${JSON.stringify(y.api||{proxy:!0,server:null})} }`),m.push(`function ${v}(){ return React.createElement(ApiReferencePage, { operation: ${f}, samples: ${g}, apiOperations: __apiOperations, api: ${JSON.stringify(y.api||{proxy:!0,server:null})} }); }`),c.push(` ${JSON.stringify(x.url)}: { Component: ${v}, frontmatter: { title: ${JSON.stringify(y.title)}, description: ${JSON.stringify(y.description)} }, toc: [], operation: ${f}, samples: ${g}, api: true },`)}h&&($.push(`const __apiOperations = [
19
+ `);$t={curl:Zn,javascript:Qn,python:er,ruby:tr},nr={curl:"cURL",javascript:"JavaScript",python:"Python",ruby:"Ruby"},rr={curl:"bash",javascript:"javascript",python:"python",ruby:"ruby"},ze=["curl","javascript","python","ruby"]});import or from"node:path";function kt(e,t){if(!t||typeof t!="object")return e;let n=z(t);return{server:t.server!=null?n.server:e?.server??null,proxy:t.playground!=null?n.proxy:e?.proxy!==!1,languages:t.examples?.languages!=null?n.languages:e?.languages}}function ir(e,t){return/^https?:\/\//.test(e)?e:or.resolve(t,e.replace(/^\/+/,""))}function sr(e,{base:t,api:n,ops:r}){let o=n?.server,i=n?.languages||ze,a={proxy:n?.proxy!==!1,server:o??null},s=new Map;for(let p of e){let u=p.op.tags?.[0]||"API";s.has(u)||s.set(u,[]),s.get(u).push(p)}let l=[];for(let[p,u]of s){let c=u.map(({op:b,segment:d})=>{let $=`${t}/${Be(p)}/${b.id}`;return r[$]={operation:b,samples:wt(b,{server:o||b.servers?.[0],languages:i}),segment:d,title:b.title,description:b.description,method:b.method,api:a},{apiPage:$,label:b.title,method:b.method}});l.push({group:p,pages:c})}return l}async function jt(e,{targetDir:t,base:n,api:r,ops:o}){let i=Array.isArray(e)?e:[e],a=[];for(let s of i){let{operations:l,segments:p,servers:u}=await bt(ir(s,t));l.forEach((c,b)=>{!c.servers?.length&&u?.length&&(c.servers=u),a.push({op:c,segment:p[b]})})}return sr(a,{base:n,api:r,ops:o})}async function At(e,{targetDir:t,api:n,ops:r,baseHint:o}){if(!e||typeof e!="object")return e;if(typeof e.tab=="string"&&e.openapi){let a=Be(e.tab),s=kt(n,e.api),l=await jt(e.openapi,{targetDir:t,base:a,api:s,ops:r}),{openapi:p,api:u,...c}=e;return{...c,groups:[...c.groups||[],...l]}}if(typeof e.group=="string"&&e.openapi){let a=Be(e.group),s=kt(n,e.api),l=await jt(e.openapi,{targetDir:t,base:a,api:s,ops:r}),{openapi:p,api:u,...c}=e,b=l.flatMap(d=>d.pages);return{...c,pages:[...c.pages||[],...b]}}let i={...e};for(let a of["products","versions","languages","tabs","groups"])Array.isArray(e[a])&&(i[a]=await Promise.all(e[a].map(s=>At(s,{targetDir:t,api:n,ops:r,baseHint:o}))));return i}async function he(e,{targetDir:t,api:n}={}){let r={};return!e||typeof e!="object"?{nav:e,ops:r}:{nav:await At(e,{targetDir:t,api:n,ops:r}),ops:r}}var Be,Ge=j(()=>{Y();xt();St();Be=e=>String(e??"").replace(/\{[^}]+\}/g,t=>t.slice(1,-1)).replace(/[^a-zA-Z0-9]+/g,"-").replace(/^-+|-+$/g,"").toLowerCase()||"x"});import ar from"node:fs";import se from"node:path";function Lt(e){return{name:"velu-site",resolveId(t){return t===Tt?Ot:null},async load(t){return t!==Ot?null:lr(e)}}}async function lr(e){let t={};try{t=JSON.parse(ar.readFileSync(se.join(e,"velu.json"),"utf-8"))}catch{}let n=z(t.api),r=t.navigation??{},o={};try{let x=await he(t.navigation??{},{targetDir:e,api:n});r=x.nav,o=x.ops}catch(x){console.warn(`[velu] openapi: ${x.message}`)}let i=U(r),{pageEntries:a,warnings:s}=M(i,e);for(let x of s)console.warn(`[velu] nav: ${x}`);let l=te(t.logo),p={name:t.name??se.basename(e),logo:l?{light:fe,dark:me,href:l.href,mono:l.light===l.dark}:null,footer:Fe(t.footer),navbar:Ne(t.navbar),contextual:lt(t.contextual),assistant:Ie(t.assistant)},u=[],c=[],b=0;for(let x of a){if(!x.exists)continue;let y=JSON.stringify(x.fileAbsPath.split(se.sep).join("/")),f=JSON.stringify(se.relative(e,x.fileAbsPath).split(se.sep).join("/")),g=`__p${b++}`;u.push(`import * as ${g} from ${y};`),c.push(` ${JSON.stringify(x.url)}: { Component: ${g}.default, frontmatter: ${g}.frontmatter, toc: ${g}.toc, relPath: ${f} },`)}let d=new Set(a.filter(x=>x.exists).map(x=>x.url));for(let x of a)!x.exists&&!d.has(x.url)&&c.push(` ${JSON.stringify(x.url)}: { missing: true },`);let $=[],m=[],L=[],h=!1,w=0;for(let x of K(i)){if(!x.node?.api)continue;let y=o[x.pagePath];if(!y)continue;h=!0;let f=`__op${w}`,g=`__samples${w}`,v=`__api${w}`;w+=1,$.push(`const ${f} = ${JSON.stringify(y.operation)};`),$.push(`const ${g} = ${JSON.stringify(y.samples)};`),L.push(`{ id: ${JSON.stringify(y.operation.id)}, method: ${JSON.stringify(y.operation.method)}, title: ${JSON.stringify(y.operation.title)}, url: ${JSON.stringify(x.url)}, operation: ${f}, samples: ${g}, api: ${JSON.stringify(y.api||{proxy:!0,server:null})} }`),m.push(`function ${v}(){ return React.createElement(ApiReferencePage, { operation: ${f}, samples: ${g}, apiOperations: __apiOperations, api: ${JSON.stringify(y.api||{proxy:!0,server:null})} }); }`),c.push(` ${JSON.stringify(x.url)}: { Component: ${v}, frontmatter: { title: ${JSON.stringify(y.title)}, description: ${JSON.stringify(y.description)} }, toc: [], operation: ${f}, samples: ${g}, api: true },`)}h&&($.push(`const __apiOperations = [
20
20
  ${L.join(`,
21
21
  `)}
22
22
  ];`),$.push(m.join(`
@@ -25,10 +25,10 @@ ${L.join(`,
25
25
  `),$.join(`
26
26
  `),"","export const pages = {",c.join(`
27
27
  `),"};",`export const navigation = ${JSON.stringify(i)};`,`export const site = ${JSON.stringify(p)};`,""].join(`
28
- `)}var Ot,At,Lt=j(()=>{B();oe();Y();Be();Ot="virtual:velu-site",At="\0"+Ot});import{visit as lr}from"unist-util-visit";function cr(e,t){let n=Pt(e).replace(/[?#].*$/,""),r=Pt(t).replace(/\/+$/,"");return r&&n.toLowerCase().startsWith(r.toLowerCase())?n.slice(r.length).replace(/^\/+/,""):null}function _t(e,t){return()=>(n,r)=>{typeof e=="function"&&lr(n,o=>{if(o.type!=="mdxJsxFlowElement"&&o.type!=="mdxJsxTextElement"||typeof o.name!="string"||!/^[A-Z]/.test(o.name)||o.name.includes("."))return;let i={};for(let s of o.attributes||[])s.type==="mdxJsxAttribute"&&(s.value==null?i[s.name]=!0:typeof s.value=="string"&&(i[s.name]=s.value));let a=e(o.name,i,{checkRequired:!1});if(a){let s=new Error(a.title);throw s.veluIssue={...a,file:cr(r?.path,t),line:o.position?.start?.line??null,column:o.position?.start?.column??null},s.loc={line:s.veluIssue.line,column:s.veluIssue.column},s}})}}var Pt,Ct=j(()=>{Pt=e=>String(e||"").replace(/\\/g,"/")});import ve from"node:path";import ur from"node:fs";import{createRequire as pr}from"node:module";import fr from"@tailwindcss/vite";import mr from"@vitejs/plugin-react";import dr from"@mdx-js/rollup";import gr from"remark-frontmatter";import hr from"remark-mdx-frontmatter";import yr from"remark-gfm";import vr from"rehype-slug";function br(e){let n=pr(import.meta.url).resolve("@mdx-js/react"),r=ve.resolve(e,"runtime","velu-ui"),o=ur.existsSync(r)?r:ve.resolve(e,"..","velu-ui","src");return[{find:"@mdx-js/react",replacement:n},{find:/^velu-ui$/,replacement:ve.join(o,"index.js")},{find:/^velu-ui\//,replacement:o+"/"}]}function Et({targetDir:e,VITE_ROOT:t,validateProps:n}){return{root:t,plugins:[Tt(e),dr({remarkPlugins:[gr,hr,yr,ne,_t(n,e)],rehypePlugins:[vr],providerImportSource:"@mdx-js/react"}),mr(),fr({optimize:!1})],cacheDir:ve.resolve(e,".velu","vite-cache"),optimizeDeps:{include:["react","react-dom","react-dom/client","react-router-dom","@mdx-js/react","lucide-react","prism-react-renderer","iso-639-1","github-slugger"],exclude:["tailwindcss","@tailwindcss/oxide","playwright","playwright-core","@apidevtools/swagger-parser","satori","@resvg/resvg-js","pagefind"],esbuildOptions:{loader:{".mdx":"jsx"}}},resolve:{alias:br(t),dedupe:["react","react-dom","@mdx-js/react"]}}}var Ft=j(()=>{Re();Lt();Ct()});function A(e){return{category:"render-crash",severity:"error",file:null,line:null,column:null,frame:null,title:"Something went wrong",detail:"",hint:"",suggestion:null,...e}}function xr(e,t){if(e=String(e),t=String(t),e===t)return 0;if(!e.length)return t.length;if(!t.length)return e.length;let n=Array.from({length:t.length+1},(o,i)=>i),r=new Array(t.length+1);for(let o=1;o<=e.length;o++){r[0]=o;for(let i=1;i<=t.length;i++){let a=e[o-1]===t[i-1]?0:1;r[i]=Math.min(r[i-1]+1,n[i]+1,n[i-1]+a)}[n,r]=[r,n]}return n[t.length]}function be(e,t=[]){if(!e)return null;let n=String(e).toLowerCase(),r=null,o=1/0;for(let a of t){let s=xr(n,String(a).toLowerCase());s<o&&(o=s,r=a)}let i=Math.min(3,Math.max(2,Math.floor(n.length/4)));return o<=i?r:null}function $r(e,t){return e==="warning"?E(t,_.yellow,"\u26A0"):e==="info"?E(t,_.cyan,"\u2139"):E(t,_.red,"\u2716")}function Je(e,{color:t=!1}={}){let n=Ge[e.category]||e.category,r=e.line?`${e.line}${e.column?`:${e.column}`:""}`:"",o=e.file?`${e.file}${r?`:${r}`:""}`:r,i=[];if(i.push(`${$r(e.severity,t)} ${E(t,_.bold,n)}`+(o?` ${E(t,_.dim,o)}`:"")),e.title&&i.push(` ${e.title}`),e.detail&&e.detail!==e.title&&i.push(` ${E(t,_.dim,e.detail)}`),e.frame)for(let a of String(e.frame).split(`
29
- `))i.push(` ${a}`);return e.suggestion&&i.push(` ${E(t,_.cyan,`Did you mean <${e.suggestion}>?`)}`),e.hint&&i.push(` ${E(t,_.dim,`\u2192 ${e.hint}`)}`),i.join(`
30
- `)}function xe(e,{color:t=!1}={}){if(!e.length)return E(t,_.cyan,"\u2713 No issues found.");let n=new Map;for(let s of e){let l=s.file||"velu.json";n.has(l)||n.set(l,[]),n.get(l).push(s)}let r=[];for(let[s,l]of n){r.push(E(t,_.bold,s));for(let p of l)r.push(Je({...p,file:null},{color:t}).replace(/^/gm," "));r.push("")}let o=e.filter(s=>s.severity!=="warning"&&s.severity!=="info").length,i=e.length-o,a=`${o} error${o===1?"":"s"}`+(i?`, ${i} warning${i===1?"":"s"}`:"");return r.push(E(t,o?_.red:_.yellow,a)),r.join(`
31
- `)}var Ge,_,E,J=j(()=>{Ge={"mdx-syntax":"MDX syntax",frontmatter:"Frontmatter","unknown-component":"Unknown component","invalid-props":"Invalid options","render-crash":"Render error","config-json":"velu.json","config-schema":"velu.json","config-nav":"Navigation","config-asset":"Asset"};_={reset:"\x1B[0m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m",bold:"\x1B[1m"},E=(e,t,n)=>e?`${t}${n}${_.reset}`:n});function wr(e){let t=e,n=0;for(;t&&t.cause&&n<3&&!(t.loc||t.line||/`[^`]+` to be defined/.test(t.message||""));)t=t.cause,n+=1;return t||e}function Ve(e,t){if(!e)return null;let n=Nt(e).replace(/[?#].*$/,""),r=t?Nt(t).replace(/\/+$/,""):"";return r&&n.toLowerCase().startsWith(r.toLowerCase())?n.slice(r.length).replace(/^\/+/,""):!/^([a-zA-Z]:\/|\/)/.test(n)&&!/node_modules/.test(n)?n:null}function Sr(e){return e?String(e).replace(/([a-zA-Z]:\\|\/)[^\s'"()]+/g,t=>/node_modules|[\\/]vite[\\/]|@veluai|velu-cli|velu-ui/.test(t)?"\u2026":t).trim():""}function kr(e){let t=/\((\d+):(\d+)(?:-\d+:\d+)?\)\s*$/.exec(String(e||""));return t?{line:Number(t[1]),column:Number(t[2])}:null}function jr(e){return String(e||"").replace(/\s*\(\d+:\d+(?:-\d+:\d+)?\)\s*$/,"").trim()}function Or(e,t){if(!e||!t)return null;let n=String(e);return/node_modules|[\\/]vite[\\/]|@veluai[\\/]/.test(n)?null:n}function ae(e,t={}){let{projectDir:n="",knownComponents:r=[],file:o=null}=t,i=null;for(let h=e,w=0;h&&w<6;h=h.cause,w+=1)if(h.veluIssue){i=h.veluIssue;break}if(i)return A({...i,file:i.file||o});let a=wr(e)||{},s=a.message||String(e||""),l=/Expected component `([^`]+)` to be defined/.exec(s);if(l){let h=l[1],w=/referenced in your code at `(\d+):(\d+)/.exec(s),F=/\bin `([^`]+)`/.exec(s),x=F?Ve(F[1],n):null;return A({category:"unknown-component",file:x||o,line:w?Number(w[1]):null,column:w?Number(w[2]):null,title:`<${h}> is not a built-in component`,detail:"",hint:"Components are built in \u2014 check the spelling and capitalization (you don\u2019t import them).",suggestion:be(h,r)})}let p=a.loc||(a.line!=null?{line:a.line,column:a.column,file:a.file}:null)||kr(a.reason||s),u=a.id||p&&p.file||a.file||null,c=Ve(u,n)||o,b=!!c&&Ve(u,n)!=null,d=Or(a.frame,b||!!o),$=Sr(jr(a.reason||s)),m=Ar.test(s),L=a.source==="remark-frontmatter"||/\byaml\b|frontmatter/i.test(s)||p&&p.line===1&&/unexpected|expected/i.test(s)&&/---/.test(s);return p||m||d&&b?A({category:L?"frontmatter":"mdx-syntax",file:c,line:p?p.line:null,column:p?p.column:null,frame:d,title:$||(L?"Invalid frontmatter":"MDX syntax error"),detail:"",hint:L?"Check the YAML between the --- markers \u2014 indentation, quotes, and colons.":"Make sure every <Component> has a matching closing tag and that { } braces are balanced."}):/\.map is not a function|is not iterable|reading '|undefined \(reading/i.test(s)?A({category:"invalid-props",file:c,title:"A component received an invalid value",detail:$,hint:"Check the props/options you passed to a component on this page."}):A({category:"render-crash",file:c,title:"This page failed to render",detail:$,hint:"Set VELU_DEBUG=1 for the full stack trace."})}var Nt,Ar,qe=j(()=>{J();Nt=e=>String(e).replace(/\\/g,"/");Ar=/closing tag|unexpected closing|could not parse (?:expression|import|export)|unexpected character|unexpected end of|expected a closing|expected the closing|unexpected `|in expression|misnested|before name/i});function Tr(e){let t=Ge[e.category]||e.category,n=e.file?`${e.file}${e.line?`:${e.line}${e.column?`:${e.column}`:""}`:""}`:"",r=[];return r.push('<div class="velu-err-card">'),r.push('<div class="velu-err-head">'),r.push(`<span class="velu-err-pill">${I(t)}</span>`),r.push("</div>"),e.title&&r.push(`<div class="velu-err-title">${I(e.title)}</div>`),n&&r.push(`<a class="velu-err-loc" title="${I(n)}">${I(n)}</a>`),e.detail&&r.push(`<div class="velu-err-detail">${I(e.detail)}</div>`),e.frame&&r.push(`<pre class="velu-err-frame">${I(e.frame)}</pre>`),e.suggestion&&r.push(`<div class="velu-err-suggest">Did you mean <code>&lt;${I(e.suggestion)}&gt;</code>?</div>`),e.hint&&r.push(`<div class="velu-err-hint">${I(e.hint)}</div>`),r.push("</div>"),r.join("")}function He(e,t={}){let n=Array.isArray(e)?e:[e],r=t.title||(n.length>1?`${n.length} problems to fix`:"There\u2019s a problem to fix"),o=n.map(Tr).join(`
28
+ `)}var Tt,Ot,Pt=j(()=>{B();oe();Y();Ge();Tt="virtual:velu-site",Ot="\0"+Tt});import{visit as cr}from"unist-util-visit";function ur(e,t){let n=_t(e).replace(/[?#].*$/,""),r=_t(t).replace(/\/+$/,"");return r&&n.toLowerCase().startsWith(r.toLowerCase())?n.slice(r.length).replace(/^\/+/,""):null}function Ct(e,t){return()=>(n,r)=>{typeof e=="function"&&cr(n,o=>{if(o.type!=="mdxJsxFlowElement"&&o.type!=="mdxJsxTextElement"||typeof o.name!="string"||!/^[A-Z]/.test(o.name)||o.name.includes("."))return;let i={};for(let s of o.attributes||[])s.type==="mdxJsxAttribute"&&(s.value==null?i[s.name]=!0:typeof s.value=="string"&&(i[s.name]=s.value));let a=e(o.name,i,{checkRequired:!1});if(a){let s=new Error(a.title);throw s.veluIssue={...a,file:ur(r?.path,t),line:o.position?.start?.line??null,column:o.position?.start?.column??null},s.loc={line:s.veluIssue.line,column:s.veluIssue.column},s}})}}var _t,Et=j(()=>{_t=e=>String(e||"").replace(/\\/g,"/")});import ye from"node:path";import pr from"node:fs";import{createRequire as fr}from"node:module";import mr from"@tailwindcss/vite";import dr from"@vitejs/plugin-react";import gr from"@mdx-js/rollup";import hr from"remark-frontmatter";import yr from"remark-mdx-frontmatter";import vr from"remark-gfm";import br from"rehype-slug";function xr(e){let n=fr(import.meta.url).resolve("@mdx-js/react"),r=ye.resolve(e,"runtime","velu-ui"),o=pr.existsSync(r)?r:ye.resolve(e,"..","velu-ui","src");return[{find:"@mdx-js/react",replacement:n},{find:/^velu-ui$/,replacement:ye.join(o,"index.js")},{find:/^velu-ui\//,replacement:o+"/"}]}function Ft({targetDir:e,VITE_ROOT:t,validateProps:n}){return{root:t,plugins:[Lt(e),gr({remarkPlugins:[hr,yr,vr,ne,Ct(n,e)],rehypePlugins:[br],providerImportSource:"@mdx-js/react"}),dr(),mr({optimize:!1})],cacheDir:ye.resolve(e,".velu","vite-cache"),optimizeDeps:{include:["react","react-dom","react-dom/client","react-router-dom","@mdx-js/react","lucide-react","prism-react-renderer","iso-639-1","github-slugger"],exclude:["tailwindcss","@tailwindcss/oxide","playwright","playwright-core","@apidevtools/swagger-parser","satori","@resvg/resvg-js","pagefind"],esbuildOptions:{loader:{".mdx":"jsx"}}},resolve:{alias:xr(t),dedupe:["react","react-dom","@mdx-js/react"]}}}var Nt=j(()=>{Ue();Pt();Et()});function A(e){return{category:"render-crash",severity:"error",file:null,line:null,column:null,frame:null,title:"Something went wrong",detail:"",hint:"",suggestion:null,...e}}function $r(e,t){if(e=String(e),t=String(t),e===t)return 0;if(!e.length)return t.length;if(!t.length)return e.length;let n=Array.from({length:t.length+1},(o,i)=>i),r=new Array(t.length+1);for(let o=1;o<=e.length;o++){r[0]=o;for(let i=1;i<=t.length;i++){let a=e[o-1]===t[i-1]?0:1;r[i]=Math.min(r[i-1]+1,n[i]+1,n[i-1]+a)}[n,r]=[r,n]}return n[t.length]}function ve(e,t=[]){if(!e)return null;let n=String(e).toLowerCase(),r=null,o=1/0;for(let a of t){let s=$r(n,String(a).toLowerCase());s<o&&(o=s,r=a)}let i=Math.min(3,Math.max(2,Math.floor(n.length/4)));return o<=i?r:null}function wr(e,t){return e==="warning"?E(t,C.yellow,"\u26A0"):e==="info"?E(t,C.cyan,"\u2139"):E(t,C.red,"\u2716")}function Ve(e,{color:t=!1}={}){let n=Je[e.category]||e.category,r=e.line?`${e.line}${e.column?`:${e.column}`:""}`:"",o=e.file?`${e.file}${r?`:${r}`:""}`:r,i=[];if(i.push(`${wr(e.severity,t)} ${E(t,C.bold,n)}`+(o?` ${E(t,C.dim,o)}`:"")),e.title&&i.push(` ${e.title}`),e.detail&&e.detail!==e.title&&i.push(` ${E(t,C.dim,e.detail)}`),e.frame)for(let a of String(e.frame).split(`
29
+ `))i.push(` ${a}`);return e.suggestion&&i.push(` ${E(t,C.cyan,`Did you mean <${e.suggestion}>?`)}`),e.hint&&i.push(` ${E(t,C.dim,`\u2192 ${e.hint}`)}`),i.join(`
30
+ `)}function be(e,{color:t=!1}={}){if(!e.length)return E(t,C.cyan,"\u2713 No issues found.");let n=new Map;for(let s of e){let l=s.file||"velu.json";n.has(l)||n.set(l,[]),n.get(l).push(s)}let r=[];for(let[s,l]of n){r.push(E(t,C.bold,s));for(let p of l)r.push(Ve({...p,file:null},{color:t}).replace(/^/gm," "));r.push("")}let o=e.filter(s=>s.severity!=="warning"&&s.severity!=="info").length,i=e.length-o,a=`${o} error${o===1?"":"s"}`+(i?`, ${i} warning${i===1?"":"s"}`:"");return r.push(E(t,o?C.red:C.yellow,a)),r.join(`
31
+ `)}var Je,C,E,J=j(()=>{Je={"mdx-syntax":"MDX syntax",frontmatter:"Frontmatter","unknown-component":"Unknown component","invalid-props":"Invalid options","render-crash":"Render error","config-json":"velu.json","config-schema":"velu.json","config-nav":"Navigation","config-asset":"Asset"};C={reset:"\x1B[0m",red:"\x1B[31m",yellow:"\x1B[33m",cyan:"\x1B[36m",dim:"\x1B[2m",bold:"\x1B[1m"},E=(e,t,n)=>e?`${t}${n}${C.reset}`:n});function Sr(e){let t=e,n=0;for(;t&&t.cause&&n<3&&!(t.loc||t.line||/`[^`]+` to be defined/.test(t.message||""));)t=t.cause,n+=1;return t||e}function qe(e,t){if(!e)return null;let n=It(e).replace(/[?#].*$/,""),r=t?It(t).replace(/\/+$/,""):"";return r&&n.toLowerCase().startsWith(r.toLowerCase())?n.slice(r.length).replace(/^\/+/,""):!/^([a-zA-Z]:\/|\/)/.test(n)&&!/node_modules/.test(n)?n:null}function kr(e){return e?String(e).replace(/([a-zA-Z]:\\|\/)[^\s'"()]+/g,t=>/node_modules|[\\/]vite[\\/]|@veluai|velu-cli|velu-ui/.test(t)?"\u2026":t).trim():""}function jr(e){let t=/\((\d+):(\d+)(?:-\d+:\d+)?\)\s*$/.exec(String(e||""));return t?{line:Number(t[1]),column:Number(t[2])}:null}function Ar(e){return String(e||"").replace(/\s*\(\d+:\d+(?:-\d+:\d+)?\)\s*$/,"").trim()}function Tr(e,t){if(!e||!t)return null;let n=String(e);return/node_modules|[\\/]vite[\\/]|@veluai[\\/]/.test(n)?null:n}function ae(e,t={}){let{projectDir:n="",knownComponents:r=[],file:o=null}=t,i=null;for(let h=e,w=0;h&&w<6;h=h.cause,w+=1)if(h.veluIssue){i=h.veluIssue;break}if(i)return A({...i,file:i.file||o});let a=Sr(e)||{},s=a.message||String(e||""),l=/Expected component `([^`]+)` to be defined/.exec(s);if(l){let h=l[1],w=/referenced in your code at `(\d+):(\d+)/.exec(s),F=/\bin `([^`]+)`/.exec(s),x=F?qe(F[1],n):null;return A({category:"unknown-component",file:x||o,line:w?Number(w[1]):null,column:w?Number(w[2]):null,title:`<${h}> is not a built-in component`,detail:"",hint:"Components are built in \u2014 check the spelling and capitalization (you don\u2019t import them).",suggestion:ve(h,r)})}let p=a.loc||(a.line!=null?{line:a.line,column:a.column,file:a.file}:null)||jr(a.reason||s),u=a.id||p&&p.file||a.file||null,c=qe(u,n)||o,b=!!c&&qe(u,n)!=null,d=Tr(a.frame,b||!!o),$=kr(Ar(a.reason||s)),m=Or.test(s),L=a.source==="remark-frontmatter"||/\byaml\b|frontmatter/i.test(s)||p&&p.line===1&&/unexpected|expected/i.test(s)&&/---/.test(s);return p||m||d&&b?A({category:L?"frontmatter":"mdx-syntax",file:c,line:p?p.line:null,column:p?p.column:null,frame:d,title:$||(L?"Invalid frontmatter":"MDX syntax error"),detail:"",hint:L?"Check the YAML between the --- markers \u2014 indentation, quotes, and colons.":"Make sure every <Component> has a matching closing tag and that { } braces are balanced."}):/\.map is not a function|is not iterable|reading '|undefined \(reading/i.test(s)?A({category:"invalid-props",file:c,title:"A component received an invalid value",detail:$,hint:"Check the props/options you passed to a component on this page."}):A({category:"render-crash",file:c,title:"This page failed to render",detail:$,hint:"Set VELU_DEBUG=1 for the full stack trace."})}var It,Or,He=j(()=>{J();It=e=>String(e).replace(/\\/g,"/");Or=/closing tag|unexpected closing|could not parse (?:expression|import|export)|unexpected character|unexpected end of|expected a closing|expected the closing|unexpected `|in expression|misnested|before name/i});function Lr(e){let t=Je[e.category]||e.category,n=e.file?`${e.file}${e.line?`:${e.line}${e.column?`:${e.column}`:""}`:""}`:"",r=[];return r.push('<div class="velu-err-card">'),r.push('<div class="velu-err-head">'),r.push(`<span class="velu-err-pill">${I(t)}</span>`),r.push("</div>"),e.title&&r.push(`<div class="velu-err-title">${I(e.title)}</div>`),n&&r.push(`<a class="velu-err-loc" title="${I(n)}">${I(n)}</a>`),e.detail&&r.push(`<div class="velu-err-detail">${I(e.detail)}</div>`),e.frame&&r.push(`<pre class="velu-err-frame">${I(e.frame)}</pre>`),e.suggestion&&r.push(`<div class="velu-err-suggest">Did you mean <code>&lt;${I(e.suggestion)}&gt;</code>?</div>`),e.hint&&r.push(`<div class="velu-err-hint">${I(e.hint)}</div>`),r.push("</div>"),r.join("")}function De(e,t={}){let n=Array.isArray(e)?e:[e],r=t.title||(n.length>1?`${n.length} problems to fix`:"There\u2019s a problem to fix"),o=n.map(Lr).join(`
32
32
  `);return`<!doctype html>
33
33
  <html lang="en">
34
34
  <head>
@@ -100,21 +100,21 @@ ${L.join(`,
100
100
  <div class="velu-err-foot">Fix the file and save \u2014 this page reloads automatically.</div>
101
101
  </div>
102
102
  </body>
103
- </html>`}var I,It=j(()=>{J();I=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")});var V,De=j(()=>{V=["Callout","Card","CardGroup","Accordion","AccordionGroup","Columns","Field","Prompt","Steps","Step","Tree","Folder","File","Image","CodeBlock","CodeGroup","MethodBadge","ApiPath","TryItBar","ApiField","ApiClient","ApiSidebar"]});import $e from"node:fs";import ce from"node:path";import{fileURLToPath as Lr}from"node:url";import Pr from"iso-639-1";function le(e,t){if(!t)return null;let n=e.indexOf(`"${t}"`);return n===-1?null:e.slice(0,n).split(`
104
- `).length}function Er(e,t){return t==null||t<0?null:e.slice(0,t).split(`
105
- `).length}function Xe(e,t){if(!t)return null;let n=e.indexOf(`"${t}"`);return n===-1?null:e.slice(0,n).split(`
106
- `).length}function Fr(e,t,n){let r=[];return s(e,t,"",null),r;function o(l){if(l&&l.$ref){let p=l.$ref.replace(/^#\//,"").split("/"),u=n;for(let c of p)u=u?.[c];return u||{}}return l}function i(l){return Array.isArray(l)?"array":l===null?"null":typeof l}function a(l,p){let u=r.length;s(l,p,"",null,!0);let c=r.length===u;return c||(r.length=u),c}function s(l,p,u,c,b){let d=o(p);if(d){if(d.oneOf){d.oneOf.some(m=>a(l,m))||r.push({path:u,key:c,message:"value does not match any allowed shape"});return}if(d.type&&i(l)!==d.type){r.push({path:u,key:c,message:`expected ${d.type}, got ${i(l)}`});return}if(d.type==="string"&&d.minLength!=null&&l.length<d.minLength&&r.push({path:u,key:c,message:"must not be empty"}),d.type==="object"&&i(l)==="object"){for(let m of d.required||[])m in l||r.push({path:u?`${u}.${m}`:m,key:m,message:`missing required "${m}"`});let $=d.properties||{};if(d.additionalProperties===!1)for(let m of Object.keys(l))m in $||r.push({path:u?`${u}.${m}`:m,key:m,message:`unknown field "${m}"`});for(let[m,L]of Object.entries($))m in l&&s(l[m],L,u?`${u}.${m}`:m,m,b)}d.type==="array"&&Array.isArray(l)&&d.items&&l.forEach(($,m)=>s($,d.items,`${u}[${m}]`,c,b))}}}function Nr(e){if(typeof e!="string")return!1;let t=e.trim();return/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(t)||/^(rgb|rgba|hsl|hsla|color|oklch|lab|lch)\(/i.test(t)||/^[a-z][a-z0-9-]*$/i.test(t)}function we(e){let t=[],n=ce.join(e,"velu.json"),r;try{r=$e.readFileSync(n,"utf-8")}catch(s){return s.code==="ENOENT"?t.push(A({category:"config-json",file:"velu.json",title:"No velu.json found",hint:"Run `velu init <name>` to scaffold a project."})):t.push(A({category:"config-json",file:"velu.json",title:"Could not read velu.json"})),t}let o;try{o=JSON.parse(r)}catch(s){let l=/position (\d+)/.exec(s.message||""),p=l?Er(r,Number(l[1])):null;return t.push(A({category:"config-json",file:"velu.json",line:p,title:"velu.json is not valid JSON",detail:String(s.message||"").replace(/\s+in JSON.*$/,""),hint:"Check for a trailing comma, a missing quote, or an unclosed brace."})),t}let i=null;try{i=JSON.parse($e.readFileSync(Cr,"utf-8"))}catch{}if(i)for(let s of Fr(o,i,i)){let l=/^unknown field/.test(s.message);t.push(A({category:"config-schema",severity:l?"warning":"error",file:"velu.json",line:le(r,s.key),title:s.path?`${s.path}: ${s.message}`:s.message,hint:l?"Remove it, or check the spelling against the velu.json schema.":""}))}for(let s of["primary","light","dark"]){let l=o.colors?.[s];l!=null&&!Nr(l)&&t.push(A({category:"config-schema",severity:"warning",file:"velu.json",line:le(r,s),title:`colors.${s}: "${l}" doesn\u2019t look like a CSS color`,hint:"Use a hex value like #dc143c, an rgb()/hsl() function, or a CSS color name."}))}if(typeof o.favicon=="string"&&o.favicon.trim()){let s=ce.resolve(e,o.favicon.replace(/^\/+/,""));$e.existsSync(s)||t.push(A({category:"config-asset",file:"velu.json",line:le(r,"favicon"),title:`favicon not found: ${o.favicon}`,hint:"The path is relative to the project root."}))}let a=te(o.logo);if(a){let s=new Map;for(let l of["light","dark"]){let p=a[l];p&&s.set(p,[...s.get(p)||[],l])}for(let[l,p]of s)if(!$e.existsSync(ce.resolve(e,l.replace(/^\/+/,"")))){let u=p.length===2?"logo":`logo (${p[0]})`;t.push(A({category:"config-asset",file:"velu.json",line:Xe(r,l),title:`${u} not found: ${l}`,hint:"The path is relative to the project root."}))}}if(o.navigation&&typeof o.navigation=="object"){let s;try{s=U(o.navigation)}catch(l){t.push(A({category:"config-nav",file:"velu.json",line:le(r,"navigation"),title:"navigation could not be processed",detail:String(l.message||"")})),s=null}if(s){let{pageEntries:l,warnings:p}=M(s,e);for(let u of p){let c=/not found$/.test(u),b=/page "([^"]+)"/.exec(u),d=b?Xe(r,b[1]):null;t.push(A({category:"config-nav",severity:c?"error":"warning",file:"velu.json",line:d,title:u,hint:c?"Create the .mdx file, or remove the page from navigation.":""}))}Ir(s,r,t)}}return t}function Ir(e,t,n){let r=new Set,o=i=>{if(!(!i||typeof i!="object")){if(i.language&&!r.has(i.language)){r.add(i.language);let a=String(i.language).toLowerCase();Pr.validate(a)||n.push(A({category:"config-nav",severity:"warning",file:"velu.json",line:Xe(t,i.language)||le(t,"language"),title:`"${i.language}" is not a valid ISO 639-1 language code`,hint:'Use a two-letter code like "en", "fr", or "ja".'}))}for(let a of Object.values(i))Array.isArray(a)?a.forEach(o):a&&typeof a=="object"&&o(a)}};o(e)}var _r,Cr,Ye=j(()=>{J();B();oe();Y();_r=ce.dirname(Lr(import.meta.url)),Cr=ce.resolve(_r,"..","..","schema","velu.schema.json")});import Rr from"node:fs/promises";import Ur from"node:fs";import q from"node:path";import{fileURLToPath as Mr,pathToFileURL as zr}from"node:url";import{compile as Br}from"@mdx-js/mdx";import Gr from"remark-frontmatter";import Jr from"remark-mdx-frontmatter";import Vr from"remark-gfm";import qr from"rehype-slug";import{visit as Hr}from"unist-util-visit";function Ke(){if(Se)return Se;let e=q.dirname(Mr(import.meta.url)),t=[q.resolve(e,"..","runtime","velu-ui"),q.resolve(e,"..","..","runtime","velu-ui"),q.resolve(e,"..","..","..","velu-ui","src")],n=null;for(let r of t){let o=q.join(r,"lib","component-schemas.js");if(Ur.existsSync(o)){n=o;break}}return Se=n?import(zr(n).href).then(r=>r.validateProps).catch(()=>null):Promise.resolve(null),Se}function Dr(e){let t={};for(let n of e.attributes||[])n.type==="mdxJsxAttribute"&&(n.value==null?t[n.name]=!0:typeof n.value=="string"&&(t[n.name]=n.value));return t}function Xr(e,t){return()=>n=>{Hr(n,r=>{if((r.type==="mdxJsxFlowElement"||r.type==="mdxJsxTextElement")&&typeof r.name=="string"&&/^[A-Z]/.test(r.name)&&!r.name.includes(".")&&e.push({name:r.name,props:Dr(r),line:r.position?.start?.line??null,column:r.position?.start?.column??null}),r.type==="mdxjsEsm"&&typeof r.value=="string")for(let o of r.value.matchAll(/\b([A-Z][A-Za-z0-9_]*)\b/g))t.add(o[1])})}}async function Yr(e,t){let n=[],r;try{r=await Rr.readFile(t.fileAbsPath,"utf-8")}catch{return n}let o=q.relative(e,t.fileAbsPath).split(q.sep).join("/"),i=[],a=new Set;try{await Br({value:r,path:t.fileAbsPath},{remarkPlugins:[Gr,Jr,Vr,ne,Xr(i,a)],rehypePlugins:[qr],providerImportSource:"@mdx-js/react"})}catch(u){return n.push(ae(u,{projectDir:e,knownComponents:V,file:o})),n}let s=new Set(V),l=await Ke(),p=new Set;for(let u of i)if(!a.has(u.name)){if(!s.has(u.name)){if(p.has(u.name))continue;p.add(u.name),n.push(A({category:"unknown-component",file:o,line:u.line,column:u.column,title:`<${u.name}> is not a built-in component`,hint:"Components are built in \u2014 check the spelling and capitalization (you don\u2019t import them).",suggestion:be(u.name,V)}));continue}if(l){let c=l(u.name,u.props,{checkRequired:!1});c&&n.push(A({...c,file:o,line:u.line,column:u.column}))}}return n}async function Rt(e,t){let n=t.filter(s=>s.exists),r=[],o=8,i=0;async function a(){for(;i<n.length;){let s=n[i++],l=await Yr(e,s);for(let p of l)r.push(p)}}return await Promise.all(Array.from({length:Math.min(o,n.length)},a)),r}var Se,We=j(()=>{Re();J();qe();De()});import ke from"node:fs";import Ze from"node:path";import zt from"js-yaml";function Qe(e,t,n){if(n>24||e===null||typeof e!="object")return n>24&&e&&typeof e=="object"?null:e;if(t.has(e))return null;t.add(e);let r;if(Array.isArray(e))r=e.map(o=>Qe(o,t,n+1));else{r={};for(let[o,i]of Object.entries(e))r[o]=Qe(i,t,n+1)}return t.delete(e),r}function Bt(e){return zt.dump(Qe(e,new Set,0),{noRefs:!0,lineWidth:100,skipInvalid:!0})}function Gt(e){let t=String(e).replace(/\.md$/i,"");return t===""||t==="/"||t==="/index"?"/":t.replace(/\/+$/,"")||"/"}function Kr(e){return e==="/"?"/index.md":`${e}.md`}function et(e,t){if(t==="api")return`# ${Ut}
107
- ${e}`;let n=e.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n/),r=`> ${Ut}
103
+ </html>`}var I,Rt=j(()=>{J();I=e=>String(e??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")});var V,Xe=j(()=>{V=["Callout","Card","CardGroup","Accordion","AccordionGroup","Columns","Field","Prompt","Steps","Step","Tree","Folder","File","Image","CodeBlock","CodeGroup","MethodBadge","ApiPath","TryItBar","ApiField","ApiClient","ApiSidebar"]});import xe from"node:fs";import ce from"node:path";import{fileURLToPath as Pr}from"node:url";import _r from"iso-639-1";function le(e,t){if(!t)return null;let n=e.indexOf(`"${t}"`);return n===-1?null:e.slice(0,n).split(`
104
+ `).length}function Fr(e,t){return t==null||t<0?null:e.slice(0,t).split(`
105
+ `).length}function Ye(e,t){if(!t)return null;let n=e.indexOf(`"${t}"`);return n===-1?null:e.slice(0,n).split(`
106
+ `).length}function Nr(e,t,n){let r=[];return s(e,t,"",null),r;function o(l){if(l&&l.$ref){let p=l.$ref.replace(/^#\//,"").split("/"),u=n;for(let c of p)u=u?.[c];return u||{}}return l}function i(l){return Array.isArray(l)?"array":l===null?"null":typeof l}function a(l,p){let u=r.length;s(l,p,"",null,!0);let c=r.length===u;return c||(r.length=u),c}function s(l,p,u,c,b){let d=o(p);if(d){if(d.oneOf){d.oneOf.some(m=>a(l,m))||r.push({path:u,key:c,message:"value does not match any allowed shape"});return}if(d.type&&i(l)!==d.type){r.push({path:u,key:c,message:`expected ${d.type}, got ${i(l)}`});return}if(d.type==="string"&&d.minLength!=null&&l.length<d.minLength&&r.push({path:u,key:c,message:"must not be empty"}),d.type==="object"&&i(l)==="object"){for(let m of d.required||[])m in l||r.push({path:u?`${u}.${m}`:m,key:m,message:`missing required "${m}"`});let $=d.properties||{};if(d.additionalProperties===!1)for(let m of Object.keys(l))m in $||r.push({path:u?`${u}.${m}`:m,key:m,message:`unknown field "${m}"`});for(let[m,L]of Object.entries($))m in l&&s(l[m],L,u?`${u}.${m}`:m,m,b)}d.type==="array"&&Array.isArray(l)&&d.items&&l.forEach(($,m)=>s($,d.items,`${u}[${m}]`,c,b))}}}function Ir(e){if(typeof e!="string")return!1;let t=e.trim();return/^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(t)||/^(rgb|rgba|hsl|hsla|color|oklch|lab|lch)\(/i.test(t)||/^[a-z][a-z0-9-]*$/i.test(t)}function $e(e){let t=[],n=ce.join(e,"velu.json"),r;try{r=xe.readFileSync(n,"utf-8")}catch(s){return s.code==="ENOENT"?t.push(A({category:"config-json",file:"velu.json",title:"No velu.json found",hint:"Run `velu init <name>` to scaffold a project."})):t.push(A({category:"config-json",file:"velu.json",title:"Could not read velu.json"})),t}let o;try{o=JSON.parse(r)}catch(s){let l=/position (\d+)/.exec(s.message||""),p=l?Fr(r,Number(l[1])):null;return t.push(A({category:"config-json",file:"velu.json",line:p,title:"velu.json is not valid JSON",detail:String(s.message||"").replace(/\s+in JSON.*$/,""),hint:"Check for a trailing comma, a missing quote, or an unclosed brace."})),t}let i=null;try{i=JSON.parse(xe.readFileSync(Er,"utf-8"))}catch{}if(i)for(let s of Nr(o,i,i)){let l=/^unknown field/.test(s.message);t.push(A({category:"config-schema",severity:l?"warning":"error",file:"velu.json",line:le(r,s.key),title:s.path?`${s.path}: ${s.message}`:s.message,hint:l?"Remove it, or check the spelling against the velu.json schema.":""}))}for(let s of["primary","light","dark"]){let l=o.colors?.[s];l!=null&&!Ir(l)&&t.push(A({category:"config-schema",severity:"warning",file:"velu.json",line:le(r,s),title:`colors.${s}: "${l}" doesn\u2019t look like a CSS color`,hint:"Use a hex value like #dc143c, an rgb()/hsl() function, or a CSS color name."}))}if(typeof o.favicon=="string"&&o.favicon.trim()){let s=ce.resolve(e,o.favicon.replace(/^\/+/,""));xe.existsSync(s)||t.push(A({category:"config-asset",file:"velu.json",line:le(r,"favicon"),title:`favicon not found: ${o.favicon}`,hint:"The path is relative to the project root."}))}let a=te(o.logo);if(a){let s=new Map;for(let l of["light","dark"]){let p=a[l];p&&s.set(p,[...s.get(p)||[],l])}for(let[l,p]of s)if(!xe.existsSync(ce.resolve(e,l.replace(/^\/+/,"")))){let u=p.length===2?"logo":`logo (${p[0]})`;t.push(A({category:"config-asset",file:"velu.json",line:Ye(r,l),title:`${u} not found: ${l}`,hint:"The path is relative to the project root."}))}}if(o.navigation&&typeof o.navigation=="object"){let s;try{s=U(o.navigation)}catch(l){t.push(A({category:"config-nav",file:"velu.json",line:le(r,"navigation"),title:"navigation could not be processed",detail:String(l.message||"")})),s=null}if(s){let{pageEntries:l,warnings:p}=M(s,e);for(let u of p){let c=/not found$/.test(u),b=/page "([^"]+)"/.exec(u),d=b?Ye(r,b[1]):null;t.push(A({category:"config-nav",severity:c?"error":"warning",file:"velu.json",line:d,title:u,hint:c?"Create the .mdx file, or remove the page from navigation.":""}))}Rr(s,r,t)}}return t}function Rr(e,t,n){let r=new Set,o=i=>{if(!(!i||typeof i!="object")){if(i.language&&!r.has(i.language)){r.add(i.language);let a=String(i.language).toLowerCase();_r.validate(a)||n.push(A({category:"config-nav",severity:"warning",file:"velu.json",line:Ye(t,i.language)||le(t,"language"),title:`"${i.language}" is not a valid ISO 639-1 language code`,hint:'Use a two-letter code like "en", "fr", or "ja".'}))}for(let a of Object.values(i))Array.isArray(a)?a.forEach(o):a&&typeof a=="object"&&o(a)}};o(e)}var Cr,Er,Ke=j(()=>{J();B();oe();Y();Cr=ce.dirname(Pr(import.meta.url)),Er=ce.resolve(Cr,"..","..","schema","velu.schema.json")});import Ur from"node:fs/promises";import Mr from"node:fs";import q from"node:path";import{fileURLToPath as zr,pathToFileURL as Br}from"node:url";import{compile as Gr}from"@mdx-js/mdx";import Jr from"remark-frontmatter";import Vr from"remark-mdx-frontmatter";import qr from"remark-gfm";import Hr from"rehype-slug";import{visit as Dr}from"unist-util-visit";function We(){if(we)return we;let e=q.dirname(zr(import.meta.url)),t=[q.resolve(e,"..","runtime","velu-ui"),q.resolve(e,"..","..","runtime","velu-ui"),q.resolve(e,"..","..","..","velu-ui","src")],n=null;for(let r of t){let o=q.join(r,"lib","component-schemas.js");if(Mr.existsSync(o)){n=o;break}}return we=n?import(Br(n).href).then(r=>r.validateProps).catch(()=>null):Promise.resolve(null),we}function Xr(e){let t={};for(let n of e.attributes||[])n.type==="mdxJsxAttribute"&&(n.value==null?t[n.name]=!0:typeof n.value=="string"&&(t[n.name]=n.value));return t}function Yr(e,t){return()=>n=>{Dr(n,r=>{if((r.type==="mdxJsxFlowElement"||r.type==="mdxJsxTextElement")&&typeof r.name=="string"&&/^[A-Z]/.test(r.name)&&!r.name.includes(".")&&e.push({name:r.name,props:Xr(r),line:r.position?.start?.line??null,column:r.position?.start?.column??null}),r.type==="mdxjsEsm"&&typeof r.value=="string")for(let o of r.value.matchAll(/\b([A-Z][A-Za-z0-9_]*)\b/g))t.add(o[1])})}}async function Kr(e,t){let n=[],r;try{r=await Ur.readFile(t.fileAbsPath,"utf-8")}catch{return n}let o=q.relative(e,t.fileAbsPath).split(q.sep).join("/"),i=[],a=new Set;try{await Gr({value:r,path:t.fileAbsPath},{remarkPlugins:[Jr,Vr,qr,ne,Yr(i,a)],rehypePlugins:[Hr],providerImportSource:"@mdx-js/react"})}catch(u){return n.push(ae(u,{projectDir:e,knownComponents:V,file:o})),n}let s=new Set(V),l=await We(),p=new Set;for(let u of i)if(!a.has(u.name)){if(!s.has(u.name)){if(p.has(u.name))continue;p.add(u.name),n.push(A({category:"unknown-component",file:o,line:u.line,column:u.column,title:`<${u.name}> is not a built-in component`,hint:"Components are built in \u2014 check the spelling and capitalization (you don\u2019t import them).",suggestion:ve(u.name,V)}));continue}if(l){let c=l(u.name,u.props,{checkRequired:!1});c&&n.push(A({...c,file:o,line:u.line,column:u.column}))}}return n}async function Ut(e,t){let n=t.filter(s=>s.exists),r=[],o=8,i=0;async function a(){for(;i<n.length;){let s=n[i++],l=await Kr(e,s);for(let p of l)r.push(p)}}return await Promise.all(Array.from({length:Math.min(o,n.length)},a)),r}var we,Ze=j(()=>{Ue();J();He();Xe()});import Se from"node:fs";import Qe from"node:path";import Bt from"js-yaml";function et(e,t,n){if(n>24||e===null||typeof e!="object")return n>24&&e&&typeof e=="object"?null:e;if(t.has(e))return null;t.add(e);let r;if(Array.isArray(e))r=e.map(o=>et(o,t,n+1));else{r={};for(let[o,i]of Object.entries(e))r[o]=et(i,t,n+1)}return t.delete(e),r}function Gt(e){return Bt.dump(et(e,new Set,0),{noRefs:!0,lineWidth:100,skipInvalid:!0})}function Jt(e){let t=String(e).replace(/\.md$/i,"");return t===""||t==="/"||t==="/index"?"/":t.replace(/\/+$/,"")||"/"}function Wr(e){return e==="/"?"/index.md":`${e}.md`}function tt(e,t){if(t==="api")return`# ${Mt}
107
+ ${e}`;let n=e.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n/),r=`> ${Mt}
108
108
 
109
- `;return n?e.slice(0,n[0].length)+r+e.slice(n[0].length):r+e}function Zr(e){return e.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/,"")}function Qr(e){try{let t=ke.readFileSync(e,"utf-8").match(/^---\r?\n([\s\S]*?)\r?\n---/);if(!t)return{};let n=zt.load(t[1]);return n&&typeof n=="object"?n:{}}catch{return{}}}async function ue(e){let t={};try{t=JSON.parse(ke.readFileSync(Ze.join(e,"velu.json"),"utf-8"))}catch{return{name:Ze.basename(e),baseUrl:"",pages:[]}}let n=t.name??Ze.basename(e),r=typeof t.url=="string"?t.url.replace(/\/+$/,""):"",o=z(t.api),i=t.navigation??{},a={};try{let c=await ye(t.navigation??{},{targetDir:e,api:o});i=c.nav,a=c.ops}catch(c){console.warn(`[velu] openapi: ${c.message}`)}let s=U(i),{pageEntries:l}=M(s,e),p=new Map(l.map(c=>[c.url,c])),u=[];for(let c of K(s)){if(!c.url)continue;let b=c.ancestors.filter(h=>h.kind==="group").pop(),d=c.ancestors.filter(h=>h.kind==="tab").pop(),$=b?.label||d?.label||"Pages",m=c.ancestors.filter(h=>h.kind==="tab"||h.kind==="group").map(h=>h.label),L=c.ancestors.filter(h=>h.kind==="language").pop()?.code||null;if(c.node?.api){let h=a[c.pagePath];if(!h)continue;let w=h.title||Mt(c.url);u.push({url:c.url,title:w,description:h.description||"",group:$,breadcrumb:[...m,w],lang:L,frontmatter:{title:h.title,description:h.description},source:{kind:"api",segment:h.segment}})}else{let h=p.get(c.url);if(!h||!h.exists)continue;let w=Qr(h.fileAbsPath),F=w.title||Mt(c.url);u.push({url:c.url,title:F,description:w.description||"",group:$,breadcrumb:[...m,F],lang:L,frontmatter:w,source:{kind:"mdx",fileAbsPath:h.fileAbsPath}})}}return{name:n,baseUrl:r,pages:u}}function Ae(e){return new Map(e.pages.map(t=>[t.url,{...t.source,title:t.title}]))}async function eo(e){return Ae(await ue(e))}async function tt(e,t,n){let o=(n||await eo(e)).get(t);if(!o)return null;if(o.kind==="mdx")try{return{body:ke.readFileSync(o.fileAbsPath,"utf-8"),contentType:"text/markdown; charset=utf-8",kind:"mdx"}}catch{return null}return o.segment?{body:Bt(o.segment),contentType:"text/yaml; charset=utf-8",kind:"api"}:null}async function Jt(e,t){let n=t||await ue(e),r=s=>n.baseUrl?n.baseUrl+s:s,o=[`# ${n.name}`,"",`> Documentation index for ${n.name}. Append \`.md\` to any page URL (or send \`Accept: text/markdown\`) for its Markdown; fetch ${je} for the whole site in one document.`,""],i=[],a=new Map;for(let s of n.pages)a.has(s.group)||(a.set(s.group,[]),i.push(s.group)),a.get(s.group).push(s);for(let s of i){o.push(`## ${s}`,"");for(let l of a.get(s))o.push(`- [${l.title}](${r(Kr(l.url))})${l.description?`: ${l.description}`:""}`);o.push("")}return o.join(`
110
- `)}async function Vt(e,t){let n=t||await ue(e),r=[`# ${n.name}`,"",`> Full documentation \u2014 every page concatenated. Index: ${W}`];for(let o of n.pages)if(r.push("","---","",`# ${o.title}`,`Source: ${o.url}`,""),o.source.kind==="mdx")try{r.push(Zr(ke.readFileSync(o.source.fileAbsPath,"utf-8")).trim())}catch{}else o.source.segment&&r.push("```yaml",Bt(o.source.segment).trim(),"```");return r.join(`
109
+ `;return n?e.slice(0,n[0].length)+r+e.slice(n[0].length):r+e}function Qr(e){return e.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/,"")}function eo(e){try{let t=Se.readFileSync(e,"utf-8").match(/^---\r?\n([\s\S]*?)\r?\n---/);if(!t)return{};let n=Bt.load(t[1]);return n&&typeof n=="object"?n:{}}catch{return{}}}async function ue(e){let t={};try{t=JSON.parse(Se.readFileSync(Qe.join(e,"velu.json"),"utf-8"))}catch{return{name:Qe.basename(e),baseUrl:"",pages:[]}}let n=t.name??Qe.basename(e),r=typeof t.url=="string"?t.url.replace(/\/+$/,""):"",o=z(t.api),i=t.navigation??{},a={};try{let c=await he(t.navigation??{},{targetDir:e,api:o});i=c.nav,a=c.ops}catch(c){console.warn(`[velu] openapi: ${c.message}`)}let s=U(i),{pageEntries:l}=M(s,e),p=new Map(l.map(c=>[c.url,c])),u=[];for(let c of K(s)){if(!c.url)continue;let b=c.ancestors.filter(h=>h.kind==="group").pop(),d=c.ancestors.filter(h=>h.kind==="tab").pop(),$=b?.label||d?.label||"Pages",m=c.ancestors.filter(h=>h.kind==="tab"||h.kind==="group").map(h=>h.label),L=c.ancestors.filter(h=>h.kind==="language").pop()?.code||null;if(c.node?.api){let h=a[c.pagePath];if(!h)continue;let w=h.title||zt(c.url);u.push({url:c.url,title:w,description:h.description||"",group:$,breadcrumb:[...m,w],lang:L,frontmatter:{title:h.title,description:h.description},source:{kind:"api",segment:h.segment}})}else{let h=p.get(c.url);if(!h||!h.exists)continue;let w=eo(h.fileAbsPath),F=w.title||zt(c.url);u.push({url:c.url,title:F,description:w.description||"",group:$,breadcrumb:[...m,F],lang:L,frontmatter:w,source:{kind:"mdx",fileAbsPath:h.fileAbsPath}})}}return{name:n,baseUrl:r,pages:u}}function je(e){return new Map(e.pages.map(t=>[t.url,{...t.source,title:t.title}]))}async function to(e){return je(await ue(e))}async function nt(e,t,n){let o=(n||await to(e)).get(t);if(!o)return null;if(o.kind==="mdx")try{return{body:Se.readFileSync(o.fileAbsPath,"utf-8"),contentType:"text/markdown; charset=utf-8",kind:"mdx"}}catch{return null}return o.segment?{body:Gt(o.segment),contentType:"text/yaml; charset=utf-8",kind:"api"}:null}async function Vt(e,t){let n=t||await ue(e),r=s=>n.baseUrl?n.baseUrl+s:s,o=[`# ${n.name}`,"",`> Documentation index for ${n.name}. Append \`.md\` to any page URL (or send \`Accept: text/markdown\`) for its Markdown; fetch ${ke} for the whole site in one document.`,""],i=[],a=new Map;for(let s of n.pages)a.has(s.group)||(a.set(s.group,[]),i.push(s.group)),a.get(s.group).push(s);for(let s of i){o.push(`## ${s}`,"");for(let l of a.get(s))o.push(`- [${l.title}](${r(Wr(l.url))})${l.description?`: ${l.description}`:""}`);o.push("")}return o.join(`
110
+ `)}async function qt(e,t){let n=t||await ue(e),r=[`# ${n.name}`,"",`> Full documentation \u2014 every page concatenated. Index: ${W}`];for(let o of n.pages)if(r.push("","---","",`# ${o.title}`,`Source: ${o.url}`,""),o.source.kind==="mdx")try{r.push(Qr(Se.readFileSync(o.source.fileAbsPath,"utf-8")).trim())}catch{}else o.source.segment&&r.push("```yaml",Gt(o.source.segment).trim(),"```");return r.join(`
111
111
  `)+`
112
- `}var W,je,Wr,Z,Ut,Mt,qt=j(()=>{B();oe();Y();Be();W="/llms.txt",je="/llms-full.txt",Wr=`<${W}>; rel="llms-txt", <${je}>; rel="llms-full-txt"`,Z={Link:Wr,"X-Llms-Txt":W},Ut=`Full documentation index: ${W}`;Mt=e=>(e.split("/").filter(Boolean).pop()||"Home").replace(/[-_]+/g," ").replace(/\b\w/g,n=>n.toUpperCase())});var Zt={};Pe(Zt,{startDevServer:()=>vo});import Ht from"node:fs/promises";import Q from"node:fs";import to from"node:http";import{spawn as no}from"node:child_process";import P from"node:path";import{fileURLToPath as ro}from"node:url";import oo from"chokidar";import Dt from"express";import{createServer as io,searchForWorkspaceRoot as so}from"vite";function po(e){return`<link rel="stylesheet" href="${`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e).replace(/%20/g,"+")}:wght@300;400;500;600;700&display=swap`}" />`}function Xt(e,t){let n=Je(e,{color:!!process.stderr.isTTY});console.error(`
112
+ `}var W,ke,Zr,Z,Mt,zt,Ht=j(()=>{B();oe();Y();Ge();W="/llms.txt",ke="/llms-full.txt",Zr=`<${W}>; rel="llms-txt", <${ke}>; rel="llms-full-txt"`,Z={Link:Zr,"X-Llms-Txt":W},Mt=`Full documentation index: ${W}`;zt=e=>(e.split("/").filter(Boolean).pop()||"Home").replace(/[-_]+/g," ").replace(/\b\w/g,n=>n.toUpperCase())});var Qt={};Pe(Qt,{startDevServer:()=>bo});import Dt from"node:fs/promises";import Q from"node:fs";import no from"node:http";import{spawn as ro}from"node:child_process";import P from"node:path";import{fileURLToPath as oo}from"node:url";import io from"chokidar";import Xt from"express";import{createServer as so,searchForWorkspaceRoot as ao}from"vite";function fo(e){return`<link rel="stylesheet" href="${`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e).replace(/%20/g,"+")}:wght@300;400;500;600;700&display=swap`}" />`}function Yt(e,t){let n=Ve(e,{color:!!process.stderr.isTTY});console.error(`
113
113
  `+n+`
114
- `),process.env.VELU_DEBUG&&t&&console.error(t)}function fo(){try{return JSON.parse(Q.readFileSync(P.join(Oe,"package.json"),"utf8")).version||"unknown"}catch{return"unknown"}}function mo(e,t){let n=P.resolve(e,".velu"),r=P.resolve(n,".velu-version"),o=null;try{o=Q.readFileSync(r,"utf8").trim()}catch{}if(o!==t){if(o!==null)try{Q.rmSync(P.join(n,"vite-cache"),{recursive:!0,force:!0}),console.log("[velu] new version detected \u2014 refreshing the preview cache\u2026")}catch{}try{Q.mkdirSync(n,{recursive:!0}),Q.writeFileSync(r,t)}catch{}}}async function Yt(e){try{return await lt(e)}catch{return Ie({},P.basename(e))}}async function Kt(e,t){let n=await e.moduleGraph.getModuleByUrl(t,!0),r=new Map,o=new Set;async function i(a){if(!(!a||o.has(a.url))){if(o.add(a.url),a.id&&lo.test(a.id)){let s=a.url.includes("?")?"&":"?",l=await e.transformRequest(`${a.url}${s}direct`);l?.code&&r.set(a.url,l.code)}for(let s of a.importedModules)await i(s)}}return await i(n),[...r.values()].join(`
115
- `)}function yo(e,t){let n=()=>{process.stdout.isTTY&&!process.env.VELU_NO_BELL&&process.stdout.write("\x07")},r=process.stdout.isTTY,o=c=>r&&process.stdout.write(`\x1B]${c}\x1B\\`),i=()=>{o(`0;\u23F3 ${t}`),o("9;4;3;0")},a=()=>{o(`0;${t}`),o("9;4;0;0")};if(r&&process.once("exit",()=>o("9;4;0;0")),i(),!e)return console.log("Starting Velu\u2026"),{ready:c=>{console.log(`Velu ready \u2192 ${c}`),a(),n()}};let s="\x1B[38;2;220;20;60m",l="\x1B[0m";console.log("");for(let c of go)console.log(`${s}${c}${l}`);console.log("");let p=null;try{p=no(process.execPath,["-e",ho],{stdio:["ignore","inherit","ignore"]}),p.on("error",()=>{})}catch{}let u=()=>{if(p){try{p.kill()}catch{}p=null}};return process.once("exit",u),{ready:c=>{u(),process.stdout.write("\x1B[2K\r"),console.log(` \x1B[32m\u2713${l} Velu ready \u2192 \x1B[36m${c}${l}`),a(),n()}}}async function vo(e){let t=!!process.env.VELU_PROFILE,n=performance.now(),r=(y,f)=>t&&console.log(`[velu-profile] ${y}: ${(performance.now()-f).toFixed(0)}ms`),o=yo(!!process.stdout.isTTY&&!t,P.basename(e)),i=await Yt(e),a=s();function s(){let f=we(e).filter(g=>g.severity==="error"&&(g.category==="config-json"||g.category==="config-schema"));return f.length&&console.error(`
116
- `+xe(f,{color:!!process.stderr.isTTY})+`
117
- `),f}let l=e;try{l=Q.realpathSync(e)}catch{}let p=0,u=y=>{let f=performance.now();if(f-p<500)return;p=f;let g=ae(y,{projectDir:l,knownComponents:V});Xt(g,y)};process.on("unhandledRejection",u),process.on("uncaughtException",u);let c=Number(process.env.PORT)||8358,b=await Ke();mo(e,fo());let d=Dt(),$=to.createServer(d),m=await io({...Et({targetDir:e,VITE_ROOT:Oe,validateProps:b}),appType:"custom",logLevel:t?"info":"warn",server:{middlewareMode:!0,fs:{allow:[so(Oe),e,l]},hmr:{server:$}}});r("vite server created",n),d.use(m.middlewares),d.get(new RegExp(`^${Ee}(\\.[a-z0-9]+)?$`,"i"),async(y,f)=>{if(!i.favicon)return f.status(404).end();let g=P.resolve(e,i.favicon.replace(/^\//,""));f.sendFile(g,v=>{v&&f.status(404).end()})});let L=y=>(f,g)=>{let v=i.logo?.[y];if(!v)return g.status(404).end();g.sendFile(P.resolve(e,v.replace(/^\//,"")),O=>{O&&g.status(404).end()})};d.get(me,L("light")),d.get(de,L("dark")),d.post("/@velu-api-proxy",Dt.json({limit:"8mb"}),async(y,f)=>{let{method:g="GET",url:v,headers:O={},body:S}=y.body||{};if(typeof v!="string"||!/^https?:\/\//i.test(v))return f.status(400).json({error:"A valid http(s) target URL is required."});try{let k=await fetch(v,{method:g,headers:O,body:S!=null&&S!==""?S:void 0}),N=await k.text(),H=k.headers.get("content-type")||"",T={};k.headers.forEach((ee,Le)=>{T[Le]=ee});let R=N;if(/json/i.test(H))try{R=JSON.parse(N)}catch{}f.json({status:k.status,statusText:k.statusText,headers:T,body:R})}catch(k){f.json({error:`Request failed: ${k.message}`})}});let h=null,w=async()=>h||=await ue(e);d.get(/\.md$/i,async(y,f,g)=>{try{let v=await w(),O=await tt(e,Gt(decodeURIComponent(y.path)),Ae(v));if(!O)return g();f.status(200).set({"Content-Type":O.contentType,...Z}).end(et(O.body,O.kind))}catch{g()}}),d.get(W,async(y,f,g)=>{try{let v=await Jt(e,await w());f.status(200).set({"Content-Type":"text/plain; charset=utf-8",...Z}).end(v)}catch{g()}}),d.get(je,async(y,f,g)=>{try{let v=await Vt(e,await w());f.status(200).set({"Content-Type":"text/plain; charset=utf-8",...Z}).end(v)}catch{g()}}),d.use("*",async(y,f,g)=>{let v=y.originalUrl,O=performance.now();if(/text\/markdown/i.test(y.headers.accept||""))try{let S=await w(),k=await tt(e,ut(v),Ae(S));if(k)return f.status(200).set({"Content-Type":k.contentType,...Z}).end(et(k.body,k.kind))}catch{}if(a.length)return f.status(200).set({"Content-Type":"text/html"}).end(He(a,{title:"Fix velu.json to continue"}));try{let S=performance.now(),k=await Ht.readFile(Wt,"utf-8");k=await m.transformIndexHtml(v,k),r(`transformIndexHtml ${v}`,S);let N="/src/runtime/server-entry.jsx";S=performance.now();let{render:H}=await m.ssrLoadModule(N);r(`ssrLoadModule ${v} (1st req includes dep pre-bundle)`,S),S=performance.now();let T=await H(v);r(`render ${v}`,S),S=performance.now();let R=await Kt(m,N);r(`collectSsrCss ${v}`,S);let ee=R?`<style data-velu-ssr>${R}</style>`:"",Le=`<style data-velu-config>
118
- ${ct(i)}
119
- </style>`,on=co.has(i.font.family)?"":po(i.font.family),fe=st(i),sn=fe?`<link rel="icon"${fe.type?` type="${fe.type}"`:""} href="${fe.url}" />`:"",an=[ee,Le,on,sn].filter(Boolean).join(`
120
- `),ln=k.replace("<!--app-title-->",uo(i.name)).replace("<!--app-head-->",an).replace("<!--app-html-->",T);f.status(200).set({"Content-Type":"text/html",...Z}).end(ln),r(`TOTAL ${v}`,O)}catch(S){m.ssrFixStacktrace(S);let k=ae(S,{projectDir:l,knownComponents:V});Xt(k,S),f.status(200).set({"Content-Type":"text/html"}).end(He([k]))}}),oo.watch(e,{ignoreInitial:!0,ignored:/(^|[\\/])(node_modules|\.git|\.velu)([\\/]|$)/,awaitWriteFinish:{stabilityThreshold:100,pollInterval:20}}).on("all",async(y,f)=>{console.log(`[velu-cli] content ${y}: ${P.relative(e,f)}`);let g=P.basename(f)==="velu.json",v=f.endsWith(".mdx"),O=g||v&&(y==="add"||y==="unlink");if((O||v||/\.(ya?ml|json)$/i.test(f))&&(h=null),g&&(i=await Yt(e),a=s()),O)m.moduleGraph.invalidateAll();else if(v){let S=f.split(P.sep).join("/"),k=m.moduleGraph.getModulesByFile(S);if(k)for(let N of k)m.moduleGraph.invalidateModule(N)}m.ws.send({type:"full-reload"})});async function x(y){let f=new Set,g=12,v=0,O=[],S=()=>v<g?(v+=1,Promise.resolve()):new Promise(T=>O.push(T)).then(()=>{v+=1}),k=()=>{v-=1,O.shift()?.()},N=T=>/[\\/]\.velu[\\/]vite-cache[\\/]|[\\/]deps[\\/]/.test(T)||/[\\/]node_modules[\\/]/.test(T)&&!/velu-ui/.test(T);async function H(T){if(!(!T||f.has(T)||N(T))){f.add(T);try{await S();try{await m.transformRequest(T,{ssr:!1})}finally{k()}let R=await m.moduleGraph.getModuleByUrl(T,!1);R?.importedModules?.size&&await Promise.all([...R.importedModules].map(ee=>H(ee.url)))}catch{}}}return await H(y),f.size}$.listen(c,async()=>{let y=performance.now(),f=0;try{let{render:g}=await m.ssrLoadModule("/src/runtime/server-entry.jsx");await x("/src/runtime/client-entry.jsx"),typeof m.waitForRequestsIdle=="function"&&await m.waitForRequestsIdle();let[v]=await Promise.allSettled([x("/src/runtime/client-entry.jsx"),g("/"),m.transformIndexHtml("/",await Ht.readFile(Wt,"utf-8")),Kt(m,"/src/runtime/server-entry.jsx")]).then(O=>O.map(S=>S.status==="fulfilled"?S.value:0));f=v}catch(g){t&&console.log("[velu-profile] warmup error:",g?.message)}r(`cold-start warm-up (${f} client modules)`,y),o.ready(`http://localhost:${c}`)})}var ao,lo,co,uo,Oe,Wt,go,ho,Qt=j(()=>{Y();Ft();qe();It();J();De();Ye();We();qt();B();ao=P.dirname(ro(import.meta.url)),lo=/\.(css|less|sass|scss|styl|stylus|pcss|postcss)(\?|$)/,co=new Set(["Google Sans Flex","Google Sans Code","Outfit"]),uo=e=>String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");Oe=P.resolve(ao,".."),Wt=P.resolve(Oe,"src","template.html"),go=[" _ __ __","| | / /__ / /_ __","| | / / _ \\/ / / / /","| |/ / __/ / /_/ /","|___/\\___/_/\\__,_/"],ho="const F=['\u280B','\u2819','\u2839','\u2838','\u283C','\u2834','\u2826','\u2827','\u2807','\u280F'],M=['Starting Velu','Setting up your preview','Preparing your docs','Warming things up','Almost ready'];let f=0,m=0;const t=Date.now();const C='\\x1b[38;2;220;20;60m',R='\\x1b[0m',D='\\x1b[2m';const d=()=>{const s=(Date.now()-t)/1000|0;process.stdout.write('\\x1b[2K\\r '+C+F[f]+R+' '+M[m]+'\\u2026 '+D+s+'s'+R);f=(f+1)%F.length;};d();setInterval(d,90);setInterval(()=>{if(m<M.length-1)m++;},4000);"});var tn={};Pe(tn,{default:()=>wo,runValidate:()=>en});import bo from"node:fs";import xo from"node:path";function $o(e){try{let t=JSON.parse(bo.readFileSync(xo.join(e,"velu.json"),"utf-8"));if(!t.navigation||typeof t.navigation!="object")return[];let n=U(t.navigation);return M(n,e).pageEntries}catch{return[]}}async function en(e){let t=we(e),n=$o(e),r=await Rt(e,n),o=[...t,...r],i=!!process.stdout.isTTY;return console.log(xe(o,{color:i})),o.some(s=>s.severity!=="warning"&&s.severity!=="info")?1:0}var wo,nn=j(()=>{B();oe();Ye();We();J();wo=en});import Te from"node:path";import C from"node:process";import{readFileSync as So}from"node:fs";var[,,rn,pe]=C.argv;function ko(){try{return JSON.parse(So(new URL("../package.json",import.meta.url),"utf8")).version}catch{return"unknown"}}async function jo(){switch(rn){case"--version":case"-v":case"version":{console.log(ko());break}case"init":{pe||(console.error("Usage: velu init <project-name>"),C.exit(1));let e=pe,t=Te.resolve(C.cwd(),e),{initProject:n}=await Promise.resolve().then(()=>(ot(),rt));await n(t,e);break}case"dev":{let e=Te.resolve(C.cwd(),pe??"."),{startDevServer:t}=await Promise.resolve().then(()=>(Qt(),Zt));await t(e);break}case"validate":{let e=Te.resolve(C.cwd(),pe??"."),{runValidate:t}=await Promise.resolve().then(()=>(nn(),tn)),n=await t(e);C.exit(n);break}case"build":{let e=Te.resolve(C.cwd(),pe??"."),t=C.argv.indexOf("--out"),n=t>-1?C.argv[t+1]:void 0,r=new URL(["..","src","build","index.js"].join("/"),import.meta.url).href,o=a=>import(a),i;try{({runBuild:i}=await o(r))}catch{console.error("velu build is an internal command, not available in this distribution."),C.exit(1)}await i(e,{out:n});break}default:console.log("Usage:"),console.log(" velu init <project-name> scaffold a new docs project"),console.log(" velu dev [dir] start the dev preview server"),console.log(" velu validate [dir] check velu.json + content for problems"),C.exit(rn?1:0)}}jo().catch(e=>{console.error(C.env.VELU_DEBUG?e:`Error: ${e.message}`),C.exit(1)});
114
+ `),process.env.VELU_DEBUG&&t&&console.error(t)}function mo(){try{return JSON.parse(Q.readFileSync(P.join(Ae,"package.json"),"utf8")).version||"unknown"}catch{return"unknown"}}function go(e,t){let n=P.resolve(e,".velu"),r=P.resolve(n,".velu-version"),o=null;try{o=Q.readFileSync(r,"utf8").trim()}catch{}if(o!==t){if(o!==null)try{Q.rmSync(P.join(n,"vite-cache"),{recursive:!0,force:!0}),console.log("[velu] new version detected \u2014 refreshing the preview cache\u2026")}catch{}try{Q.mkdirSync(n,{recursive:!0}),Q.writeFileSync(r,t)}catch{}}}async function Kt(e){try{return await ct(e)}catch{return Re({},P.basename(e))}}async function Wt(e,t){let n=await e.moduleGraph.getModuleByUrl(t,!0),r=new Map,o=new Set;async function i(a){if(!(!a||o.has(a.url))){if(o.add(a.url),a.id&&co.test(a.id)){let s=a.url.includes("?")?"&":"?",l=await e.transformRequest(`${a.url}${s}direct`);l?.code&&r.set(a.url,l.code)}for(let s of a.importedModules)await i(s)}}return await i(n),[...r.values()].join(`
115
+ `)}function vo(e,t){let n=()=>{process.stdout.isTTY&&!process.env.VELU_NO_BELL&&process.stdout.write("\x07")},r=process.stdout.isTTY,o=c=>r&&process.stdout.write(`\x1B]${c}\x1B\\`),i=()=>{o(`0;\u23F3 ${t}`),o("9;4;3;0")},a=()=>{o(`0;${t}`),o("9;4;0;0")};if(r&&process.once("exit",()=>o("9;4;0;0")),i(),!e)return console.log("Starting Velu\u2026"),{ready:c=>{console.log(`Velu ready \u2192 ${c}`),a(),n()}};let s="\x1B[38;2;220;20;60m",l="\x1B[0m";console.log("");for(let c of ho)console.log(`${s}${c}${l}`);console.log("");let p=null;try{p=ro(process.execPath,["-e",yo],{stdio:["ignore","inherit","ignore"]}),p.on("error",()=>{})}catch{}let u=()=>{if(p){try{p.kill()}catch{}p=null}};return process.once("exit",u),{ready:c=>{u(),process.stdout.write("\x1B[2K\r"),console.log(` \x1B[32m\u2713${l} Velu ready \u2192 \x1B[36m${c}${l}`),a(),n()}}}async function bo(e){let t=!!process.env.VELU_PROFILE,n=performance.now(),r=(y,f)=>t&&console.log(`[velu-profile] ${y}: ${(performance.now()-f).toFixed(0)}ms`),o=vo(!!process.stdout.isTTY&&!t,P.basename(e)),i=await Kt(e),a=s();function s(){let f=$e(e).filter(g=>g.severity==="error"&&(g.category==="config-json"||g.category==="config-schema"));return f.length&&console.error(`
116
+ `+be(f,{color:!!process.stderr.isTTY})+`
117
+ `),f}let l=e;try{l=Q.realpathSync(e)}catch{}let p=0,u=y=>{let f=performance.now();if(f-p<500)return;p=f;let g=ae(y,{projectDir:l,knownComponents:V});Yt(g,y)};process.on("unhandledRejection",u),process.on("uncaughtException",u);let c=Number(process.env.PORT)||8358,b=await We();go(e,mo());let d=Xt(),$=no.createServer(d),m=await so({...Ft({targetDir:e,VITE_ROOT:Ae,validateProps:b}),appType:"custom",logLevel:t?"info":"warn",server:{middlewareMode:!0,fs:{allow:[ao(Ae),e,l]},hmr:{server:$}}});r("vite server created",n),d.use(m.middlewares),d.get(new RegExp(`^${Ee}(\\.[a-z0-9]+)?$`,"i"),async(y,f)=>{if(!i.favicon)return f.status(404).end();let g=P.resolve(e,i.favicon.replace(/^\//,""));f.sendFile(g,v=>{v&&f.status(404).end()})});let L=y=>(f,g)=>{let v=i.logo?.[y];if(!v)return g.status(404).end();g.sendFile(P.resolve(e,v.replace(/^\//,"")),O=>{O&&g.status(404).end()})};d.get(fe,L("light")),d.get(me,L("dark")),d.post("/@velu-api-proxy",Xt.json({limit:"8mb"}),async(y,f)=>{let{method:g="GET",url:v,headers:O={},body:S}=y.body||{};if(typeof v!="string"||!/^https?:\/\//i.test(v))return f.status(400).json({error:"A valid http(s) target URL is required."});try{let k=await fetch(v,{method:g,headers:O,body:S!=null&&S!==""?S:void 0}),N=await k.text(),H=k.headers.get("content-type")||"",T={};k.headers.forEach((ee,Le)=>{T[Le]=ee});let R=N;if(/json/i.test(H))try{R=JSON.parse(N)}catch{}f.json({status:k.status,statusText:k.statusText,headers:T,body:R})}catch(k){f.json({error:`Request failed: ${k.message}`})}});let h=null,w=async()=>h||=await ue(e);d.get(/\.md$/i,async(y,f,g)=>{try{let v=await w(),O=await nt(e,Jt(decodeURIComponent(y.path)),je(v));if(!O)return g();f.status(200).set({"Content-Type":O.contentType,...Z}).end(tt(O.body,O.kind))}catch{g()}}),d.get(W,async(y,f,g)=>{try{let v=await Vt(e,await w());f.status(200).set({"Content-Type":"text/plain; charset=utf-8",...Z}).end(v)}catch{g()}}),d.get(ke,async(y,f,g)=>{try{let v=await qt(e,await w());f.status(200).set({"Content-Type":"text/plain; charset=utf-8",...Z}).end(v)}catch{g()}}),d.use("*",async(y,f,g)=>{let v=y.originalUrl,O=performance.now();if(/text\/markdown/i.test(y.headers.accept||""))try{let S=await w(),k=await nt(e,pt(v),je(S));if(k)return f.status(200).set({"Content-Type":k.contentType,...Z}).end(tt(k.body,k.kind))}catch{}if(a.length)return f.status(200).set({"Content-Type":"text/html"}).end(De(a,{title:"Fix velu.json to continue"}));try{let S=performance.now(),k=await Dt.readFile(Zt,"utf-8");k=await m.transformIndexHtml(v,k),r(`transformIndexHtml ${v}`,S);let N="/src/runtime/server-entry.jsx";S=performance.now();let{render:H}=await m.ssrLoadModule(N);r(`ssrLoadModule ${v} (1st req includes dep pre-bundle)`,S),S=performance.now();let T=await H(v);r(`render ${v}`,S),S=performance.now();let R=await Wt(m,N);r(`collectSsrCss ${v}`,S);let ee=R?`<style data-velu-ssr>${R}</style>`:"",Le=`<style data-velu-config>
118
+ ${ut(i)}
119
+ </style>`,sn=uo.has(i.font.family)?"":fo(i.font.family),pe=at(i),an=pe?`<link rel="icon"${pe.type?` type="${pe.type}"`:""} href="${pe.url}" />`:"",ln=[ee,Le,sn,an].filter(Boolean).join(`
120
+ `),cn=k.replace("<!--app-title-->",po(i.name)).replace("<!--app-head-->",ln).replace("<!--app-html-->",T);f.status(200).set({"Content-Type":"text/html",...Z}).end(cn),r(`TOTAL ${v}`,O)}catch(S){m.ssrFixStacktrace(S);let k=ae(S,{projectDir:l,knownComponents:V});Yt(k,S),f.status(200).set({"Content-Type":"text/html"}).end(De([k]))}}),io.watch(e,{ignoreInitial:!0,ignored:/(^|[\\/])(node_modules|\.git|\.velu)([\\/]|$)/,awaitWriteFinish:{stabilityThreshold:100,pollInterval:20}}).on("all",async(y,f)=>{console.log(`[velu-cli] content ${y}: ${P.relative(e,f)}`);let g=P.basename(f)==="velu.json",v=f.endsWith(".mdx"),O=g||v&&(y==="add"||y==="unlink");if((O||v||/\.(ya?ml|json)$/i.test(f))&&(h=null),g&&(i=await Kt(e),a=s()),O)m.moduleGraph.invalidateAll();else if(v){let S=f.split(P.sep).join("/"),k=m.moduleGraph.getModulesByFile(S);if(k)for(let N of k)m.moduleGraph.invalidateModule(N)}m.ws.send({type:"full-reload"})});async function x(y){let f=new Set,g=12,v=0,O=[],S=()=>v<g?(v+=1,Promise.resolve()):new Promise(T=>O.push(T)).then(()=>{v+=1}),k=()=>{v-=1,O.shift()?.()},N=T=>/[\\/]\.velu[\\/]vite-cache[\\/]|[\\/]deps[\\/]/.test(T)||/[\\/]node_modules[\\/]/.test(T)&&!/velu-ui/.test(T);async function H(T){if(!(!T||f.has(T)||N(T))){f.add(T);try{await S();try{await m.transformRequest(T,{ssr:!1})}finally{k()}let R=await m.moduleGraph.getModuleByUrl(T,!1);R?.importedModules?.size&&await Promise.all([...R.importedModules].map(ee=>H(ee.url)))}catch{}}}return await H(y),f.size}$.listen(c,async()=>{let y=performance.now(),f=0;try{let{render:g}=await m.ssrLoadModule("/src/runtime/server-entry.jsx");await x("/src/runtime/client-entry.jsx"),typeof m.waitForRequestsIdle=="function"&&await m.waitForRequestsIdle();let[v]=await Promise.allSettled([x("/src/runtime/client-entry.jsx"),g("/"),m.transformIndexHtml("/",await Dt.readFile(Zt,"utf-8")),Wt(m,"/src/runtime/server-entry.jsx")]).then(O=>O.map(S=>S.status==="fulfilled"?S.value:0));f=v}catch(g){t&&console.log("[velu-profile] warmup error:",g?.message)}r(`cold-start warm-up (${f} client modules)`,y),o.ready(`http://localhost:${c}`)})}var lo,co,uo,po,Ae,Zt,ho,yo,en=j(()=>{Y();Nt();He();Rt();J();Xe();Ke();Ze();Ht();B();lo=P.dirname(oo(import.meta.url)),co=/\.(css|less|sass|scss|styl|stylus|pcss|postcss)(\?|$)/,uo=new Set(["Google Sans Flex","Google Sans Code","Outfit"]),po=e=>String(e).replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");Ae=P.resolve(lo,".."),Zt=P.resolve(Ae,"src","template.html"),ho=[" _ __ __","| | / /__ / /_ __","| | / / _ \\/ / / / /","| |/ / __/ / /_/ /","|___/\\___/_/\\__,_/"],yo="const F=['\u280B','\u2819','\u2839','\u2838','\u283C','\u2834','\u2826','\u2827','\u2807','\u280F'],M=['Starting Velu','Setting up your preview','Preparing your docs','Warming things up','Almost ready'];let f=0,m=0;const t=Date.now();const C='\\x1b[38;2;220;20;60m',R='\\x1b[0m',D='\\x1b[2m';const d=()=>{const s=(Date.now()-t)/1000|0;process.stdout.write('\\x1b[2K\\r '+C+F[f]+R+' '+M[m]+'\\u2026 '+D+s+'s'+R);f=(f+1)%F.length;};d();setInterval(d,90);setInterval(()=>{if(m<M.length-1)m++;},4000);"});var nn={};Pe(nn,{default:()=>So,runValidate:()=>tn});import xo from"node:fs";import $o from"node:path";function wo(e){try{let t=JSON.parse(xo.readFileSync($o.join(e,"velu.json"),"utf-8"));if(!t.navigation||typeof t.navigation!="object")return[];let n=U(t.navigation);return M(n,e).pageEntries}catch{return[]}}async function tn(e){let t=$e(e),n=wo(e),r=await Ut(e,n),o=[...t,...r],i=!!process.stdout.isTTY;return console.log(be(o,{color:i})),o.some(s=>s.severity!=="warning"&&s.severity!=="info")?1:0}var So,rn=j(()=>{B();oe();Ke();Ze();J();So=tn});import Oe from"node:path";import _ from"node:process";import{readFileSync as ko}from"node:fs";var[,,on,Te]=_.argv;function jo(){try{return JSON.parse(ko(new URL("../package.json",import.meta.url),"utf8")).version}catch{return"unknown"}}function Ao(){let e=_.argv.slice(3);for(let t=0;t<e.length;t++){let n=e[t];if(n==="--out"){t++;continue}if(!n.startsWith("-"))return n}}async function Oo(){switch(on){case"--version":case"-v":case"version":{console.log(jo());break}case"init":{Te||(console.error("Usage: velu init <project-name>"),_.exit(1));let e=Te,t=Oe.resolve(_.cwd(),e),{initProject:n}=await Promise.resolve().then(()=>(it(),ot));await n(t,e);break}case"dev":{let e=Oe.resolve(_.cwd(),Te??"."),{startDevServer:t}=await Promise.resolve().then(()=>(en(),Qt));await t(e);break}case"validate":{let e=Oe.resolve(_.cwd(),Te??"."),{runValidate:t}=await Promise.resolve().then(()=>(rn(),nn)),n=await t(e);_.exit(n);break}case"build":{let e=Oe.resolve(_.cwd(),Ao()??"."),t=_.argv.indexOf("--out"),n=t>-1?_.argv[t+1]:void 0,r=new URL(["..","src","build","index.js"].join("/"),import.meta.url).href,o=a=>import(a),i;try{({runBuild:i}=await o(r))}catch{console.error("velu build is an internal command, not available in this distribution."),_.exit(1)}await i(e,{out:n});break}default:console.log("Usage:"),console.log(" velu init <project-name> scaffold a new docs project"),console.log(" velu dev [dir] start the dev preview server"),console.log(" velu validate [dir] check velu.json + content for problems"),_.exit(on?1:0)}}Oo().catch(e=>{console.error(_.env.VELU_DEBUG?e:`Error: ${e.message}`),_.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@veluai/velu",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "type": "module",
5
5
  "bin": "./dist/cli.js",
6
6
  "publishConfig": {
@@ -13,15 +13,24 @@ import Cluster from '../primitives/Cluster.jsx';
13
13
  * open={chatOpen}
14
14
  * seedQuestion={question} // first message — sent on open
15
15
  * onClose={() => setChatOpen(false)}
16
+ * ask={askDocs} // OPTIONAL — real backend (see below)
17
+ * onFeedback={(id, v) => …} // OPTIONAL — 👍/👎 for a message
16
18
  * />
17
19
  *
18
20
  * Slide: the panel is fixed to the inline-end edge; `open` toggles a
19
21
  * `translateX` between fully off-screen and 0. Width is the
20
22
  * `--vchat-width` variable (default 24rem ≈ the design's 384px).
21
23
  *
22
- * The AI reply is a canned, fake-streamed answer (token-by-token) with
23
- * inline citation chips, a Sources list, and follow-up suggestions
24
- * a dummy stand-in until a real RAG backend is wired up.
24
+ * Backend seam (mirrors Search.jsx's injectable `search` prop):
25
+ * ask(prompt, { conversationId, signal }) AsyncIterable<AskEvent>
26
+ * AskEvent = {
27
+ * delta?: string, // text chunk to append (streamed)
28
+ * citations?: Source[], // [{ num, title, path, url }] — replaces sources
29
+ * messageId?: string, // assistant message id (for feedback)
30
+ * conversationId?: string, // threaded across turns
31
+ * }
32
+ * When `ask` is omitted the panel falls back to a canned, fake-streamed
33
+ * demo answer (so dev preview / offline still shows the experience).
25
34
  */
26
35
 
27
36
  /* ── Brand mark — the Velu double-hook logo ─────────────────────────── */
@@ -111,6 +120,34 @@ function buildAnswer() {
111
120
  };
112
121
  }
113
122
 
123
+ /* Real-backend path: turn the accumulated answer TEXT into the same token
124
+ shape `renderStream` consumes. The assistant streams plain text with inline
125
+ `code` spans and bracketed citation markers ([1], [2]); split those out so
126
+ they render as <code> and citation chips, exactly like the canned path. */
127
+ function textToTokens(text) {
128
+ const tokens = [];
129
+ const re = /(`[^`]*`|\[\d+\])/g;
130
+ let last = 0;
131
+ let m;
132
+ while ((m = re.exec(text)) !== null) {
133
+ if (m.index > last) tokens.push({ kind: 't', v: text.slice(last, m.index) });
134
+ const tok = m[0];
135
+ if (tok[0] === '`') tokens.push({ kind: 'code', v: tok.slice(1, -1) });
136
+ else tokens.push({ kind: 'cite', n: Number(tok.slice(1, -1)) });
137
+ last = re.lastIndex;
138
+ }
139
+ if (last < text.length) tokens.push({ kind: 't', v: text.slice(last) });
140
+ return tokens;
141
+ }
142
+
143
+ /* Plain-text of an answer (for the Copy action). */
144
+ function tokensToPlain(tokens) {
145
+ return tokens
146
+ .map((tk) => (tk.kind === 'cite' ? `[${tk.n}]` : tk.v))
147
+ .join('')
148
+ .trim();
149
+ }
150
+
114
151
  /* Flatten an answer into a stream of small tokens for incremental render. */
115
152
  function tokenizeAnswer(answer) {
116
153
  const tokens = [];
@@ -286,8 +323,37 @@ function UserMsg({ text }) {
286
323
  );
287
324
  }
288
325
 
289
- function AiMsg({ tokens, sources, followups, streaming, onFollowup }) {
326
+ function AiMsg({
327
+ tokens,
328
+ sources,
329
+ followups,
330
+ streaming,
331
+ onFollowup,
332
+ messageId,
333
+ onFeedback,
334
+ }) {
290
335
  const thinking = tokens.length === 0;
336
+ const [vote, setVote] = useState(null); // 'up' | 'down' | null
337
+ const [copied, setCopied] = useState(false);
338
+
339
+ const onAction = (ic) => {
340
+ if (ic === 'copy') {
341
+ try {
342
+ navigator.clipboard?.writeText(tokensToPlain(tokens));
343
+ setCopied(true);
344
+ setTimeout(() => setCopied(false), 1400);
345
+ } catch {
346
+ /* clipboard blocked — no-op */
347
+ }
348
+ return;
349
+ }
350
+ if (ic === 'thumbs-up' || ic === 'thumbs-down') {
351
+ const v = ic === 'thumbs-up' ? 'up' : 'down';
352
+ const next = vote === v ? null : v; // toggle off if re-clicked
353
+ setVote(next);
354
+ onFeedback?.(messageId, next); // null = retract
355
+ }
356
+ };
291
357
  return (
292
358
  <div className="velu-chatbot__msg velu-chatbot__msg--ai">
293
359
  <Cluster
@@ -345,16 +411,24 @@ function AiMsg({ tokens, sources, followups, streaming, onFollowup }) {
345
411
 
346
412
  {!streaming && !thinking && (
347
413
  <Cluster space="0" className="velu-chatbot__msg-actions">
348
- {['copy', 'refresh-cw', 'thumbs-up', 'thumbs-down'].map((ic) => (
349
- <button
350
- key={ic}
351
- type="button"
352
- className="velu-chatbot__msg-action"
353
- aria-label={ic}
354
- >
355
- {resolveIcon(ic, { size: '1em' })}
356
- </button>
357
- ))}
414
+ {['copy', 'thumbs-up', 'thumbs-down'].map((ic) => {
415
+ const active =
416
+ (ic === 'thumbs-up' && vote === 'up') ||
417
+ (ic === 'thumbs-down' && vote === 'down');
418
+ const label = ic === 'copy' && copied ? 'check' : ic;
419
+ return (
420
+ <button
421
+ key={ic}
422
+ type="button"
423
+ className={`velu-chatbot__msg-action${active ? ' is-active' : ''}`}
424
+ aria-label={ic}
425
+ aria-pressed={ic === 'copy' ? undefined : active}
426
+ onClick={() => onAction(ic)}
427
+ >
428
+ {resolveIcon(label, { size: '1em' })}
429
+ </button>
430
+ );
431
+ })}
358
432
  </Cluster>
359
433
  )}
360
434
  </div>
@@ -413,6 +487,8 @@ export default function Chatbot({
413
487
  open = false,
414
488
  seedQuestion,
415
489
  onClose,
490
+ ask,
491
+ onFeedback,
416
492
  className = '',
417
493
  ...rest
418
494
  }) {
@@ -422,48 +498,133 @@ export default function Chatbot({
422
498
  const bodyRef = useRef(null);
423
499
  const streamingRef = useRef(false);
424
500
  const lastSeedRef = useRef(undefined);
501
+ // Real-backend session: conversation id threads turns; the controller lets
502
+ // a new-chat / close / unmount abort an in-flight stream.
503
+ const convoRef = useRef(undefined);
504
+ const abortRef = useRef(null);
425
505
 
426
506
  useEffect(() => {
427
507
  const el = bodyRef.current;
428
508
  if (el) el.scrollTop = el.scrollHeight;
429
509
  }, [messages]);
430
510
 
431
- const send = useCallback((text) => {
432
- const prompt = String(text ?? '').trim();
433
- if (!prompt || streamingRef.current) return;
434
- setInput('');
435
- const answer = buildAnswer();
436
- const fullTokens = tokenizeAnswer(answer);
437
- setMessages((prev) => [
438
- ...prev,
439
- { role: 'user', text: prompt },
440
- { role: 'ai', answer, tokens: [], streaming: true },
441
- ]);
442
- streamingRef.current = true;
443
-
444
- let i = 0;
445
- const startDelay = 1400; // "thinking" pause
446
- const stepDelay = 28; // per token
447
- let timer = setTimeout(function step() {
448
- i = Math.min(fullTokens.length, i + 1);
449
- setMessages((prev) => {
450
- const out = prev.slice();
451
- const last = out[out.length - 1];
452
- out[out.length - 1] = {
453
- ...last,
454
- tokens: fullTokens.slice(0, i),
455
- streaming: i < fullTokens.length,
511
+ // Merge a patch into the last (assistant) message.
512
+ const patchLast = useCallback((patch) => {
513
+ setMessages((prev) => {
514
+ if (!prev.length) return prev;
515
+ const out = prev.slice();
516
+ out[out.length - 1] = { ...out[out.length - 1], ...patch };
517
+ return out;
518
+ });
519
+ }, []);
520
+
521
+ // Stop whatever is in flight — a canned setTimeout chain ({ timer }) or a
522
+ // real fetch stream (an AbortController). Safe to call any time.
523
+ const cancelInFlight = useCallback(() => {
524
+ const a = abortRef.current;
525
+ if (a) {
526
+ if (a.timer) clearTimeout(a.timer);
527
+ if (typeof a.abort === 'function') a.abort();
528
+ }
529
+ abortRef.current = null;
530
+ streamingRef.current = false;
531
+ }, []);
532
+
533
+ const send = useCallback(
534
+ async (text) => {
535
+ const prompt = String(text ?? '').trim();
536
+ if (!prompt || streamingRef.current) return;
537
+ setInput('');
538
+
539
+ // ── No backend wired → canned, fake-streamed demo answer ──────────
540
+ if (!ask) {
541
+ const answer = buildAnswer();
542
+ const fullTokens = tokenizeAnswer(answer);
543
+ setMessages((prev) => [
544
+ ...prev,
545
+ { role: 'user', text: prompt },
546
+ {
547
+ role: 'ai',
548
+ tokens: [],
549
+ sources: answer.sources,
550
+ followups: answer.followups,
551
+ streaming: true,
552
+ },
553
+ ]);
554
+ streamingRef.current = true;
555
+ let i = 0;
556
+ const step = () => {
557
+ i = Math.min(fullTokens.length, i + 1);
558
+ patchLast({
559
+ tokens: fullTokens.slice(0, i),
560
+ streaming: i < fullTokens.length,
561
+ });
562
+ if (i < fullTokens.length) {
563
+ abortRef.current = { timer: setTimeout(step, 28) };
564
+ } else {
565
+ streamingRef.current = false;
566
+ abortRef.current = null;
567
+ }
456
568
  };
457
- return out;
458
- });
459
- if (i < fullTokens.length) {
460
- timer = setTimeout(step, stepDelay);
461
- } else {
569
+ abortRef.current = { timer: setTimeout(step, 1400) }; // "thinking" pause
570
+ return;
571
+ }
572
+
573
+ // ── Real backend → stream deltas + citations from `ask` ───────────
574
+ setMessages((prev) => [
575
+ ...prev,
576
+ { role: 'user', text: prompt },
577
+ { role: 'ai', tokens: [], sources: [], followups: [], streaming: true },
578
+ ]);
579
+ streamingRef.current = true;
580
+ const controller =
581
+ typeof AbortController !== 'undefined' ? new AbortController() : null;
582
+ abortRef.current = controller;
583
+
584
+ let acc = '';
585
+ let sources = [];
586
+ let messageId;
587
+ try {
588
+ for await (const ev of ask(prompt, {
589
+ conversationId: convoRef.current,
590
+ signal: controller?.signal,
591
+ })) {
592
+ if (ev.conversationId) convoRef.current = ev.conversationId;
593
+ if (ev.messageId) messageId = ev.messageId;
594
+ if (ev.delta) acc += ev.delta;
595
+ if (ev.citations) {
596
+ sources = ev.citations.map((c, idx) => ({
597
+ num: c.num ?? idx + 1,
598
+ title: c.title,
599
+ path: c.path ?? c.route_path,
600
+ url: c.url,
601
+ }));
602
+ }
603
+ patchLast({ tokens: textToTokens(acc), sources, streaming: true, messageId });
604
+ }
605
+ patchLast({ tokens: textToTokens(acc), sources, streaming: false, messageId });
606
+ } catch (err) {
607
+ if (controller?.signal?.aborted) {
608
+ patchLast({ streaming: false });
609
+ } else {
610
+ patchLast({
611
+ tokens: textToTokens(
612
+ acc || 'Sorry — I couldn’t reach the assistant. Please try again.'
613
+ ),
614
+ streaming: false,
615
+ error: true,
616
+ });
617
+ }
618
+ } finally {
462
619
  streamingRef.current = false;
620
+ abortRef.current = null;
463
621
  }
464
- }, startDelay);
465
- return () => clearTimeout(timer);
466
- }, []);
622
+ },
623
+ [ask, patchLast]
624
+ );
625
+
626
+ // Abort any in-flight stream when the panel unmounts.
627
+ useEffect(() => () => cancelInFlight(), [cancelInFlight]);
467
628
 
468
629
  // A new seedQuestion (from the page's AskBar) sends the first message.
469
630
  useEffect(() => {
@@ -474,7 +635,8 @@ export default function Chatbot({
474
635
  }, [open, seedQuestion, send]);
475
636
 
476
637
  const newChat = () => {
477
- if (streamingRef.current) return;
638
+ cancelInFlight();
639
+ convoRef.current = undefined; // fresh conversation thread
478
640
  setMessages([]);
479
641
  setInput('');
480
642
  setHistoryOpen(false);
@@ -574,9 +736,11 @@ export default function Chatbot({
574
736
  <AiMsg
575
737
  key={i}
576
738
  tokens={m.tokens}
577
- sources={m.answer?.sources}
578
- followups={m.answer?.followups}
739
+ sources={m.sources}
740
+ followups={m.followups}
579
741
  streaming={m.streaming}
742
+ messageId={m.messageId}
743
+ onFeedback={onFeedback}
580
744
  onFollowup={(f) => send(f)}
581
745
  />
582
746
  ),
@@ -141,7 +141,12 @@
141
141
  padding: 0;
142
142
  border: var(--border-width) solid var(--border-color);
143
143
  border-radius: 999px;
144
- background: var(--page-bg);
144
+ /* Frosted glass — same recipe as the scrolled header / toc-bar: 75%
145
+ --page-bg + a saturate/blur backdrop, so the nav content shows through
146
+ faintly behind the button. */
147
+ background: color-mix(in srgb, var(--page-bg) 75%, transparent);
148
+ backdrop-filter: saturate(140%) blur(12px);
149
+ -webkit-backdrop-filter: saturate(140%) blur(12px);
145
150
  color: var(--muted-color);
146
151
  cursor: pointer;
147
152
  z-index: 3;
@@ -161,19 +166,21 @@
161
166
  block-size: 1.1em;
162
167
  }
163
168
  .velu-docs-nav-arrow--up {
164
- inset-block-start: var(--s-3);
169
+ /* Float ABOVE the scroll region — up in the context-divider gap — instead
170
+ of over the first section heading. The lift is the arrow's own height
171
+ (2rem, matching block-size) plus a small gap, so its bottom clears the
172
+ scroll content and it never overlaps nav text. */
173
+ inset-block-start: calc(-2rem - var(--s-4));
165
174
  }
166
175
  .velu-docs-nav-arrow--down {
167
176
  inset-block-end: var(--s-3);
168
177
  }
169
- /* Reveal only while hovering the sidebar AND there's content beyond
170
- that edge. */
171
- .velu-docs-layout__aside--left:hover
172
- .velu-docs-nav-scroll[data-fade-top='true']
173
- ~ .velu-docs-nav-arrow--up,
174
- .velu-docs-layout__aside--left:hover
175
- .velu-docs-nav-scroll[data-fade-bottom='true']
176
- ~ .velu-docs-nav-arrow--down {
178
+ /* Reveal whenever there's content beyond that edge always on (not just on
179
+ hover), so the scroll affordance is visible as long as there's more to
180
+ scroll. The data-fade-* attrs (set by the runtime from scroll position)
181
+ already gate each arrow to the direction that actually has overflow. */
182
+ .velu-docs-nav-scroll[data-fade-top='true'] ~ .velu-docs-nav-arrow--up,
183
+ .velu-docs-nav-scroll[data-fade-bottom='true'] ~ .velu-docs-nav-arrow--down {
177
184
  opacity: 1;
178
185
  pointer-events: auto;
179
186
  transform: translateX(-50%) scale(1);
@@ -43,6 +43,7 @@ export {
43
43
  } from './components/PageHeader.jsx';
44
44
  export { default as Search } from './components/Search.jsx';
45
45
  export { default as pagefindSearch } from './lib/pagefind.js';
46
+ export { createDocsAssistant } from './lib/docs-assistant.js';
46
47
  export { default as Image } from './components/Image.jsx';
47
48
  export {
48
49
  default as CodeBlock,
@@ -0,0 +1,163 @@
1
+ /**
2
+ * docs-assistant — runtime client for the published docs site's "Ask AI",
3
+ * talking to the backend's PUBLIC docs-AI-assistant API:
4
+ *
5
+ * GET /api/v1/public/ai-assistant/bootstrap (visitor cookie + tenant)
6
+ * POST /api/v1/public/ai-assistant/messages ({ message, conversation_id })
7
+ * GET /api/v1/public/ai-assistant/conversations/{id}/events (SSE; ?token=…)
8
+ * POST|DELETE /api/v1/public/ai-assistant/messages/{id}/feedback ({ rating })
9
+ *
10
+ * `createDocsAssistant({ apiBase, host })` returns `{ ask, sendFeedback }`,
11
+ * shaped to drop straight into <Chatbot ask onFeedback>. `ask` is an async
12
+ * generator yielding the AskEvent shape Chatbot expects.
13
+ *
14
+ * Contract notes (from the backend):
15
+ * - bootstrap sets an **httponly visitor cookie**, so every call uses
16
+ * `credentials: 'include'`. Cross-origin therefore needs CORS w/ credentials
17
+ * AND a cross-site-capable cookie (SameSite=None) — today the cookie is
18
+ * SameSite=Lax, so the API must be same-site with the docs (proxied under the
19
+ * docs domain) until the backend relaxes it. See the plan's open questions.
20
+ * - tenant is resolved from the `X-Velu-Site-Host` header (falls back to Origin).
21
+ * - POST /messages returns immediately; the answer is generated in the
22
+ * background and arrives as a SINGLE `assistant.completed` SSE event with the
23
+ * full content + citations (NOT token-by-token). So `ask` yields one content
24
+ * event when the answer is ready (the panel shows its "thinking" state until).
25
+ */
26
+
27
+ const trimSlash = (s) => String(s || '').replace(/\/+$/, '');
28
+
29
+ function siteHost(explicit) {
30
+ if (explicit) return explicit;
31
+ return typeof window !== 'undefined' ? window.location.host : '';
32
+ }
33
+
34
+ // Parse one raw SSE record ("event: x\ndata: {…}") into { event, data }.
35
+ function parseSseRecord(raw) {
36
+ let event = 'message';
37
+ const dataLines = [];
38
+ for (const line of raw.split('\n')) {
39
+ if (line.startsWith('event:')) event = line.slice(6).trim();
40
+ else if (line.startsWith('data:')) dataLines.push(line.slice(5).replace(/^ /, ''));
41
+ }
42
+ if (!dataLines.length) return { event, data: null };
43
+ try {
44
+ return { event, data: JSON.parse(dataLines.join('\n')) };
45
+ } catch {
46
+ return { event, data: null };
47
+ }
48
+ }
49
+
50
+ // Backend citation → the Chatbot's Source shape.
51
+ function mapCitations(cits) {
52
+ if (!Array.isArray(cits)) return undefined;
53
+ return cits.map((c, i) => ({
54
+ num: c.num ?? c.index ?? i + 1,
55
+ title: c.title,
56
+ path: c.route_path ?? c.path,
57
+ url: c.url,
58
+ }));
59
+ }
60
+
61
+ export function createDocsAssistant({ apiBase, host } = {}) {
62
+ const base = trimSlash(apiBase);
63
+ if (!base) return null;
64
+ const root = `${base}/api/v1/public/ai-assistant`;
65
+ let bootstrapped = false;
66
+
67
+ const headers = (extra) => ({
68
+ 'X-Velu-Site-Host': siteHost(host),
69
+ ...extra,
70
+ });
71
+
72
+ async function bootstrap() {
73
+ if (bootstrapped) return;
74
+ // Sets the httponly visitor cookie used by every subsequent call.
75
+ await fetch(`${root}/bootstrap`, {
76
+ method: 'GET',
77
+ credentials: 'include',
78
+ headers: headers(),
79
+ });
80
+ bootstrapped = true;
81
+ }
82
+
83
+ // Async generator: yields { conversationId } early, then one
84
+ // { delta, citations, messageId, conversationId } when the answer is ready.
85
+ async function* ask(prompt, { conversationId, signal } = {}) {
86
+ await bootstrap();
87
+
88
+ const res = await fetch(`${root}/messages`, {
89
+ method: 'POST',
90
+ credentials: 'include',
91
+ headers: headers({ 'Content-Type': 'application/json' }),
92
+ body: JSON.stringify({ message: prompt, conversation_id: conversationId ?? null }),
93
+ signal,
94
+ });
95
+ if (!res.ok) throw new Error(`ask-ai: messages ${res.status}`);
96
+ const { conversation_id: convId, conversation_token: token } = await res.json();
97
+ yield { conversationId: convId };
98
+
99
+ // Manual fetch-stream SSE parse (not EventSource): supports credentials,
100
+ // the X-Velu-Site-Host header, and AbortController cancellation.
101
+ const evRes = await fetch(
102
+ `${root}/conversations/${convId}/events?after_seq=0&token=${encodeURIComponent(token)}`,
103
+ { credentials: 'include', headers: headers({ Accept: 'text/event-stream' }), signal },
104
+ );
105
+ if (!evRes.ok || !evRes.body) throw new Error(`ask-ai: stream ${evRes.status}`);
106
+
107
+ const reader = evRes.body.getReader();
108
+ const decoder = new TextDecoder();
109
+ let buf = '';
110
+ try {
111
+ while (true) {
112
+ const { value, done } = await reader.read();
113
+ if (done) break;
114
+ buf += decoder.decode(value, { stream: true });
115
+ let sep;
116
+ while ((sep = buf.indexOf('\n\n')) !== -1) {
117
+ const { event, data } = parseSseRecord(buf.slice(0, sep));
118
+ buf = buf.slice(sep + 2);
119
+ if (event === 'assistant.completed') {
120
+ const m = data?.message || {};
121
+ yield {
122
+ delta: m.content || '',
123
+ citations: mapCitations(m.citations),
124
+ messageId: m.id,
125
+ conversationId: convId,
126
+ };
127
+ return; // answer delivered — done
128
+ }
129
+ if (event === 'assistant.error') {
130
+ throw new Error(data?.error || 'ask-ai: generation failed');
131
+ }
132
+ // message.created (echoed user turn) and ping are ignored.
133
+ }
134
+ }
135
+ } finally {
136
+ try {
137
+ await reader.cancel();
138
+ } catch {
139
+ /* already closed */
140
+ }
141
+ }
142
+ }
143
+
144
+ // rating: 'up' | 'down' to set, null to retract.
145
+ async function sendFeedback(messageId, rating) {
146
+ if (messageId == null) return;
147
+ const url = `${root}/messages/${messageId}/feedback`;
148
+ if (rating == null) {
149
+ await fetch(url, { method: 'DELETE', credentials: 'include', headers: headers() });
150
+ return;
151
+ }
152
+ await fetch(url, {
153
+ method: 'POST',
154
+ credentials: 'include',
155
+ headers: headers({ 'Content-Type': 'application/json' }),
156
+ body: JSON.stringify({ rating }),
157
+ });
158
+ }
159
+
160
+ return { ask, sendFeedback };
161
+ }
162
+
163
+ export default createDocsAssistant;
@@ -242,6 +242,22 @@
242
242
  "description": "Where the menu renders. Default \"header\"."
243
243
  }
244
244
  }
245
+ },
246
+ "assistant": {
247
+ "type": "object",
248
+ "additionalProperties": false,
249
+ "description": "Docs-site \"Ask AI\" backend. When apiBase is set, the published build wires the chatbot to the public docs-AI-assistant API; absent → the chatbot shows a canned demo answer (also in the dev preview).",
250
+ "required": ["apiBase"],
251
+ "properties": {
252
+ "apiBase": {
253
+ "type": "string",
254
+ "description": "Base URL of the Velu backend that serves /api/v1/public/ai-assistant/* (e.g. \"https://api.getvelu.com\"). Must be same-site with the docs (or send a SameSite=None visitor cookie) for the credentialed requests to work."
255
+ },
256
+ "host": {
257
+ "type": "string",
258
+ "description": "Override the tenant-resolution host sent as X-Velu-Site-Host. Defaults to the page's own host at runtime."
259
+ }
260
+ }
245
261
  }
246
262
  },
247
263
  "$defs": {
@@ -40,6 +40,7 @@ import {
40
40
  resolveIcon,
41
41
  Search,
42
42
  pagefindSearch,
43
+ createDocsAssistant,
43
44
  Logo,
44
45
  SocialLinks,
45
46
  Tree,
@@ -744,6 +745,17 @@ function DocsPage() {
744
745
  });
745
746
  }, []);
746
747
 
748
+ // Ask-AI backend: wire the chatbot to the public docs-AI-assistant API only
749
+ // in a real build AND when an apiBase is configured (velu.json → assistant).
750
+ // Otherwise `ask` stays undefined and the Chatbot uses its canned demo answer
751
+ // (dev preview, or a site that hasn't enabled the assistant).
752
+ const assistant = React.useMemo(() => {
753
+ if (IS_DEV_PREVIEW) return null;
754
+ const apiBase = site.assistant?.apiBase;
755
+ if (!apiBase) return null;
756
+ return createDocsAssistant({ apiBase, host: site.assistant?.host });
757
+ }, []);
758
+
747
759
  const frontmatter = entry?.frontmatter ?? {};
748
760
  const PageComponent = entry?.Component ?? null;
749
761
  const pageToc = entry?.toc ?? [];
@@ -1609,6 +1621,8 @@ function DocsPage() {
1609
1621
  open={chatOpen}
1610
1622
  seedQuestion={chatQuestion}
1611
1623
  onClose={() => setChatOpen(false)}
1624
+ ask={assistant?.ask}
1625
+ onFeedback={assistant?.sendFeedback}
1612
1626
  />
1613
1627
  </div>
1614
1628
  );