velloo 0.7.0 → 0.8.0
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/README.md +8 -1
- package/canvas/assets/index-CcPwhD7W.js +31 -0
- package/canvas/assets/index-CkVteRZ9.css +2 -0
- package/canvas/assets/lucide-all-Cezxn40A.js +1 -0
- package/canvas/index.html +2 -2
- package/{chunk-4y2xy1kf.js → chunk-07fxzrx2.js} +1 -1
- package/{chunk-acsv6m3n.js → chunk-32cq4wpr.js} +1 -1
- package/{chunk-gfppsgvv.js → chunk-3612470d.js} +1 -1
- package/{chunk-mdgwdqnq.js → chunk-45wv1fs5.js} +8 -8
- package/chunk-4g4c9h7k.js +2 -0
- package/{chunk-64pex3mw.js → chunk-6w42sr61.js} +1 -1
- package/{chunk-0pxm5v0b.js → chunk-8n07n0cr.js} +2 -2
- package/{chunk-ejppcfa5.js → chunk-8qf0ne1p.js} +1 -1
- package/{chunk-0e5j6nqs.js → chunk-8ztgcajz.js} +1 -1
- package/{chunk-brnkprt5.js → chunk-9g45c5md.js} +142 -50
- package/{chunk-pjkkp7xa.js → chunk-aefn23tr.js} +1 -1
- package/{chunk-82x2jkfq.js → chunk-asqpx5v7.js} +1 -1
- package/{chunk-dvh0b2r4.js → chunk-b4hny6hw.js} +1 -1
- package/chunk-bntsn3wj.js +2 -0
- package/{chunk-gbq5wv7x.js → chunk-c4164x55.js} +1 -1
- package/{chunk-b8vcbbrg.js → chunk-cg0sjdqt.js} +1 -1
- package/{chunk-fmcm06xb.js → chunk-cq2q36d1.js} +1 -1
- package/{chunk-s84vxcdv.js → chunk-d19ttv1a.js} +1 -1
- package/{chunk-rqd4swxx.js → chunk-djwvt6jx.js} +1 -1
- package/chunk-dqqpbmxt.js +22 -0
- package/{chunk-eh2xp4v6.js → chunk-dy7qwj3t.js} +1 -1
- package/{chunk-rxkvjyst.js → chunk-ejpccmcj.js} +1 -1
- package/{chunk-sme6hv6f.js → chunk-emty5315.js} +1 -1
- package/{chunk-7gyzh0vq.js → chunk-esg0x95a.js} +1 -1
- package/{chunk-5yhnnhkd.js → chunk-ez720ked.js} +1 -1
- package/{chunk-md4mpvqc.js → chunk-ffm2jpxp.js} +1 -1
- package/{chunk-84n18xgx.js → chunk-g3k8k6fq.js} +2 -2
- package/{chunk-531xzfq5.js → chunk-h3ser37q.js} +1 -1
- package/{chunk-zv17t1n7.js → chunk-hsk91jms.js} +1 -1
- package/{chunk-snak5zpr.js → chunk-jxgwdz2r.js} +1 -1
- package/chunk-kvq7pcph.js +2 -0
- package/{chunk-qp3wahg4.js → chunk-m0v3d581.js} +1 -1
- package/{chunk-gcce587w.js → chunk-majd3gx9.js} +1 -1
- package/{chunk-qrnkrkkt.js → chunk-mqtnj8ws.js} +1 -1
- package/{chunk-0vaff40g.js → chunk-mqx96m2g.js} +1 -1
- package/{chunk-5s1wjhtj.js → chunk-nrxqr4v5.js} +1 -1
- package/{chunk-qqrac4va.js → chunk-nx0ex7qw.js} +1 -1
- package/{chunk-j306gr0c.js → chunk-q7wwqn03.js} +1 -1
- package/{chunk-xzf52wvn.js → chunk-qgbat4fv.js} +1 -1
- package/{chunk-asfgvzse.js → chunk-qqagacne.js} +1 -1
- package/{chunk-xg71h7nb.js → chunk-qx83fdv2.js} +1 -1
- package/{chunk-d93kpv7s.js → chunk-r5y1sh4f.js} +1 -1
- package/{chunk-kkvf0xk2.js → chunk-rg86bhtb.js} +2 -2
- package/{chunk-667ag8ts.js → chunk-rhfzy9c0.js} +1 -1
- package/{chunk-3m28pvzr.js → chunk-rrrn1mkq.js} +1 -1
- package/{chunk-fvezyap4.js → chunk-s1cwck4c.js} +1 -1
- package/{chunk-g7d065ek.js → chunk-sjxp2bx3.js} +1 -1
- package/{chunk-d0j8dg1e.js → chunk-t08391mh.js} +1 -1
- package/{chunk-j4fn2a2b.js → chunk-t61vyqpd.js} +1 -1
- package/{chunk-bms1sg4c.js → chunk-v6ks5v53.js} +1 -1
- package/{chunk-abr2hgay.js → chunk-w30zfv3m.js} +1 -1
- package/{chunk-ykpctq15.js → chunk-x84qrz4q.js} +1 -1
- package/{chunk-ex36z3b3.js → chunk-xg49s85z.js} +8 -8
- package/{chunk-5x4nw0zz.js → chunk-xxw67jpk.js} +2 -2
- package/{chunk-vdbr81a3.js → chunk-yjwtdm71.js} +1 -1
- package/{chunk-vs8j3x6t.js → chunk-z6r6wxm6.js} +1 -1
- package/{chunk-srp5gyr1.js → chunk-zgwvkgsz.js} +1 -1
- package/cli.js +1 -1
- package/package.json +1 -1
- package/pkgs/provider-antd/src/index.ts +1 -0
- package/pkgs/provider-html/src/index.ts +1 -0
- package/pkgs/provider-mui/src/index.ts +10 -0
- package/pkgs/provider-none/src/index.ts +1 -0
- package/pkgs/schema/src/board.ts +13 -1
- package/pkgs/schema/src/config.ts +34 -0
- package/pkgs/schema/src/flow.ts +230 -0
- package/pkgs/schema/src/frame.ts +7 -0
- package/pkgs/schema/src/index.ts +21 -0
- package/pkgs/schema/src/node-identity.ts +48 -0
- package/pkgs/schema/src/node.ts +80 -9
- package/pkgs/schema/src/theme.ts +56 -0
- package/plugins/claude/velloo/agents/velloo-designer.md +7 -4
- package/plugins/claude/velloo/commands/setup.md +13 -0
- package/plugins/gemini/GEMINI.md +9 -5
- package/plugins/gemini/commands/velloo/setup.toml +11 -0
- package/skills/velloo-design/SKILL.md +11 -6
- package/skills/velloo-setup/SKILL.md +179 -36
- package/canvas/assets/index-BQ5710lu.js +0 -29
- package/canvas/assets/index-GNLd0pCG.css +0 -2
- package/canvas/assets/lucide-all-DIRZdJPK.js +0 -1
- package/chunk-bys7pqdb.js +0 -2
- package/chunk-g8xrwjvq.js +0 -22
- package/chunk-jbgde2v9.js +0 -2
- package/chunk-sjjnm4a1.js +0 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./chunk-80fjfyha.js";import{string,number,boolean,unknown,array,object}from"./chunk-
|
|
2
|
+
import"./chunk-80fjfyha.js";import{string,number,boolean,unknown,array,object}from"./chunk-xxw67jpk.js";import"./chunk-9g45c5md.js";import"./chunk-xg49s85z.js";import"./chunk-bntsn3wj.js";import{fail}from"./chunk-s23gtejf.js";import{openUrl}from"./chunk-hggap8fq.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-6w42sr61.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{writeFileSync}from"fs";import{basename,join as join3,resolve as resolve2}from"path";import{readFileSync}from"fs";import{join,resolve,sep}from"path";var AssetRefSchema=object({file:string(),mimeType:string(),bytes:number()}),TapeRecordSchema=object({seq:number().optional(),ts:string().optional(),tool:string().optional(),durationMs:number().optional(),ok:boolean().optional(),params:unknown().optional(),text:string().optional(),images:array(AssetRefSchema).optional(),isError:boolean().optional(),error:object({name:string().optional(),message:string().optional(),stack:string().optional()}).optional(),sessionId:string().optional()}),TapeMetaSchema=object({tapeId:string().optional(),startedAt:string().optional(),folder:string().optional(),pid:number().optional()}),PendingCallSchema=object({seq:number().optional(),ts:string().optional(),tool:string().optional(),params:unknown().optional(),sessionId:string().optional()});function loadTape(dir){let meta={};try{let parsed=TapeMetaSchema.safeParse(JSON.parse(readFileSync(join(dir,"meta.json"),"utf8")));if(parsed.success)meta=parsed.data}catch{}let records=[],raw="";try{raw=readFileSync(join(dir,"tape.jsonl"),"utf8")}catch{}for(let line of raw.split(`
|
|
3
3
|
`)){let t=line.trim();if(!t)continue;try{let parsed=TapeRecordSchema.safeParse(JSON.parse(t));if(parsed.success)records.push(parsed.data)}catch{}}let pending=[];try{let raw=JSON.parse(readFileSync(join(dir,"pending.json"),"utf8"));if(Array.isArray(raw))pending=raw.flatMap((entry)=>{let parsed=PendingCallSchema.safeParse(entry);return parsed.success?[parsed.data]:[]})}catch{}let done=new Set(records.map((r)=>r.seq));return pending=pending.filter((p)=>!done.has(p.seq)),{dir,meta,records,pending}}var ESC={"&":"&","<":"<",">":">",'"':""","'":"'"};function esc(s){return s.replace(/[&<>"']/g,(c)=>ESC[c]??c)}function isBad(r){return r.ok===!1||r.isError===!0||Boolean(r.error)}function prettyJsonText(text){try{return JSON.stringify(JSON.parse(text),null,2)}catch{return text}}function fmtDuration(ms){if(ms===void 0)return"";return ms>=1000?`${(ms/1000).toFixed(2)}s`:`${ms}ms`}function fmtBytes(n){if(n>=1048576)return`${(n/1048576).toFixed(1)}MB`;if(n>=1024)return`${(n/1024).toFixed(0)}KB`;return`${n}B`}function timeOnly(iso){if(!iso)return"";let m=/T(\d{2}:\d{2}:\d{2})/.exec(iso);return m?m[1]:iso}function tapeStats(tape){let totalMs=tape.records.reduce((s,r)=>s+(r.durationMs??0),0);return{calls:tape.records.length,errors:tape.records.filter(isBad).length,totalLabel:fmtDuration(totalMs)}}function safeMimeType(mime){return/^[a-z0-9.+-]+\/[a-z0-9.+-]+$/i.test(mime)?mime:"application/octet-stream"}function inlineImage(dir,asset){let dataUri="";try{let abs=resolve(dir,asset.file);if(abs!==resolve(dir)&&!abs.startsWith(resolve(dir)+sep))return`<div class="missing">out-of-tree asset: ${esc(asset.file)}</div>`;let buf=readFileSync(abs);dataUri=`data:${safeMimeType(asset.mimeType)};base64,${buf.toString("base64")}`}catch{return`<div class="missing">missing asset: ${esc(asset.file)}</div>`}return`<img class="shot" loading="lazy" src="${dataUri}" alt="${esc(asset.file)}"/>`}function renderResult(dir,rec){if(rec.error){let head=esc([rec.error.name,rec.error.message].filter(Boolean).join(": ")||"error"),stack=rec.error.stack?`<pre class="stack">${esc(rec.error.stack)}</pre>`:"";return`<div class="err-box"><div class="err-head">${head}</div>${stack}</div>`}let parts=[];if(rec.text)parts.push(`<pre class="json">${esc(prettyJsonText(rec.text))}</pre>`);if(rec.images?.length){let imgs=rec.images.map((a)=>`<figure>${inlineImage(dir,a)}<figcaption>${esc(a.file.replace(/^assets\//,""))} \xB7 ${fmtBytes(a.bytes)}</figcaption></figure>`).join("");parts.push(`<div class="shots">${imgs}</div>`)}if(rec.isError)parts.unshift('<div class="flag">isError: true</div>');return parts.join("")||'<div class="muted">no output</div>'}function renderRow(dir,rec){let bad=isBad(rec),tool=esc(rec.tool??"?"),seq=rec.seq??"",params=esc(JSON.stringify(rec.params??null,null,2)),search=esc(`${rec.tool??""} ${rec.text??""} ${JSON.stringify(rec.params??"")}`.toLowerCase().slice(0,4000)),nShots=rec.images?.length?` \xB7 ${rec.images.length}\uD83D\uDCF7`:"";return`<details class="call${bad?" bad":""}" data-seq="${rec.seq??""}" data-error="${bad?1:0}" data-search="${search}">
|
|
4
4
|
<summary>
|
|
5
5
|
<span class="dot"></span>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{loadDesignFolder,liveExtensions,LiveBundler,hostAssetRequest,resolveProviders,findHostTailwindConfig,TailwindJit,createCaptureMount,extraThemeBlock}from"./chunk-
|
|
2
|
+
import{loadDesignFolder,liveExtensions,LiveBundler,hostAssetRequest,resolveProviders,findHostTailwindConfig,TailwindJit,createCaptureMount,extraThemeBlock}from"./chunk-9g45c5md.js";import{join,sep}from"path";var LIVE_BUNDLE_PATH="/live/bundle.js";async function withAssetServer(folder,liveCode,fn,routes={}){let{bundle,host}=routes,assetsRoot=join(folder,"assets"),server=Bun.serve({port:0,hostname:"127.0.0.1",async fetch(req){let url=new URL(req.url),stored=host?.(req);if(stored)return stored;let mounted=bundle?await bundle(url):null;if(mounted!==null)return new Response(mounted,{headers:{"Content-Type":"text/javascript","Access-Control-Allow-Origin":"*"}});if(liveCode!==null&&url.pathname===LIVE_BUNDLE_PATH)return new Response(liveCode,{headers:{"Content-Type":"text/javascript"}});if(url.pathname.startsWith("/assets/")){let fsPath=join(folder,decodeURIComponent(url.pathname));if(fsPath.startsWith(assetsRoot+sep)){let file=Bun.file(fsPath);if(await file.exists())return new Response(file)}}let hostAsset=host&&hostAssetRequest(req),fromHost=hostAsset?host(hostAsset):null;if(fromHost)return fromHost;return new Response("not found",{status:404})}});try{return await fn(`http://127.0.0.1:${server.port}/`)}finally{server.stop(!0)}}import{join as join2}from"path";function createOneShotLiveBundler(root,config){if(Object.keys(liveExtensions(config.extensions)).length===0)return null;return new LiveBundler(root,()=>config,()=>liveExtensions(config.extensions),!0,!0)}async function buildLiveModule(bundler){let bundle=await bundler.build();return{code:bundle.code.length>0?bundle.code:null,warnings:bundle.errors.map((error)=>`live-island: ${error.message}`)}}async function loadPipeline(folderPath){let design=await loadDesignFolder(folderPath),config=design.config,{providers,defaultProvider}=await resolveProviders(config,folderPath),capture=createCaptureMount(design,providers,defaultProvider),liveBundler=createOneShotLiveBundler(folderPath,config),jit=new TailwindJit(Object.values(providers),join2(folderPath,"screens"),void 0,()=>extraThemeBlock(design),()=>[...liveBundler?.hostSourceDirs()??[],...capture.sourceDirs()],()=>findHostTailwindConfig(folderPath,config.hostApp),config.styling?.framework),snapshotCss=await jit.build(),live;return{folderPath,design,config,providers,defaultProvider,jit,snapshotCss,capture,liveModule(){return live??=liveBundler?buildLiveModule(liveBundler):Promise.resolve({code:null,warnings:[]}),live}}}
|
|
3
3
|
export{LIVE_BUNDLE_PATH,withAssetServer,createOneShotLiveBundler,buildLiveModule,loadPipeline};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{ok,err,PROTECTED_SHARES_UNAVAILABLE,PublishDestinationsResponseSchema,LinkResponseSchema,LinkAccessResponseSchema,VersionUploadResponseSchema,PublishedDesignsResponseSchema,TeamsResponseSchema,unreachable,protocolViolation,uploadRaceLost,readFailure,cloudFailure,httpFailureFrom,boardLimitFrom,describeBoardLimit,describeCloudError,cloudJson,cloudFetch}from"./chunk-bys7pqdb.js";import{prettifyError,string,number,boolean,array,object,strictObject,record,_enum,literal,AnnotationSchema,CanvasNoteSchema,BoardSchema,ExtensionSchema,ViewportPresetSchema,LibrarySchema,StylingSchema,ScreenSchema,SnippetSchema,sanitizeSvgMarkup,ThemeSchema,ViewportSchema}from"./chunk-5x4nw0zz.js";import{buildBoardComposite,MAX_CONCURRENT_RENDERS,renderScreen,captureMountedDocument,captureScreenshot}from"./chunk-ex36z3b3.js";import{writeJsonAtomic,managedDesignId,localDesignOf,recordedDesignName,orderedBoards,activeBoards,registryForScreen,renderPassForScreen,hostStylesheetsForScreen,hostFilesFetch,storedHostSource,shipHostFiles,createCaptureMount}from"./chunk-brnkprt5.js";import{LIVE_BUNDLE_PATH,withAssetServer,createOneShotLiveBundler,buildLiveModule}from"./chunk-zv17t1n7.js";import{checkCloudHealth}from"./chunk-abr2hgay.js";var VERSION_UPLOAD_TIMEOUT_MS=60000,VERSION_UPLOAD_RETRIES=1;async function listPublishDestinations(opts){let query=new URLSearchParams({folderId:opts.folderId});if(opts.teamId)query.set("teamId",opts.teamId);return cloudFetch(`${opts.baseUrl}/v1/publish-destinations?${query}`,PublishDestinationsResponseSchema,{operation:"listing publish destinations",token:opts.token})}async function uploadLinkBundle(opts){let{baseUrl,token,form}=opts,authorized={authorization:`Bearer ${token}`},createRes=await fetch(`${baseUrl}/v1/links`,{method:"POST",headers:authorized,body:JSON.stringify(opts.link)}).catch((error)=>error);if(!(createRes instanceof Response))return err(unreachable(createRes,{url:baseUrl}));if(createRes.status!==200&&createRes.status!==201)return err(await httpFailureFrom("link creation",createRes));let created=createRes.status===201,createdLink=await cloudJson(createRes,LinkResponseSchema,"link creation");if(!createdLink.ok)return createdLink;let link=createdLink.value;if(opts.link.publishMode==="new"&&!created)return err(protocolViolation("the cloud reused a link even though a new publish destination was requested"));if(opts.link.publishMode==="update"&&created)return await fetch(`${baseUrl}/v1/links/${link.slug}`,{method:"DELETE",headers:authorized}).catch(()=>{}),err(protocolViolation("the cloud created a link even though an existing destination was selected"));if(!created){let accessRes=await fetch(`${baseUrl}/v1/links/${link.slug}/access`,{method:"PUT",headers:{...authorized,"content-type":"application/json"},body:JSON.stringify({visibility:opts.link.visibility,password:opts.link.password??null,passwordExpiresAt:opts.link.password?opts.link.passwordExpiresAt??null:null,expectedVersionId:opts.link.expectedVersionId??null,...opts.link.audience?.length?{audience:opts.link.audience}:{},...opts.link.publicComments!==void 0?{publicComments:opts.link.publicComments}:{}})});if(!accessRes.ok)return err(await httpFailureFrom("privacy update",accessRes));let access=await cloudJson(accessRes,LinkAccessResponseSchema,"privacy update");if(!access.ok)return access;link={...link,...access.value}}if(form.append("publishMode",opts.link.publishMode),opts.link.expectedVersionId)form.append("expectedVersionId",opts.link.expectedVersionId);let attempt=await uploadVersionWithRetry({url:`${baseUrl}/v1/links/${link.slug}/versions`,headers:authorized,form,timeoutMs:opts.uploadTimeoutMs??VERSION_UPLOAD_TIMEOUT_MS,retries:opts.uploadRetries??VERSION_UPLOAD_RETRIES});if(!attempt.ok)return attempt;let upload=attempt.value,uploadRes=upload.response;if(uploadRes.status!==201){let{detail,code}=await readFailure(uploadRes);if(upload.transientFailures>0&&uploadRes.status===409&&/slot changed|already has a version/i.test(detail))return err(uploadRaceLost());if(created)await fetch(`${baseUrl}/v1/links/${link.slug}`,{method:"DELETE",headers:authorized}).catch(()=>{});return err(cloudFailure("upload",uploadRes.status,detail,code))}let parsed=await cloudJson(uploadRes,VersionUploadResponseSchema,"upload");if(!parsed.ok)return parsed;let uploaded=parsed.value;return ok({link:{slug:link.slug,visibility:link.visibility??opts.link.visibility,passwordProtected:link.passwordProtected??opts.link.password!=null,...link.audience!==void 0?{audience:link.audience}:{},...link.publicComments!==void 0?{publicComments:link.publicComments}:{}},created,files:uploaded.files,bytes:uploaded.bytes,shareUrl:uploaded.url.startsWith("http")?uploaded.url:`${baseUrl}${uploaded.url}`,...uploaded.tier!==void 0?{tier:uploaded.tier}:{},...uploaded.history!==void 0?{history:uploaded.history}:{}})}async function uploadVersionWithRetry(opts){let attempts=Math.max(1,Math.floor(opts.retries)+1),transientFailures=0,lastNetworkError="unknown network error",lastTimedOut=!1;for(let attempt=1;attempt<=attempts;attempt+=1){let controller=new AbortController,timedOut=!1,timer=setTimeout(()=>{timedOut=!0,controller.abort()},Math.max(1,opts.timeoutMs));try{let response=await fetch(opts.url,{method:"POST",headers:opts.headers,body:opts.form,signal:controller.signal});if(response.status<500||attempt===attempts)return ok({response,transientFailures});transientFailures+=1,await response.body?.cancel().catch(()=>{})}catch(error){if(transientFailures+=1,lastTimedOut=timedOut,lastNetworkError=error instanceof Error?error.message:String(error),attempt===attempts){let retried=attempts>1?` after ${attempts} attempts`:"";return err(timedOut?unreachable(`timed out after ${formatDuration(opts.timeoutMs)}${retried}`,{url:opts.url,timedOut:!0}):unreachable(`version upload${retried}: ${lastNetworkError}`,{url:opts.url}))}}finally{clearTimeout(timer)}}return err(lastTimedOut?unreachable(`timed out after ${formatDuration(opts.timeoutMs)}`,{url:opts.url,timedOut:!0}):unreachable(`version upload: ${lastNetworkError}`,{url:opts.url}))}function formatDuration(ms){return ms>=1000?`${Math.round(ms/1000)}s`:`${Math.max(1,Math.round(ms))}ms`}var cloudUnhealthy=(detail)=>({kind:"CloudUnhealthy",detail}),noScreens=(root)=>({kind:"NoScreens",root}),noBoardScreens=(unplaced)=>({kind:"NoBoardScreens",unplaced}),bundleInvalid=(detail)=>({kind:"BundleInvalid",detail}),teamNotFound=(requested)=>({kind:"TeamNotFound",requested}),teamAmbiguous=(requested)=>({kind:"TeamAmbiguous",requested}),teamNotPublishable=(requested,reviewer)=>({kind:"TeamNotPublishable",requested,reviewer}),noPublishableTeam=(reviewer)=>({kind:"NoPublishableTeam",reviewer}),teamChoiceRequired=(names)=>({kind:"TeamChoiceRequired",names}),REVIEWERS_CANNOT_PUBLISH="reviewers can view and comment on boards, but not publish them \u2014 to publish, ask an owner or admin to make you a member",FREE_PLAN_OWNER_ONLY="on the Free plan only the organization owner publishes \u2014 ask the owner to renew, or leave the organization to publish on your own";function unplacedHint(unplaced){if(unplaced.length===0)return"";let shown=unplaced.slice(0,5).join(", "),more=unplaced.length>5?`, and ${unplaced.length-5} more`:"",[subject,it]=unplaced.length===1?["1 screen is","it"]:[`${unplaced.length} screens are`,"each"];return` ${subject} on no board (${shown}${more}): add a frame for ${it} on the canvas, or with add_frame.`}function describePublishError(error){switch(error.kind){case"CloudUnhealthy":return error.detail;case"NoScreens":return`no screens found in ${error.root} \u2014 is this a velloo design folder?`;case"NoBoardScreens":return`the selected boards have no screens.${unplacedHint(error.unplaced)}`;case"BundleInvalid":return`velloo built an invalid design bundle and did not upload it: ${error.detail}. This is a bug \u2014 please report it.`;case"TeamNotFound":return`no team named or identified by '${error.requested}'`;case"TeamAmbiguous":return`more than one team is named '${error.requested}'; pass its UUID`;case"TeamNotPublishable":return error.reviewer?REVIEWERS_CANNOT_PUBLISH:`you can't publish to '${error.requested}' \u2014 you can only publish to teams you're on`;case"NoPublishableTeam":return error.reviewer?REVIEWERS_CANNOT_PUBLISH:FREE_PLAN_OWNER_ONLY;case"TeamChoiceRequired":return`you can publish to more than one team \u2014 choose one (${error.names.join(", ")}) with --team`;case"HttpFailure":{if(error.status===403&&/protected shares/i.test(error.detail))return`${PROTECTED_SHARES_UNAVAILABLE}. Publish publicly, or upgrade your plan from your cloud's billing page`;let limit=boardLimitFrom(error);if(limit)return`${describeBoardLimit(limit)}. Run \`velloo publish list\` to see them, or upgrade your plan from your cloud's billing page`;return describeCloudError(error)}default:return describeCloudError(error)}}import{execFileSync}from"child_process";import{existsSync}from"fs";import{readFile}from"fs/promises";import{join}from"path";var DESIGN_BUNDLE_FORMAT=2,BundleScreenshotsSchema=object({cover:string().optional(),screens:record(string(),string()).optional(),boards:record(string(),string()).optional()}),DesignBundleMetaSchema=object({formatVersion:number().int().positive().optional(),title:string().optional(),screens:array(object({id:string(),name:string().optional()})).optional(),boards:array(object({id:string()})).optional(),screenshots:BundleScreenshotsSchema.optional()});var DesignBundleSchema=strictObject({formatVersion:literal(DESIGN_BUNDLE_FORMAT),title:string(),viewport:ViewportSchema,defaultLibrary:string(),libraries:record(string(),LibrarySchema),extensions:record(string(),ExtensionSchema),styling:StylingSchema.optional(),viewportPresets:array(ViewportPresetSchema),theme:ThemeSchema,themes:record(string(),ThemeSchema),customCss:string(),snippets:array(SnippetSchema),screens:array(ScreenSchema),boards:array(BoardSchema),annotations:record(string(),array(AnnotationSchema)),notes:record(string(),array(CanvasNoteSchema)),live:boolean(),snapshotCssPath:string(),bundlePath:string().optional(),hostStylesheets:array(string().regex(/^(?:assets\/host\/[A-Za-z0-9._@~+-][A-Za-z0-9._@~+/-]*\.css|https:\/\/\S+)$/)).optional(),appStylesheets:record(string(),string().regex(/^app-[a-z0-9]+\.css$/)).optional(),frozenScreens:record(string(),record(string(),string().regex(/^frozen\/[a-z0-9]+\.json$/))).optional(),screenshots:object({cover:string(),screens:record(string(),string()),boards:record(string(),string())}).optional()}),FrozenScreenSchema=strictObject({head:array(strictObject({tag:_enum(["style","link"]),attributes:record(string(),string()),css:string().optional(),file:string().regex(/^(?:snapshot|app-[a-z0-9]+|frozen\/[a-z0-9]+)\.css$/).optional()})),body:string(),htmlAttributes:record(string(),string()),bodyAttributes:record(string(),string())});function frozenVariantKey(themeName,scheme){return`${themeName}/${scheme}`}import{homedir}from"os";import{delimiter,dirname,resolve}from"path";function designGitEnv(folder){let ceilings=[homedir()];if(managedDesignId(folder)||localDesignOf(folder))ceilings.push(dirname(resolve(folder)));let inherited=process.env.GIT_CEILING_DIRECTORIES;if(inherited)ceilings.push(inherited);return{...process.env,GIT_CEILING_DIRECTORIES:ceilings.join(delimiter)}}var MAX_SCREENSHOT_BYTES=4194304,MAX_SCREENSHOT_COUNT=120,DOWNSCALE_WIDTH=1280;function isBrowserMissing(err){return err instanceof Error&&err.name==="BrowserMissingError"}async function captureBundleScreenshots(opts){let{screens,boards,viewport,renderHtml,capture,warn,progress}=opts,selectedScreens=opts.screenIds?screens.filter((screen)=>opts.screenIds?.has(screen.id)):screens,selectedBoards=opts.boardIds?boards.filter((board)=>opts.boardIds?.has(board.id)):boards,manifest={cover:"",screens:{},boards:{}},total=selectedScreens.length+selectedBoards.filter((board)=>board.frames.length>0).length,done=0,advance=()=>{done+=1,progress?.(done,total)},shoot=async(html,vp,fullPage,screen)=>{let of=screen?{screen}:{},png=await capture({html,viewport:vp,fullPage,deviceScaleFactor:1,...of});if(png.byteLength>MAX_SCREENSHOT_BYTES&&DOWNSCALE_WIDTH<vp.w)png=await capture({html,viewport:vp,fullPage,deviceScaleFactor:DOWNSCALE_WIDTH/vp.w,...of});return png.byteLength<=MAX_SCREENSHOT_BYTES?png:null},jobs=[];for(let screen of selectedScreens)jobs.push({run:async()=>{try{let png=await shoot(await renderHtml(screen),viewport,!0,screen);if(!png)return warn(`screenshot of screen "${screen.id}" exceeds 4MB even downscaled \u2014 skipped`),null;return{kind:"screen",id:screen.id,path:`screenshots/${screen.id}.png`,bytes:png}}catch(err){if(isBrowserMissing(err))throw err;return warn(`screenshot of screen "${screen.id}" failed \u2014 skipped (${message(err)})`),null}finally{advance()}}});let screenById=new Map(screens.map((screen)=>[screen.id,screen]));for(let board of selectedBoards){if(board.frames.length===0)continue;jobs.push({run:async()=>{try{let framed=(await Promise.all(board.frames.map(async(frame)=>{let screen=screenById.get(frame.screen);return screen?{frame,html:await renderHtml(screen,board.theme,frame.scheme??"light")}:null}))).filter((entry)=>entry!==null);if(framed.length===0)return null;let composite=buildBoardComposite(framed),png=await shoot(composite.html,composite.viewport,!1);if(!png)return warn(`screenshot of board "${board.id}" exceeds 4MB even downscaled \u2014 skipped`),null;return{kind:"board",id:board.id,path:`screenshots/${board.id}.png`,bytes:png}}catch(err){if(isBrowserMissing(err))throw err;return warn(`screenshot of board "${board.id}" failed \u2014 skipped (${message(err)})`),null}finally{advance()}}})}let shotLimit=MAX_SCREENSHOT_COUNT-1,results=Array.from({length:jobs.length},()=>null),nextJob=0,completedShots=0,reservedShots=0,browserMissing=!1,worker=async()=>{while(!browserMissing&&nextJob<jobs.length&&completedShots+reservedShots<shotLimit){let index=nextJob++;reservedShots+=1;try{let shot=await jobs[index]?.run();if(shot)results[index]=shot,completedShots+=1}catch(err){if(isBrowserMissing(err))browserMissing=!0;else throw err}finally{reservedShots-=1}}},concurrency=Math.max(1,Math.min(MAX_CONCURRENT_RENDERS,Math.floor(opts.concurrency??MAX_CONCURRENT_RENDERS)));if(await Promise.all(Array.from({length:Math.min(concurrency,jobs.length)},worker)),browserMissing)return warn("no headless browser available \u2014 publishing without screenshots"),null;if(nextJob<jobs.length)warn(`screenshot limit (${MAX_SCREENSHOT_COUNT}) reached \u2014 remaining shots skipped`);let files=[];for(let shot of results){if(!shot)continue;if(files.push({path:shot.path,bytes:shot.bytes}),shot.kind==="screen")manifest.screens[shot.id]=shot.path;else manifest.boards[shot.id]=shot.path}let coverSource=selectedBoards.map((b)=>manifest.boards[b.id]).find((p)=>p!==void 0)??selectedScreens.map((s)=>manifest.screens[s.id]).find((p)=>p!==void 0);if(!coverSource)return null;let source=files.find((f)=>f.path===coverSource);if(!source)return null;return manifest.cover="screenshots/cover.png",files.push({path:manifest.cover,bytes:source.bytes}),{manifest,files}}function message(err){let msg=err instanceof Error?err.message:String(err);return msg.split(`
|
|
2
|
+
import{ok,err,PROTECTED_SHARES_UNAVAILABLE,PublishDestinationsResponseSchema,LinkResponseSchema,LinkAccessResponseSchema,VersionUploadResponseSchema,PublishedDesignsResponseSchema,TeamsResponseSchema,unreachable,protocolViolation,uploadRaceLost,readFailure,cloudFailure,httpFailureFrom,boardLimitFrom,describeBoardLimit,describeCloudError,cloudJson,cloudFetch}from"./chunk-bntsn3wj.js";import{prettifyError,string,number,boolean,array,object,strictObject,record,_enum,literal,AnnotationSchema,CanvasNoteSchema,BoardSchema,ExtensionSchema,ViewportPresetSchema,LibrarySchema,StylingSchema,ScreenSchema,SnippetSchema,sanitizeSvgMarkup,ThemeSchema,ViewportSchema}from"./chunk-xxw67jpk.js";import{buildBoardComposite,MAX_CONCURRENT_RENDERS,renderScreen,captureMountedDocument,captureScreenshot}from"./chunk-xg49s85z.js";import{writeJsonAtomic,managedDesignId,localDesignOf,recordedDesignName,orderedBoards,activeBoards,registryForScreen,renderPassForScreen,hostStylesheetsForScreen,hostFilesFetch,storedHostSource,shipHostFiles,createCaptureMount}from"./chunk-9g45c5md.js";import{LIVE_BUNDLE_PATH,withAssetServer,createOneShotLiveBundler,buildLiveModule}from"./chunk-hsk91jms.js";import{checkCloudHealth}from"./chunk-w30zfv3m.js";var VERSION_UPLOAD_TIMEOUT_MS=60000,VERSION_UPLOAD_RETRIES=1;async function listPublishDestinations(opts){let query=new URLSearchParams({folderId:opts.folderId});if(opts.teamId)query.set("teamId",opts.teamId);return cloudFetch(`${opts.baseUrl}/v1/publish-destinations?${query}`,PublishDestinationsResponseSchema,{operation:"listing publish destinations",token:opts.token})}async function uploadLinkBundle(opts){let{baseUrl,token,form}=opts,authorized={authorization:`Bearer ${token}`},createRes=await fetch(`${baseUrl}/v1/links`,{method:"POST",headers:authorized,body:JSON.stringify(opts.link)}).catch((error)=>error);if(!(createRes instanceof Response))return err(unreachable(createRes,{url:baseUrl}));if(createRes.status!==200&&createRes.status!==201)return err(await httpFailureFrom("link creation",createRes));let created=createRes.status===201,createdLink=await cloudJson(createRes,LinkResponseSchema,"link creation");if(!createdLink.ok)return createdLink;let link=createdLink.value;if(opts.link.publishMode==="new"&&!created)return err(protocolViolation("the cloud reused a link even though a new publish destination was requested"));if(opts.link.publishMode==="update"&&created)return await fetch(`${baseUrl}/v1/links/${link.slug}`,{method:"DELETE",headers:authorized}).catch(()=>{}),err(protocolViolation("the cloud created a link even though an existing destination was selected"));if(!created){let accessRes=await fetch(`${baseUrl}/v1/links/${link.slug}/access`,{method:"PUT",headers:{...authorized,"content-type":"application/json"},body:JSON.stringify({visibility:opts.link.visibility,password:opts.link.password??null,passwordExpiresAt:opts.link.password?opts.link.passwordExpiresAt??null:null,expectedVersionId:opts.link.expectedVersionId??null,...opts.link.audience?.length?{audience:opts.link.audience}:{},...opts.link.publicComments!==void 0?{publicComments:opts.link.publicComments}:{}})});if(!accessRes.ok)return err(await httpFailureFrom("privacy update",accessRes));let access=await cloudJson(accessRes,LinkAccessResponseSchema,"privacy update");if(!access.ok)return access;link={...link,...access.value}}if(form.append("publishMode",opts.link.publishMode),opts.link.expectedVersionId)form.append("expectedVersionId",opts.link.expectedVersionId);let attempt=await uploadVersionWithRetry({url:`${baseUrl}/v1/links/${link.slug}/versions`,headers:authorized,form,timeoutMs:opts.uploadTimeoutMs??VERSION_UPLOAD_TIMEOUT_MS,retries:opts.uploadRetries??VERSION_UPLOAD_RETRIES});if(!attempt.ok)return attempt;let upload=attempt.value,uploadRes=upload.response;if(uploadRes.status!==201){let{detail,code}=await readFailure(uploadRes);if(upload.transientFailures>0&&uploadRes.status===409&&/slot changed|already has a version/i.test(detail))return err(uploadRaceLost());if(created)await fetch(`${baseUrl}/v1/links/${link.slug}`,{method:"DELETE",headers:authorized}).catch(()=>{});return err(cloudFailure("upload",uploadRes.status,detail,code))}let parsed=await cloudJson(uploadRes,VersionUploadResponseSchema,"upload");if(!parsed.ok)return parsed;let uploaded=parsed.value;return ok({link:{slug:link.slug,visibility:link.visibility??opts.link.visibility,passwordProtected:link.passwordProtected??opts.link.password!=null,...link.audience!==void 0?{audience:link.audience}:{},...link.publicComments!==void 0?{publicComments:link.publicComments}:{}},created,files:uploaded.files,bytes:uploaded.bytes,shareUrl:uploaded.url.startsWith("http")?uploaded.url:`${baseUrl}${uploaded.url}`,...uploaded.tier!==void 0?{tier:uploaded.tier}:{},...uploaded.history!==void 0?{history:uploaded.history}:{}})}async function uploadVersionWithRetry(opts){let attempts=Math.max(1,Math.floor(opts.retries)+1),transientFailures=0,lastNetworkError="unknown network error",lastTimedOut=!1;for(let attempt=1;attempt<=attempts;attempt+=1){let controller=new AbortController,timedOut=!1,timer=setTimeout(()=>{timedOut=!0,controller.abort()},Math.max(1,opts.timeoutMs));try{let response=await fetch(opts.url,{method:"POST",headers:opts.headers,body:opts.form,signal:controller.signal});if(response.status<500||attempt===attempts)return ok({response,transientFailures});transientFailures+=1,await response.body?.cancel().catch(()=>{})}catch(error){if(transientFailures+=1,lastTimedOut=timedOut,lastNetworkError=error instanceof Error?error.message:String(error),attempt===attempts){let retried=attempts>1?` after ${attempts} attempts`:"";return err(timedOut?unreachable(`timed out after ${formatDuration(opts.timeoutMs)}${retried}`,{url:opts.url,timedOut:!0}):unreachable(`version upload${retried}: ${lastNetworkError}`,{url:opts.url}))}}finally{clearTimeout(timer)}}return err(lastTimedOut?unreachable(`timed out after ${formatDuration(opts.timeoutMs)}`,{url:opts.url,timedOut:!0}):unreachable(`version upload: ${lastNetworkError}`,{url:opts.url}))}function formatDuration(ms){return ms>=1000?`${Math.round(ms/1000)}s`:`${Math.max(1,Math.round(ms))}ms`}var cloudUnhealthy=(detail)=>({kind:"CloudUnhealthy",detail}),noScreens=(root)=>({kind:"NoScreens",root}),noBoardScreens=(unplaced)=>({kind:"NoBoardScreens",unplaced}),bundleInvalid=(detail)=>({kind:"BundleInvalid",detail}),teamNotFound=(requested)=>({kind:"TeamNotFound",requested}),teamAmbiguous=(requested)=>({kind:"TeamAmbiguous",requested}),teamNotPublishable=(requested,reviewer)=>({kind:"TeamNotPublishable",requested,reviewer}),noPublishableTeam=(reviewer)=>({kind:"NoPublishableTeam",reviewer}),teamChoiceRequired=(names)=>({kind:"TeamChoiceRequired",names}),REVIEWERS_CANNOT_PUBLISH="reviewers can view and comment on boards, but not publish them \u2014 to publish, ask an owner or admin to make you a member",FREE_PLAN_OWNER_ONLY="on the Free plan only the organization owner publishes \u2014 ask the owner to renew, or leave the organization to publish on your own";function unplacedHint(unplaced){if(unplaced.length===0)return"";let shown=unplaced.slice(0,5).join(", "),more=unplaced.length>5?`, and ${unplaced.length-5} more`:"",[subject,it]=unplaced.length===1?["1 screen is","it"]:[`${unplaced.length} screens are`,"each"];return` ${subject} on no board (${shown}${more}): add a frame for ${it} on the canvas, or with add_frame.`}function describePublishError(error){switch(error.kind){case"CloudUnhealthy":return error.detail;case"NoScreens":return`no screens found in ${error.root} \u2014 is this a velloo design folder?`;case"NoBoardScreens":return`the selected boards have no screens.${unplacedHint(error.unplaced)}`;case"BundleInvalid":return`velloo built an invalid design bundle and did not upload it: ${error.detail}. This is a bug \u2014 please report it.`;case"TeamNotFound":return`no team named or identified by '${error.requested}'`;case"TeamAmbiguous":return`more than one team is named '${error.requested}'; pass its UUID`;case"TeamNotPublishable":return error.reviewer?REVIEWERS_CANNOT_PUBLISH:`you can't publish to '${error.requested}' \u2014 you can only publish to teams you're on`;case"NoPublishableTeam":return error.reviewer?REVIEWERS_CANNOT_PUBLISH:FREE_PLAN_OWNER_ONLY;case"TeamChoiceRequired":return`you can publish to more than one team \u2014 choose one (${error.names.join(", ")}) with --team`;case"HttpFailure":{if(error.status===403&&/protected shares/i.test(error.detail))return`${PROTECTED_SHARES_UNAVAILABLE}. Publish publicly, or upgrade your plan from your cloud's billing page`;let limit=boardLimitFrom(error);if(limit)return`${describeBoardLimit(limit)}. Run \`velloo publish list\` to see them, or upgrade your plan from your cloud's billing page`;return describeCloudError(error)}default:return describeCloudError(error)}}import{execFileSync}from"child_process";import{existsSync}from"fs";import{readFile}from"fs/promises";import{join}from"path";var DESIGN_BUNDLE_FORMAT=2,BundleScreenshotsSchema=object({cover:string().optional(),screens:record(string(),string()).optional(),boards:record(string(),string()).optional()}),DesignBundleMetaSchema=object({formatVersion:number().int().positive().optional(),title:string().optional(),screens:array(object({id:string(),name:string().optional()})).optional(),boards:array(object({id:string()})).optional(),screenshots:BundleScreenshotsSchema.optional()});var DesignBundleSchema=strictObject({formatVersion:literal(DESIGN_BUNDLE_FORMAT),title:string(),viewport:ViewportSchema,defaultLibrary:string(),libraries:record(string(),LibrarySchema),extensions:record(string(),ExtensionSchema),styling:StylingSchema.optional(),viewportPresets:array(ViewportPresetSchema),theme:ThemeSchema,themes:record(string(),ThemeSchema),customCss:string(),snippets:array(SnippetSchema),screens:array(ScreenSchema),boards:array(BoardSchema),annotations:record(string(),array(AnnotationSchema)),notes:record(string(),array(CanvasNoteSchema)),live:boolean(),snapshotCssPath:string(),bundlePath:string().optional(),hostStylesheets:array(string().regex(/^(?:assets\/host\/[A-Za-z0-9._@~+-][A-Za-z0-9._@~+/-]*\.css|https:\/\/\S+)$/)).optional(),appStylesheets:record(string(),string().regex(/^app-[a-z0-9]+\.css$/)).optional(),frozenScreens:record(string(),record(string(),string().regex(/^frozen\/[a-z0-9]+\.json$/))).optional(),screenshots:object({cover:string(),screens:record(string(),string()),boards:record(string(),string())}).optional()}),FrozenScreenSchema=strictObject({head:array(strictObject({tag:_enum(["style","link"]),attributes:record(string(),string()),css:string().optional(),file:string().regex(/^(?:snapshot|app-[a-z0-9]+|frozen\/[a-z0-9]+)\.css$/).optional()})),body:string(),htmlAttributes:record(string(),string()),bodyAttributes:record(string(),string())});function frozenVariantKey(themeName,scheme){return`${themeName}/${scheme}`}import{homedir}from"os";import{delimiter,dirname,resolve}from"path";function designGitEnv(folder){let ceilings=[homedir()];if(managedDesignId(folder)||localDesignOf(folder))ceilings.push(dirname(resolve(folder)));let inherited=process.env.GIT_CEILING_DIRECTORIES;if(inherited)ceilings.push(inherited);return{...process.env,GIT_CEILING_DIRECTORIES:ceilings.join(delimiter)}}var MAX_SCREENSHOT_BYTES=4194304,MAX_SCREENSHOT_COUNT=120,DOWNSCALE_WIDTH=1280;function isBrowserMissing(err){return err instanceof Error&&err.name==="BrowserMissingError"}async function captureBundleScreenshots(opts){let{screens,boards,viewport,renderHtml,capture,warn,progress}=opts,selectedScreens=opts.screenIds?screens.filter((screen)=>opts.screenIds?.has(screen.id)):screens,selectedBoards=opts.boardIds?boards.filter((board)=>opts.boardIds?.has(board.id)):boards,manifest={cover:"",screens:{},boards:{}},total=selectedScreens.length+selectedBoards.filter((board)=>board.frames.length>0).length,done=0,advance=()=>{done+=1,progress?.(done,total)},shoot=async(html,vp,fullPage,screen)=>{let of=screen?{screen}:{},png=await capture({html,viewport:vp,fullPage,deviceScaleFactor:1,...of});if(png.byteLength>MAX_SCREENSHOT_BYTES&&DOWNSCALE_WIDTH<vp.w)png=await capture({html,viewport:vp,fullPage,deviceScaleFactor:DOWNSCALE_WIDTH/vp.w,...of});return png.byteLength<=MAX_SCREENSHOT_BYTES?png:null},jobs=[];for(let screen of selectedScreens)jobs.push({run:async()=>{try{let png=await shoot(await renderHtml(screen),viewport,!0,screen);if(!png)return warn(`screenshot of screen "${screen.id}" exceeds 4MB even downscaled \u2014 skipped`),null;return{kind:"screen",id:screen.id,path:`screenshots/${screen.id}.png`,bytes:png}}catch(err){if(isBrowserMissing(err))throw err;return warn(`screenshot of screen "${screen.id}" failed \u2014 skipped (${message(err)})`),null}finally{advance()}}});let screenById=new Map(screens.map((screen)=>[screen.id,screen]));for(let board of selectedBoards){if(board.frames.length===0)continue;jobs.push({run:async()=>{try{let framed=(await Promise.all(board.frames.map(async(frame)=>{let screen=screenById.get(frame.screen);return screen?{frame,html:await renderHtml(screen,board.theme,frame.scheme??"light")}:null}))).filter((entry)=>entry!==null);if(framed.length===0)return null;let composite=buildBoardComposite(framed),png=await shoot(composite.html,composite.viewport,!1);if(!png)return warn(`screenshot of board "${board.id}" exceeds 4MB even downscaled \u2014 skipped`),null;return{kind:"board",id:board.id,path:`screenshots/${board.id}.png`,bytes:png}}catch(err){if(isBrowserMissing(err))throw err;return warn(`screenshot of board "${board.id}" failed \u2014 skipped (${message(err)})`),null}finally{advance()}}})}let shotLimit=MAX_SCREENSHOT_COUNT-1,results=Array.from({length:jobs.length},()=>null),nextJob=0,completedShots=0,reservedShots=0,browserMissing=!1,worker=async()=>{while(!browserMissing&&nextJob<jobs.length&&completedShots+reservedShots<shotLimit){let index=nextJob++;reservedShots+=1;try{let shot=await jobs[index]?.run();if(shot)results[index]=shot,completedShots+=1}catch(err){if(isBrowserMissing(err))browserMissing=!0;else throw err}finally{reservedShots-=1}}},concurrency=Math.max(1,Math.min(MAX_CONCURRENT_RENDERS,Math.floor(opts.concurrency??MAX_CONCURRENT_RENDERS)));if(await Promise.all(Array.from({length:Math.min(concurrency,jobs.length)},worker)),browserMissing)return warn("no headless browser available \u2014 publishing without screenshots"),null;if(nextJob<jobs.length)warn(`screenshot limit (${MAX_SCREENSHOT_COUNT}) reached \u2014 remaining shots skipped`);let files=[];for(let shot of results){if(!shot)continue;if(files.push({path:shot.path,bytes:shot.bytes}),shot.kind==="screen")manifest.screens[shot.id]=shot.path;else manifest.boards[shot.id]=shot.path}let coverSource=selectedBoards.map((b)=>manifest.boards[b.id]).find((p)=>p!==void 0)??selectedScreens.map((s)=>manifest.screens[s.id]).find((p)=>p!==void 0);if(!coverSource)return null;let source=files.find((f)=>f.path===coverSource);if(!source)return null;return manifest.cover="screenshots/cover.png",files.push({path:manifest.cover,bytes:source.bytes}),{manifest,files}}function message(err){let msg=err instanceof Error?err.message:String(err);return msg.split(`
|
|
3
3
|
`)[0]??msg}var normalizedBoardIds=(boardIds)=>[...new Set(boardIds)].sort();function publishSlotMismatches(slot,current){let mismatches=[];if(!slot.context.contextKnown)mismatches.push("older publish has no board-selection context");if(!(current.candidateTeamIds?slot.teamId!==null&¤t.candidateTeamIds.includes(slot.teamId):slot.teamId===current.teamId))mismatches.push("team differs");if(JSON.stringify(normalizedBoardIds(slot.context.boardIds))!==JSON.stringify(normalizedBoardIds(current.boardIds)))mismatches.push("board selection differs");if(slot.context.repo!==current.repo)mismatches.push("repository differs");else if(current.repo!==null){if(!slot.context.branch||!current.branch)mismatches.push("branch is unavailable");else if(slot.context.branch!==current.branch)mismatches.push("branch differs")}return mismatches}function recommendedPublishSlot(slots,current){return exactPublishSlots(slots,current)[0]??null}function exactPublishSlots(slots,current){return slots.filter((slot)=>publishSlotMismatches(slot,current).length===0).sort((left,right)=>publishedAt(right.lastPublishedAt)-publishedAt(left.lastPublishedAt))}var publishedAt=(value)=>{let parsed=value?Date.parse(value):Number.NaN;return Number.isFinite(parsed)?parsed:Number.NEGATIVE_INFINITY},PUBLISH_VIEWPORT={w:1440,h:900};function defaultPublishTitle(folderRoot){return`${recordedDesignName(folderRoot)??folderRoot.split("/").filter(Boolean).pop()} designs`}async function ensureFolderId(folder,existing,report){if(existing)return existing;let path=join(folder,".design","config.json"),raw=JSON.parse(await readFile(path,"utf8")),folderId=crypto.randomUUID();return await writeJsonAtomic(path,{...raw,folderId}),report({kind:"note",message:"assigned this folder a cloud id (.design/config.json folderId) \u2014 commit it so every clone finds the folder's share links."}),folderId}function reportProvenance(git,report){if(git.repo){report({kind:"info",message:git.branch?`source: ${git.repo} on ${git.branch}`:`source: ${git.repo} (detached HEAD \u2014 no branch recorded)`});return}report({kind:"info",message:git.branch?`source: branch ${git.branch} \u2014 no git remote, publishing without a repository`:"source: not a git repository \u2014 publishing without repository or branch"})}function gitProbe(folder){return{encoding:"utf8",stdio:["ignore","pipe","ignore"],env:designGitEnv(folder)}}function gitCommitSha(folder){try{let probe=gitProbe(folder);if(execFileSync("git",["-C",folder,"status","--porcelain"],probe).trim().length>0)return null;return execFileSync("git",["-C",folder,"rev-parse","HEAD"],probe).trim()}catch{return null}}function normalizeRemote(url){let rest=url.trim().replace(/\.git\/?$/,"");if(/^[./~]/.test(rest)||/^[a-z]:[\\/]/i.test(rest)||rest.startsWith("file://"))return null;let scp=/^(?:[\w.-]+@)?([\w.-]+):(?!\/\/)(.+)$/.exec(rest);if(scp?.[1]&&scp[2])return`${scp[1]}/${scp[2].replace(/^\/+/,"")}`;try{let parsed=new URL(rest.includes("://")?rest:`https://${rest}`);if(!parsed.hostname||!parsed.pathname||parsed.pathname==="/")return null;return`${parsed.hostname}${parsed.pathname.replace(/\/+$/,"")}`}catch{return null}}function gitContext(folder){let probe=gitProbe(folder),run=(args)=>{try{return execFileSync("git",["-C",folder,...args],probe).trim()||null}catch{return null}},branchRaw=run(["rev-parse","--abbrev-ref","HEAD"]),remote=run(["remote","get-url","origin"]);return{repo:remote?normalizeRemote(remote):null,branch:branchRaw==="HEAD"?null:branchRaw}}function publishableTeams(teams){return teams.filter((team)=>team.canPublish!==!1)}function resolvePublishTeam(teams,requested){if(teams.length===0)return requested?err(teamNotFound(requested)):ok({kind:"personal"});let reviewer=teams.some((team)=>team.role==="reviewer"),publishable=publishableTeams(teams);if(requested){let named=(candidates)=>candidates.filter((team)=>team.id===requested||team.name.toLowerCase()===requested.toLowerCase()),exact=named(publishable);if(exact.length>1)return err(teamAmbiguous(requested));let[team]=exact;if(team)return ok({kind:"team",team});return err(named(teams).length>0?teamNotPublishable(requested,reviewer):publishable.length===0?noPublishableTeam(reviewer):teamNotFound(requested))}let[only,...rest]=publishable;if(!only)return err(noPublishableTeam(reviewer));return rest.length===0?ok({kind:"team",team:only}):ok({kind:"choose",teams:publishable})}async function listTeams(baseUrl,token){let body=await cloudFetch(`${baseUrl}/v1/teams/mine`,TeamsResponseSchema,{operation:"listing teams",token});return body.ok?ok(body.value.teams):body}function selectBoards(design,boardIds){if(!boardIds||boardIds.length===0)return activeBoards(design).map(([,board])=>board);let wanted=new Set(boardIds);return orderedBoards(design).map(([,board])=>board).filter((board)=>wanted.has(board.id))}var SNAPSHOT_CSS_PATH="snapshot.css",SHARED_CSS_MIN_LENGTH=2048;function frozenVariantsOf(screen,design,boards){let themes=new Map,see=(themeName,pinnedDark)=>{let theme=(themeName?design.themes.get(themeName):void 0)??design.theme,seen=themes.get(theme.name);themes.set(theme.name,{themeName:seen?seen.themeName:themeName,theme,dark:Boolean(seen?.dark)||pinnedDark||Boolean(theme.colorsDark)})};see(void 0,!1);for(let board of boards)for(let frame of board.frames)if(frame.screen===screen.id)see(board.theme,frame.scheme==="dark");return[...themes.values()].flatMap(({themeName,theme,dark})=>(dark?["light","dark"]:["light"]).map((scheme)=>({key:`${screen.id}\x00${theme.name}\x00${scheme}`,screen,themeName,theme,scheme})))}async function publishDesign(cloud,pipeline,request,report=()=>{}){let{folder:design}=pipeline,{root,config}=design;report({kind:"step",step:"check",message:"checking the cloud"});let health=await checkCloudHealth(cloud.baseUrl);if(health.status==="unreachable")return err(unreachable(health.reason,{url:cloud.baseUrl}));if(health.status==="unhealthy")return err(cloudUnhealthy(health.detail));if(design.screens.size===0)return err(noScreens(root));report({kind:"step",step:"select",message:"collecting boards"});let boards=selectBoards(design,request.boardIds),screenIds=Boolean(request.boardIds&&request.boardIds.length>0)?new Set(boards.flatMap((b)=>b.frames.map((f)=>f.screen))):null,screens=screenIds?[...design.screens.values()].filter((s)=>screenIds.has(s.id)):[...design.screens.values()];if(screens.length===0){let placed=new Set([...design.boards.values()].flatMap((board)=>board.frames.map((frame)=>frame.screen)));return err(noBoardScreens([...design.screens.keys()].filter((id)=>!placed.has(id))))}let viewport=request.viewport??PUBLISH_VIEWPORT,title=request.title?.trim()||defaultPublishTitle(root),form=new FormData,bundleFiles=0,bundleBytes=0,addFile=(path,data,type)=>{if(typeof data==="string"?data.length===0:data.byteLength===0)return report({kind:"warn",message:`skipped empty file: ${path}`}),!1;return form.append("file",new File([data],path,type?{type}:void 0)),bundleFiles+=1,bundleBytes+=typeof data==="string"?new TextEncoder().encode(data).byteLength:data.byteLength,!0},bundler=pipeline.liveBundler??createOneShotLiveBundler(root,config);report({kind:"step",step:"styles",message:"compiling styles"});let snapshotCss=await pipeline.snapshotCss(),live=!1,liveCode=null;if(bundler){report({kind:"step",step:"bundle",message:"bundling live components"});let bundle=await buildLiveModule(bundler);for(let message of bundle.warnings)report({kind:"warn",message});if(bundle.code!==null&&addFile("bundle.js",bundle.code,"text/javascript"))liveCode=bundle.code,live=!0}report({kind:"step",step:"capture",message:"capturing previews"});let mount=createCaptureMount(pipeline.folder,pipeline.providers,pipeline.defaultProvider),appCss=new Map,appStylesheets={},assetBearing=[],shipped=new Set,sharedCss=new Map;if(snapshotCss)sharedCss.set(snapshotCss,SNAPSHOT_CSS_PATH);let addOnce=(path,data,type)=>{if(shipped.has(path))return;shipped.add(path),addFile(path,data,type)};for(let screen of screens){let css=await mount.appCss(screen).catch(()=>"");if(css.trim()==="")continue;appCss.set(screen.id,css);let path=`app-${Bun.hash(css).toString(36)}.css`;addOnce(path,css,"text/css"),appStylesheets[screen.id]=path,sharedCss.set(css,path),assetBearing.push(css)}let frozenFiles=new Map,frozenAt=new Map,freezeAttempted=new Set,notFrozen=new Set,browserMissing=!1,nameOf=(screen)=>screen.name||screen.id,shareStyle=(style)=>{let{tag,attributes,css}=style;if(css===void 0)return{tag,attributes};if(css.length<SHARED_CSS_MIN_LENGTH)return{tag,attributes,css};let file=sharedCss.get(css);if(!file)file=`frozen/${Bun.hash(css).toString(36)}.css`,frozenFiles.set(file,css),sharedCss.set(css,file);return{tag,attributes,file}},keepFrozen=(variant,page)=>{if(freezeAttempted.add(variant.key),!page?.mounted){notFrozen.add(nameOf(variant.screen));return}let frozen={head:page.head.map(shareStyle),body:page.body,htmlAttributes:page.htmlAttributes,bodyAttributes:page.bodyAttributes},json=JSON.stringify(frozen),path=`frozen/${Bun.hash(json).toString(36)}.json`;frozenFiles.set(path,json);let variants=frozenAt.get(variant.screen.id)??new Map;variants.set(frozenVariantKey(variant.theme.name,variant.scheme),path),frozenAt.set(variant.screen.id,variants)},shots=await withAssetServer(root,liveCode,async(baseHref)=>{let htmlCache=new Map,renderHtml=async(screen,themeName,scheme="light")=>{let theme=(themeName?design.themes.get(themeName):void 0)??design.theme,key=`${screen.id}\x00${theme.name}\x00${scheme}`,cached=htmlCache.get(key);if(cached)return cached;let canvasBundle=await mount.forScreen(screen,theme,scheme==="dark"),rendering=renderScreen(screen,theme,{viewport,snapshotCss,registry:registryForScreen(screen,pipeline.providers,pipeline.defaultProvider,config.extensions??{},config.styling?.framework),renderPass:renderPassForScreen(screen,pipeline.providers,pipeline.defaultProvider,theme),snippets:design.snippets,customCss:design.customCss,appCss:appCss.get(screen.id),dark:scheme==="dark",baseHref,includeRuntime:!1,...live?{liveBundleUrl:LIVE_BUNDLE_PATH}:{},...canvasBundle?{canvasBundle}:{},hostStylesheets:hostStylesheetsForScreen(screen,pipeline.providers,pipeline.defaultProvider,config.hostApp)}).then(({html})=>html);return htmlCache.set(key,rendering),rendering},variants=[];for(let screen of screens){if(await mount.forScreen(screen,design.theme,!1)===void 0)continue;variants.push(...frozenVariantsOf(screen,design,boards))}let previewed=(screen)=>request.screenshotSelection?.screenIds.has(screen.id)??!0,withPreview=new Map;for(let variant of variants)if(variant.themeName===void 0&&variant.scheme==="light"&&previewed(variant.screen))withPreview.set(variant.screen.id,variant);let freeze=async(variant)=>{try{keepFrozen(variant,await captureMountedDocument({html:await renderHtml(variant.screen,variant.themeName,variant.scheme),viewport}))}catch(error){if(error instanceof Error&&error.name==="BrowserMissingError")browserMissing=!0;freezeAttempted.add(variant.key),notFrozen.add(nameOf(variant.screen))}},ownLoads=Promise.all(variants.filter((variant)=>withPreview.get(variant.screen.id)!==variant).map(freeze)),shots=await captureBundleScreenshots({screens,boards,...request.screenshotSelection?{screenIds:request.screenshotSelection.screenIds,boardIds:request.screenshotSelection.boardIds}:{},viewport,renderHtml,capture:async(req)=>{let variant=req.screen?withPreview.get(req.screen.id):void 0,toFreeze=variant!==void 0&&!freezeAttempted.has(variant.key),shot=await captureScreenshot({html:req.html,viewport:req.viewport,fullPage:req.fullPage,deviceScaleFactor:req.deviceScaleFactor,...toFreeze?{freeze:!0}:{}});if(toFreeze)keepFrozen(variant,shot.frozen);return shot.png},warn:(message)=>report({kind:"warn",message}),progress:(done,total)=>report({kind:"capture",done,total})});return await ownLoads,await Promise.all(variants.filter((variant)=>!freezeAttempted.has(variant.key)).map(freeze)),shots},{bundle:mount.serve,host:hostFilesFetch(()=>root)});for(let path of[...frozenFiles.keys()].sort()){let text=frozenFiles.get(path)??"";addFile(path,text,path.endsWith(".css")?"text/css":"application/json"),assetBearing.push(text)}let frozenScreens={};for(let screen of screens){let at=frozenAt.get(screen.id);if(at)frozenScreens[screen.id]=Object.fromEntries([...at].sort(([a],[b])=>a<b?-1:1))}for(let f of shots?.files??[])addFile(f.path,f.bytes,"image/png");if(notFrozen.size>0)report({kind:"warn",message:`the share will not match the canvas for ${[...notFrozen].sort().join(", ")}: the canvas draws ${notFrozen.size===1?"it":"them"} with the app's own components, which could not be mounted here, so a viewer sees velloo's stand-ins instead. ${browserMissing?"Run `velloo browser install` and publish again.":"component_status says what stopped them mounting."}`});let host=Object.values(pipeline.providers).some((provider)=>provider.hostStylesheets)?await shipHostFiles({source:storedHostSource(root),stylesheets:config.hostApp?.stylesheets??[],screens,snippets:[...design.snippets.values()],warn:(message)=>report({kind:"warn",message}),designAsset:(path)=>existsSync(join(root,path))}):{screens,snippets:[...design.snippets.values()],files:[],stylesheets:[]};for(let f of host.files)addFile(f.path,f.bytes,f.type);let annotations=Object.fromEntries([...design.annotations].filter(([screenId,list])=>list.length>0&&screens.some((s)=>s.id===screenId))),notes=Object.fromEntries([...design.notes].filter(([boardId,list])=>list.length>0&&boards.some((b)=>b.id===boardId))),designDoc={formatVersion:DESIGN_BUNDLE_FORMAT,title,viewport,defaultLibrary:config.defaultLibrary,libraries:config.libraries,extensions:config.extensions??{},...config.styling?{styling:config.styling}:{},viewportPresets:config.viewportPresets??[],theme:design.theme,themes:Object.fromEntries(design.themes),customCss:design.customCss,snippets:host.snippets,screens:host.screens,boards,annotations,notes,live,snapshotCssPath:SNAPSHOT_CSS_PATH,...live?{bundlePath:"bundle.js"}:{},...host.stylesheets.length>0?{hostStylesheets:host.stylesheets}:{},...Object.keys(appStylesheets).length>0?{appStylesheets}:{},...Object.keys(frozenScreens).length>0?{frozenScreens}:{},...shots?{screenshots:shots.manifest}:{}},validated=DesignBundleSchema.safeParse(designDoc);if(!validated.success)return err(bundleInvalid(prettifyError(validated.error)));addFile("design.json",JSON.stringify(designDoc),"application/json"),addFile(SNAPSHOT_CSS_PATH,snapshotCss||`/* this folder uses no CSS framework */
|
|
4
4
|
`,"text/css");let assetRefs=new Set,assetRe=/\/assets\/[A-Za-z0-9._@\-/]+/g;for(let source of[...host.screens,...host.snippets])for(let m of JSON.stringify(source).matchAll(assetRe))assetRefs.add(m[0]);for(let text of[design.customCss,...assetBearing])for(let m of text.matchAll(assetRe))assetRefs.add(m[0]);for(let ref of assetRefs){if(ref.startsWith("/assets/host/"))continue;let rel=ref.replace(/^\//,"");try{let bytes=await readFile(join(root,rel));addFile(rel,/\.svg$/i.test(rel)?Buffer.from(sanitizeSvgMarkup(bytes.toString("utf8")),"utf8"):bytes)}catch{report({kind:"warn",message:`asset not found: ${rel}`})}}let commitSha=gitCommitSha(root);if(commitSha)form.append("commitSha",commitSha);let git=request.provenance??gitContext(root);if(reportProvenance(git,report),git.repo)form.append("gitRepo",git.repo);if(git.branch)form.append("gitBranch",git.branch);let folderId=await ensureFolderId(root,config.folderId,report);report({kind:"step",step:"upload",message:`uploading ${bundleFiles} file${bundleFiles===1?"":"s"} (${formatBytes(bundleBytes)})`});let uploaded=await uploadLinkBundle({baseUrl:cloud.baseUrl,token:cloud.token,link:{...request.destination.slug?{slug:request.destination.slug}:{},folderId,publishMode:request.destination.mode,...request.destination.mode==="update"?{expectedVersionId:request.destination.expectedVersionId}:{},title,visibility:request.visibility,...request.teamId?{teamId:request.teamId}:{},...request.audience?.length?{audience:request.audience}:{},...request.publicComments!==void 0?{publicComments:request.publicComments}:{},...request.password?{password:request.password}:{},...request.passwordExpiresAt?{passwordExpiresAt:request.passwordExpiresAt}:{}},form});if(!uploaded.ok)return uploaded;let upload=uploaded.value;return ok({shareUrl:upload.shareUrl,slug:upload.link.slug,visibility:upload.link.visibility,passwordProtected:upload.link.passwordProtected,...upload.link.audience!==void 0?{audience:upload.link.audience}:{},...upload.link.publicComments!==void 0?{publicComments:upload.link.publicComments}:{},files:upload.files,bytes:upload.bytes,screenshots:shots?.files.length??0,boards:boards.length,screens:screens.length,commitSha,created:upload.created,...upload.tier!==void 0?{tier:upload.tier}:{},...upload.history!==void 0?{history:upload.history}:{}})}function formatBytes(bytes){if(bytes>=1048576)return`${(bytes/1048576).toFixed(1)} MB`;if(bytes>=1024)return`${Math.round(bytes/1024)} KB`;return`${bytes} B`}function publishedDesignSubtitle(design){let published=design.lastPublishedAt?`Published ${design.lastPublishedAt}`:"Publish time unavailable",who=design.ownerEmail?.trim()||design.ownerName?.trim(),publisher=who?`by ${who}`:"publisher unavailable",repo=design.git?.repo?.trim(),branch=design.git?.branch?.trim(),source=repo?`repo ${repo}${branch?` (${branch})`:""}`:"repository unavailable";return`${published} \xB7 ${publisher} \xB7 ${source}`}async function listPublishedDesigns(opts){let body=await cloudFetch(`${opts.baseUrl}/v1/links`,PublishedDesignsResponseSchema,{operation:"listing published designs",token:opts.token});if(!body.ok)return body;return ok((body.value.links??[]).filter((link)=>link.published).map((link)=>({...link,url:link.url.startsWith("http")?link.url:`${opts.baseUrl}${link.url}`})))}async function unpublishDesign(opts){let res=await fetch(`${opts.baseUrl}/v1/links/${encodeURIComponent(opts.slug)}`,{method:"DELETE",headers:{authorization:`Bearer ${opts.token}`}}).catch((error)=>error);if(!(res instanceof Response))return err(unreachable(res,{url:opts.baseUrl}));if(!res.ok)return err(await httpFailureFrom("unpublishing the design",res));return ok(void 0)}
|
|
5
5
|
export{publishedDesignSubtitle,listPublishedDesigns,unpublishDesign,listPublishDestinations,designGitEnv,teamChoiceRequired,describePublishError,recommendedPublishSlot,exactPublishSlots,PUBLISH_VIEWPORT,gitContext,publishableTeams,resolvePublishTeam,listTeams,publishDesign};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
import{upgrade_default,migrateFolder2}from"./chunk-mqx96m2g.js";import"./chunk-07fxzrx2.js";import"./chunk-pjtg3wnm.js";import"./chunk-ez720ked.js";import"./chunk-qgbat4fv.js";import"./chunk-6w42sr61.js";import"./chunk-80fjfyha.js";import"./chunk-9g45c5md.js";import"./chunk-xg49s85z.js";import"./chunk-w30zfv3m.js";import"./chunk-bntsn3wj.js";import"./chunk-d19ttv1a.js";import"./chunk-rrrn1mkq.js";import"./chunk-s23gtejf.js";import"./chunk-xxw67jpk.js";export{upgrade_default as default,migrateFolder2 as migrateFolder};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{isCancel,select}from"./chunk-80fjfyha.js";import{chromiumExecutable,closePooledBrowser}from"./chunk-
|
|
2
|
+
import{isCancel,select}from"./chunk-80fjfyha.js";import{chromiumExecutable,closePooledBrowser}from"./chunk-xg49s85z.js";import"./chunk-xxw67jpk.js";import{writeText,findFrame,exportFilename,exportFramePng,exportBoardPng,exportFramePdf,exportBoardPdf,exportScreenHtml,exportScreenPng,exportScreenPdf,exportFrameHtml,exportBoardHtml,hostFilesFetch,screensForExportTarget}from"./chunk-9g45c5md.js";import"./chunk-bntsn3wj.js";import{fail}from"./chunk-s23gtejf.js";import{captureWithBrowserSetup}from"./chunk-dy7qwj3t.js";import{confirmRenderFailures}from"./chunk-qqagacne.js";import{LIVE_BUNDLE_PATH,withAssetServer,loadPipeline}from"./chunk-hsk91jms.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-6w42sr61.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{extname,isAbsolute,resolve}from"path";var export_default=defineCommand({meta:{name:"export",description:"Export a screen, frame, or board as PNG, PDF, or standalone HTML (format = --to extension)"},args:{target:{type:"positional",required:!1,description:"Screen, frame, or board id. Omit to pick interactively."},design:{type:"string",description:DESIGN_ARG_DESCRIPTION},to:{type:"string",description:"Output path; extension picks the format (.png | .pdf | .html). Default: ./<target>.png"},mode:{type:"string",description:"light (default) | dark | compare (side-by-side light|dark; PNG, non-board only)"},scale:{type:"string",description:"PNG raster density (0.25\u20133; default 1; 2 = retina)"},theme:{type:"string",description:"Named theme to render with (default: the board's pin, else the folder default)"},w:{type:"string",description:"Viewport width for screen targets (default: first preset)"},h:{type:"string",description:"Viewport height for screen targets (default: first preset)"},yes:{type:"boolean",description:"Export even when a component fails to render (required without an interactive terminal)"}},async run({args}){let folder=await resolveDesign(args.design,"export",{designFlag:"--design"}),pipeline=await loadPipeline(folder),design=pipeline.design,mode=args.mode??"light";if(!["light","dark","compare"].includes(mode))fail("export",`--mode must be light, dark, or compare \u2014 got '${args.mode}'`);let scale=args.scale?Number(args.scale):1;if(!Number.isFinite(scale)||scale<0.25||scale>3)fail("export",`--scale must be between 0.25 and 3 \u2014 got '${args.scale}'`);let targetId=args.target;if(!targetId){let options=[...[...design.boards.values()].map((b)=>({value:b.id,label:b.name,hint:`board \xB7 ${b.frames.length} frame${b.frames.length===1?"":"s"}`})),...[...design.screens.values()].map((s)=>({value:s.id,label:s.name||s.id,hint:"screen"}))];if(options.length===0)fail("export",`nothing to export in ${folder}.`);if(!process.stdin.isTTY)fail("export",`pass a target: ${options.map((o)=>o.value).join(", ")} (boards and screens; frame ids work too)`);let chosen=await select({message:"Export what?",options});if(isCancel(chosen))fail("export","cancelled.");targetId=chosen}let screen=design.screens.get(targetId),framed=screen?null:findFrame(design,targetId),board=screen||framed?null:design.boards.get(targetId),kind=screen?"screen":framed?"frame":board?"board":null;if(!kind)fail("export",`no screen, frame, or board with id "${targetId}" in ${folder}. Boards: ${[...design.boards.keys()].join(", ")||"(none)"}; screens: ${[...design.screens.keys()].join(", ")||"(none)"}.`);let name=screen?.name||framed?.frame.label||(framed?design.screens.get(framed.frame.screen)?.name:void 0)||board?.name||targetId,outPath=args.to?isAbsolute(args.to)?args.to:resolve(args.to):resolve(exportFilename(name,"png")),ext=extname(outPath).toLowerCase().slice(1);if(ext!=="png"&&ext!=="pdf"&&ext!=="html")fail("export",`unsupported output extension ".${ext}" \u2014 use .png, .pdf, or .html.`);let format=ext;if(mode==="compare"&&(format!=="png"||kind==="board"))fail("export",'mode "compare" is PNG-only and not available for boards.');let preset=design.config.viewportPresets[0]??{name:"default",w:1440,h:900},viewport={w:args.w?Number(args.w):preset.w,h:args.h?Number(args.h):preset.h};await confirmRenderFailures("export",{folder:design,providers:pipeline.providers,defaultProvider:pipeline.defaultProvider},screensForExportTarget(design,kind,targetId),args.yes===!0);let opts={mode,scale,...args.theme?{theme:args.theme}:{}},assetOrigin,live=format==="html"?null:await pipeline.liveModule(),notes=[],p={folder:design,providers:pipeline.providers,defaultProvider:pipeline.defaultProvider,snapshotCss:async()=>pipeline.snapshotCss,assetOrigin:()=>assetOrigin,canvasBundleFor:pipeline.capture.forScreen,appCss:pipeline.capture.appCss,mountProblems:pipeline.capture.problems,warn:(message)=>{if(!notes.includes(message))notes.push(message)},liveBundleUrl:()=>live?.code?LIVE_BUNDLE_PATH:void 0},produce=async()=>{if(kind==="screen"&&screen){if(format==="html"){let out=await exportScreenHtml(p,screen,{dark:mode==="dark",...args.theme?{theme:args.theme}:{},viewport});return{bytes:out.html,warnings:out.warnings}}if(format==="pdf")return{bytes:await exportScreenPdf(p,screen,{...opts,viewport}),warnings:[]};return{bytes:await exportScreenPng(p,screen,{...opts,viewport}),warnings:[]}}if(kind==="frame"&&framed){if(format==="html"){let out=await exportFrameHtml(p,framed.board,framed.frame,opts);return{bytes:out.html,warnings:out.warnings}}return{bytes:format==="pdf"?await exportFramePdf(p,framed.board,framed.frame,opts):await exportFramePng(p,framed.board,framed.frame,opts),warnings:[]}}if(!board)fail("export","internal: target resolution failed");if(format==="html"){let out=await exportBoardHtml(p,board,opts);return{bytes:out.html,warnings:out.warnings}}return{bytes:format==="pdf"?await exportBoardPdf(p,board,opts):await exportBoardPng(p,board,opts),warnings:[]}},result;try{if(format==="html"&&await chromiumExecutable()===null)result=await produce();else if(format==="html")await withAssetServer(folder,null,async(baseHref)=>{assetOrigin=baseHref,result=await produce()},{bundle:pipeline.capture.serve,host:hostFilesFetch(()=>folder)});else await withAssetServer(folder,live?.code??null,async(baseHref)=>{assetOrigin=baseHref,await captureWithBrowserSetup("export",async()=>{result=await produce()})},{bundle:pipeline.capture.serve,host:hostFilesFetch(()=>folder)})}finally{await closePooledBrowser()}if(!result)fail("export","capture produced no output");if(typeof result.bytes==="string")await writeText(outPath,result.bytes);else await Bun.write(outPath,result.bytes);console.log(`velloo export: wrote ${outPath} (${kind}=${targetId}, mode=${mode})`);for(let warning of[...live?.warnings??[],...notes,...result.warnings])console.log(` note: ${warning}`)}});export{export_default as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{ELEMENT_TAG,helperDescriptors,require_react_jsx_dev_runtime_development,STACK_ALIGN_CLASS,STACK_JUSTIFY_CLASS,CONTAINER_WIDTH_CLASS,CARD_CLASS,BUTTON_BASE_CLASS,BUTTON_VARIANT_CLASS,INPUT_CLASS,TextRunContext,textTag,helpersRegistry,helperSourcePath}from"./chunk-brnkprt5.js";import{headingInlineStyle,textInlineStyle}from"./chunk-5x4nw0zz.js";import{TAILWIND_CLASSNAME,require_react_development}from"./chunk-ex36z3b3.js";import{__toESM}from"./chunk-2smsg2ct.js";import{noLibVersion}from"./chunk-cxe6jjwj.js";import{resolveProviderSrcDir}from"./chunk-v6c3h9ft.js";import{dirname,join}from"path";import{fileURLToPath}from"url";var NONE_INTRO=["**This folder has no component library** \u2014 only bare primitives wrapping plain HTML: `Box`/`Stack`/`Container` for layout, `Card`, `Button`, `Input`, plus the velloo helpers (`Heading`/`Text`, `Image`, `Gradient`, `Layer`, `SVG`, `Divider`, `Placeholder`, `Icon`). The primitives stop there: for a `Badge`/`Tabs`/`Dialog`, use the app's own component when `list_components` shows one on a Repo shelf, else build it from primitives or a snippet. Call `list_components` for the exact set. Styling is **Tailwind classes**.",""],NONE_INLINE_INTRO=["**This folder has no component library and no CSS framework** \u2014 bare primitives wrapping plain HTML (`Box`/`Stack`/`Container`, `Card`, `Button`, `Input`) plus the velloo helpers (`Heading`/`Text`, `Image`, `Icon`, `SVG`, `Divider`, `Gradient`, `Layer`, `Placeholder`). The primitives stop there: for a `Badge`/`Tabs`/`Dialog`, use the app's own component when `list_components` shows one on a Repo shelf, else build it from primitives or a snippet. Call `list_components` for the exact set.","",'**Style through inline `style` objects.** `update_props { style: { display: "flex", gap: "16px", padding: "24px", borderRadius: "8px", color: "var(--color-foreground)" } }` \u2014 a plain React style object (merges shallowly; an inner `null` drops a key, `style: null` clears). Reference theme tokens as CSS variables (`var(--color-primary)`, `var(--radius)`) from `get_theme` so the design stays themable. `emit_code` emits `style={{\u2026}}` on plain elements \u2014 no imports, no Tailwind. Tailwind utility diagnostics do not apply.',""];var React=__toESM(require_react_development(),1),jsx_dev_runtime=__toESM(require_react_jsx_dev_runtime_development(),1);import{clsx}from"clsx";var Box=React.forwardRef(({as,className,...rest},ref)=>React.createElement(typeof as==="string"&&ELEMENT_TAG.test(as)?as:"div",{ref,className:clsx(className),...rest}));Box.displayName="Box";var Stack=React.forwardRef(({direction="col",gap=4,align,justify,className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx("flex",direction==="row"?"flex-row":"flex-col",`gap-${gap}`,align?STACK_ALIGN_CLASS[align]:void 0,justify?STACK_JUSTIFY_CLASS[justify]:void 0,className),...rest},void 0,!1,void 0,this));Stack.displayName="Stack";var Container=React.forwardRef(({size="md",className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx("mx-auto w-full px-4",CONTAINER_WIDTH_CLASS[size],className),...rest},void 0,!1,void 0,this));Container.displayName="Container";var Button=React.forwardRef(({variant="default",className,type,...rest},ref)=>jsx_dev_runtime.jsxDEV("button",{ref,type:type??"button",className:clsx(BUTTON_BASE_CLASS,BUTTON_VARIANT_CLASS[variant],className),...rest},void 0,!1,void 0,this));Button.displayName="Button";var Input=React.forwardRef(({className,type="text",value,onChange,...rest},ref)=>jsx_dev_runtime.jsxDEV("input",{ref,type,value,onChange,readOnly:value!==void 0&&onChange===void 0||rest.readOnly,className:clsx(INPUT_CLASS,className),...rest},void 0,!1,void 0,this));Input.displayName="Input";var Card=React.forwardRef(({className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx(CARD_CLASS,className),...rest},void 0,!1,void 0,this));Card.displayName="Card";var REUSED_HELPER_IDS=["Heading","Text","Prose","Icon","SVG","Image","Layer","Divider","Gradient","Placeholder"],registry={Box,Stack,Container,Card,Button,Input,...helpersRegistry(REUSED_HELPER_IDS)};var PRIMITIVE_DESCRIPTORS=[{id:"Box",category:"ui",source:"velloo",plainElement:!0,props:[{name:"as",type:"string",optional:!0,control:"string"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Stack",category:"ui",source:"velloo",props:[{name:"direction",type:'"row" | "col" | undefined',optional:!0,control:"enum",enumValues:["row","col"],defaultValue:"col"},{name:"gap",type:"number | undefined",optional:!0,control:"number",defaultValue:"4"},{name:"align",type:'"start" | "center" | "end" | "stretch" | undefined',optional:!0,control:"enum",enumValues:["start","center","end","stretch"]},{name:"justify",type:'"start" | "center" | "end" | "between" | "around" | undefined',optional:!0,control:"enum",enumValues:["start","center","end","between","around"]},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Container",category:"ui",source:"velloo",props:[{name:"size",type:'"sm" | "md" | "lg" | "xl" | "full" | undefined',optional:!0,control:"enum",enumValues:["sm","md","lg","xl","full"],defaultValue:"md"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Card",category:"ui",source:"velloo",props:[{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Button",category:"ui",source:"velloo",props:[{name:"variant",type:'"default" | "ghost" | "outline" | undefined',optional:!0,control:"enum",enumValues:["default","ghost","outline"],defaultValue:"default"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Input",category:"ui",source:"velloo",props:[{name:"placeholder",type:"string | undefined",optional:!0,control:"string"},{name:"value",type:"string | undefined",optional:!0,control:"string"},{name:"type",type:"string | undefined",optional:!0,control:"string",defaultValue:"text"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]}],NONE_MANIFEST2=[...PRIMITIVE_DESCRIPTORS,...helperDescriptors(REUSED_HELPER_IDS)];var React2=__toESM(require_react_development(),1),jsx_dev_runtime2=__toESM(require_react_jsx_dev_runtime_development(),1);function merge(defaults,authored){return authored?{...defaults,...authored}:defaults}var space=(n)=>`${n*0.25}rem`,Box2=React2.forwardRef(({as,...rest},ref)=>React2.createElement(typeof as==="string"&&ELEMENT_TAG.test(as)?as:"div",{ref,...rest}));Box2.displayName="Box";var alignStyle={start:"flex-start",center:"center",end:"flex-end",stretch:"stretch"},justifyStyle={start:"flex-start",center:"center",end:"flex-end",between:"space-between",around:"space-around"},Stack2=React2.forwardRef(({direction="col",gap=4,align,justify,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({display:"flex",flexDirection:direction==="row"?"row":"column",gap:space(gap),...align?{alignItems:alignStyle[align]}:{},...justify?{justifyContent:justifyStyle[justify]}:{}},style),...rest},void 0,!1,void 0,this));Stack2.displayName="Stack";var containerMaxWidth={sm:"640px",md:"768px",lg:"1024px",xl:"1280px",full:"100%"},Container2=React2.forwardRef(({size="md",style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({marginInline:"auto",width:"100%",paddingInline:"1rem",maxWidth:containerMaxWidth[size]},style),...rest},void 0,!1,void 0,this));Container2.displayName="Container";var buttonVariantStyle={default:{background:"var(--color-foreground)",color:"var(--color-background)"},ghost:{background:"transparent",color:"var(--color-foreground)"},outline:{background:"transparent",color:"var(--color-foreground)",border:"1px solid var(--color-border)"}},Button2=React2.forwardRef(({variant="default",type,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("button",{ref,type:type??"button",style:merge({display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"0.5rem",borderRadius:"var(--radius)",padding:"0.5rem 1rem",fontSize:"0.875rem",fontWeight:500,cursor:"pointer",...buttonVariantStyle[variant]},style),...rest},void 0,!1,void 0,this));Button2.displayName="Button";var Input2=React2.forwardRef(({type="text",value,onChange,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("input",{ref,type,value,onChange,readOnly:value!==void 0&&onChange===void 0||rest.readOnly,style:merge({display:"block",width:"100%",borderRadius:"var(--radius)",border:"1px solid var(--color-input)",background:"var(--color-background)",padding:"0.5rem 0.75rem",fontSize:"0.875rem"},style),...rest},void 0,!1,void 0,this));Input2.displayName="Input";var Card2=React2.forwardRef(({style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({borderRadius:"var(--radius)",border:"1px solid var(--color-border)",background:"var(--color-card)",color:"var(--color-card-foreground)",padding:"1.5rem",boxShadow:"0 1px 2px 0 rgb(0 0 0 / 0.05)"},style),...rest},void 0,!1,void 0,this));Card2.displayName="Card";var Heading=React2.forwardRef(({level=1,style,...rest},ref)=>{let Tag=`h${level}`;return jsx_dev_runtime2.jsxDEV(Tag,{ref,style:merge(headingInlineStyle(level),style),...rest},void 0,!1,void 0,this)});Heading.displayName="Heading";var Text=React2.forwardRef(({variant,style,...rest},ref)=>{let run=React2.useContext(TextRunContext);return jsx_dev_runtime2.jsxDEV(TextRunContext.Provider,{value:!0,children:React2.createElement(textTag(run),{ref,style:merge(textInlineStyle(variant,run),style),...rest})},void 0,!1,void 0,this)});Text.displayName="Text";var REUSED_HELPER_IDS2=["Prose","Icon","SVG","Image","Layer","Divider","Gradient","Placeholder"],inlineRegistry={Box:Box2,Stack:Stack2,Container:Container2,Card:Card2,Button:Button2,Input:Input2,Heading,Text,...helpersRegistry(REUSED_HELPER_IDS2)};var PRIMITIVES=new Set(["Box","Stack","Container","Card","Button","Input"]),INLINE_TYPOGRAPHY=new Set(["Heading","Text"]),here=dirname(fileURLToPath(import.meta.url)),srcDir=resolveProviderSrcDir(here,"provider-none",process.env.VELLOO_NOLIB_SRC),entryCssPath2=join(srcDir,"tailwind-entry.css"),componentsDir2=srcDir;async function loadManifest(){return NONE_MANIFEST2}function createProvider2(){return{id:"none",version:noLibVersion,componentsDir:componentsDir2,styleEntryPath:entryCssPath2,registry,loadManifest,label:`none ${noLibVersion}`,styleChannel:TAILWIND_CLASSNAME,styleChannels:["tailwind-classname","style"],mcpIntro:(channel)=>[...channel==="style"?NONE_INLINE_INTRO:NONE_INTRO],registryForChannel:(kind)=>kind==="style"?inlineRegistry:registry,canvasBundleSpec:{styleRuntime:{kind:"none"},onlyWithRepository:!0,components:(ids,context)=>{let inline=context?.channel==="style";return ids.flatMap((id)=>{let own=PRIMITIVES.has(id)||inline&&INLINE_TYPOGRAPHY.has(id)?join(srcDir,inline?"components-inline.tsx":"components.tsx"):helperSourcePath(id);return own?[{id,sources:[{importPath:own,exportName:id,fidelity:"exact",note:"Velloo primitive, mounted beside the app's components."}]}]:[]})}}}}
|
|
2
|
+
import{ELEMENT_TAG,helperDescriptors,require_react_jsx_dev_runtime_development,STACK_ALIGN_CLASS,STACK_JUSTIFY_CLASS,CONTAINER_WIDTH_CLASS,CARD_CLASS,BUTTON_BASE_CLASS,BUTTON_VARIANT_CLASS,INPUT_CLASS,TextRunContext,textTag,helpersRegistry,helperSourcePath}from"./chunk-9g45c5md.js";import{headingInlineStyle,textInlineStyle}from"./chunk-xxw67jpk.js";import{TAILWIND_CLASSNAME,require_react_development}from"./chunk-xg49s85z.js";import{__toESM}from"./chunk-2smsg2ct.js";import{noLibVersion}from"./chunk-cxe6jjwj.js";import{resolveProviderSrcDir}from"./chunk-v6c3h9ft.js";import{dirname,join}from"path";import{fileURLToPath}from"url";var NONE_INTRO=["**This folder has no component library** \u2014 only bare primitives wrapping plain HTML: `Box`/`Stack`/`Container` for layout, `Card`, `Button`, `Input`, plus the velloo helpers (`Heading`/`Text`, `Image`, `Gradient`, `Layer`, `SVG`, `Divider`, `Placeholder`, `Icon`). The primitives stop there: for a `Badge`/`Tabs`/`Dialog`, use the app's own component when `list_components` shows one on a Repo shelf, else build it from primitives or a snippet. Call `list_components` for the exact set. Styling is **Tailwind classes**.",""],NONE_INLINE_INTRO=["**This folder has no component library and no CSS framework** \u2014 bare primitives wrapping plain HTML (`Box`/`Stack`/`Container`, `Card`, `Button`, `Input`) plus the velloo helpers (`Heading`/`Text`, `Image`, `Icon`, `SVG`, `Divider`, `Gradient`, `Layer`, `Placeholder`). The primitives stop there: for a `Badge`/`Tabs`/`Dialog`, use the app's own component when `list_components` shows one on a Repo shelf, else build it from primitives or a snippet. Call `list_components` for the exact set.","",'**Style through inline `style` objects.** `update_props { style: { display: "flex", gap: "16px", padding: "24px", borderRadius: "8px", color: "var(--color-foreground)" } }` \u2014 a plain React style object (merges shallowly; an inner `null` drops a key, `style: null` clears). Reference theme tokens as CSS variables (`var(--color-primary)`, `var(--radius)`) from `get_theme` so the design stays themable. `emit_code` emits `style={{\u2026}}` on plain elements \u2014 no imports, no Tailwind. Tailwind utility diagnostics do not apply.',""];var React=__toESM(require_react_development(),1),jsx_dev_runtime=__toESM(require_react_jsx_dev_runtime_development(),1);import{clsx}from"clsx";var Box=React.forwardRef(({as,className,...rest},ref)=>React.createElement(typeof as==="string"&&ELEMENT_TAG.test(as)?as:"div",{ref,className:clsx(className),...rest}));Box.displayName="Box";var Stack=React.forwardRef(({direction="col",gap=4,align,justify,className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx("flex",direction==="row"?"flex-row":"flex-col",`gap-${gap}`,align?STACK_ALIGN_CLASS[align]:void 0,justify?STACK_JUSTIFY_CLASS[justify]:void 0,className),...rest},void 0,!1,void 0,this));Stack.displayName="Stack";var Container=React.forwardRef(({size="md",className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx("mx-auto w-full px-4",CONTAINER_WIDTH_CLASS[size],className),...rest},void 0,!1,void 0,this));Container.displayName="Container";var Button=React.forwardRef(({variant="default",className,type,...rest},ref)=>jsx_dev_runtime.jsxDEV("button",{ref,type:type??"button",className:clsx(BUTTON_BASE_CLASS,BUTTON_VARIANT_CLASS[variant],className),...rest},void 0,!1,void 0,this));Button.displayName="Button";var Input=React.forwardRef(({className,type="text",value,onChange,...rest},ref)=>jsx_dev_runtime.jsxDEV("input",{ref,type,value,onChange,readOnly:value!==void 0&&onChange===void 0||rest.readOnly,className:clsx(INPUT_CLASS,className),...rest},void 0,!1,void 0,this));Input.displayName="Input";var Card=React.forwardRef(({className,...rest},ref)=>jsx_dev_runtime.jsxDEV("div",{ref,className:clsx(CARD_CLASS,className),...rest},void 0,!1,void 0,this));Card.displayName="Card";var REUSED_HELPER_IDS=["Heading","Text","Prose","Icon","SVG","Image","Layer","Divider","Gradient","Placeholder"],registry={Box,Stack,Container,Card,Button,Input,...helpersRegistry(REUSED_HELPER_IDS)};var PRIMITIVE_DESCRIPTORS=[{id:"Box",category:"ui",source:"velloo",plainElement:!0,props:[{name:"as",type:"string",optional:!0,control:"string"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Stack",category:"ui",source:"velloo",props:[{name:"direction",type:'"row" | "col" | undefined',optional:!0,control:"enum",enumValues:["row","col"],defaultValue:"col"},{name:"gap",type:"number | undefined",optional:!0,control:"number",defaultValue:"4"},{name:"align",type:'"start" | "center" | "end" | "stretch" | undefined',optional:!0,control:"enum",enumValues:["start","center","end","stretch"]},{name:"justify",type:'"start" | "center" | "end" | "between" | "around" | undefined',optional:!0,control:"enum",enumValues:["start","center","end","between","around"]},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Container",category:"ui",source:"velloo",props:[{name:"size",type:'"sm" | "md" | "lg" | "xl" | "full" | undefined',optional:!0,control:"enum",enumValues:["sm","md","lg","xl","full"],defaultValue:"md"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Card",category:"ui",source:"velloo",props:[{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Button",category:"ui",source:"velloo",props:[{name:"variant",type:'"default" | "ghost" | "outline" | undefined',optional:!0,control:"enum",enumValues:["default","ghost","outline"],defaultValue:"default"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]},{id:"Input",category:"ui",source:"velloo",props:[{name:"placeholder",type:"string | undefined",optional:!0,control:"string"},{name:"value",type:"string | undefined",optional:!0,control:"string"},{name:"type",type:"string | undefined",optional:!0,control:"string",defaultValue:"text"},{name:"className",type:"string | undefined",optional:!0,control:"string"}]}],NONE_MANIFEST2=[...PRIMITIVE_DESCRIPTORS,...helperDescriptors(REUSED_HELPER_IDS)];var React2=__toESM(require_react_development(),1),jsx_dev_runtime2=__toESM(require_react_jsx_dev_runtime_development(),1);function merge(defaults,authored){return authored?{...defaults,...authored}:defaults}var space=(n)=>`${n*0.25}rem`,Box2=React2.forwardRef(({as,...rest},ref)=>React2.createElement(typeof as==="string"&&ELEMENT_TAG.test(as)?as:"div",{ref,...rest}));Box2.displayName="Box";var alignStyle={start:"flex-start",center:"center",end:"flex-end",stretch:"stretch"},justifyStyle={start:"flex-start",center:"center",end:"flex-end",between:"space-between",around:"space-around"},Stack2=React2.forwardRef(({direction="col",gap=4,align,justify,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({display:"flex",flexDirection:direction==="row"?"row":"column",gap:space(gap),...align?{alignItems:alignStyle[align]}:{},...justify?{justifyContent:justifyStyle[justify]}:{}},style),...rest},void 0,!1,void 0,this));Stack2.displayName="Stack";var containerMaxWidth={sm:"640px",md:"768px",lg:"1024px",xl:"1280px",full:"100%"},Container2=React2.forwardRef(({size="md",style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({marginInline:"auto",width:"100%",paddingInline:"1rem",maxWidth:containerMaxWidth[size]},style),...rest},void 0,!1,void 0,this));Container2.displayName="Container";var buttonVariantStyle={default:{background:"var(--color-foreground)",color:"var(--color-background)"},ghost:{background:"transparent",color:"var(--color-foreground)"},outline:{background:"transparent",color:"var(--color-foreground)",border:"1px solid var(--color-border)"}},Button2=React2.forwardRef(({variant="default",type,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("button",{ref,type:type??"button",style:merge({display:"inline-flex",alignItems:"center",justifyContent:"center",gap:"0.5rem",borderRadius:"var(--radius)",padding:"0.5rem 1rem",fontSize:"0.875rem",fontWeight:500,cursor:"pointer",...buttonVariantStyle[variant]},style),...rest},void 0,!1,void 0,this));Button2.displayName="Button";var Input2=React2.forwardRef(({type="text",value,onChange,style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("input",{ref,type,value,onChange,readOnly:value!==void 0&&onChange===void 0||rest.readOnly,style:merge({display:"block",width:"100%",borderRadius:"var(--radius)",border:"1px solid var(--color-input)",background:"var(--color-background)",padding:"0.5rem 0.75rem",fontSize:"0.875rem"},style),...rest},void 0,!1,void 0,this));Input2.displayName="Input";var Card2=React2.forwardRef(({style,...rest},ref)=>jsx_dev_runtime2.jsxDEV("div",{ref,style:merge({borderRadius:"var(--radius)",border:"1px solid var(--color-border)",background:"var(--color-card)",color:"var(--color-card-foreground)",padding:"1.5rem",boxShadow:"0 1px 2px 0 rgb(0 0 0 / 0.05)"},style),...rest},void 0,!1,void 0,this));Card2.displayName="Card";var Heading=React2.forwardRef(({level=1,style,...rest},ref)=>{let Tag=`h${level}`;return jsx_dev_runtime2.jsxDEV(Tag,{ref,style:merge(headingInlineStyle(level),style),...rest},void 0,!1,void 0,this)});Heading.displayName="Heading";var Text=React2.forwardRef(({variant,style,...rest},ref)=>{let run=React2.useContext(TextRunContext);return jsx_dev_runtime2.jsxDEV(TextRunContext.Provider,{value:!0,children:React2.createElement(textTag(run),{ref,style:merge(textInlineStyle(variant,run),style),...rest})},void 0,!1,void 0,this)});Text.displayName="Text";var REUSED_HELPER_IDS2=["Prose","Icon","SVG","Image","Layer","Divider","Gradient","Placeholder"],inlineRegistry={Box:Box2,Stack:Stack2,Container:Container2,Card:Card2,Button:Button2,Input:Input2,Heading,Text,...helpersRegistry(REUSED_HELPER_IDS2)};var PRIMITIVES=new Set(["Box","Stack","Container","Card","Button","Input"]),INLINE_TYPOGRAPHY=new Set(["Heading","Text"]),here=dirname(fileURLToPath(import.meta.url)),srcDir=resolveProviderSrcDir(here,"provider-none",process.env.VELLOO_NOLIB_SRC),entryCssPath2=join(srcDir,"tailwind-entry.css"),componentsDir2=srcDir;async function loadManifest(){return NONE_MANIFEST2}function createProvider2(){return{id:"none",version:noLibVersion,componentsDir:componentsDir2,styleEntryPath:entryCssPath2,registry,loadManifest,label:`none ${noLibVersion}`,styleChannel:TAILWIND_CLASSNAME,styleChannels:["tailwind-classname","style"],themeRoles:["background","foreground","card","muted","border","input"],mcpIntro:(channel)=>[...channel==="style"?NONE_INLINE_INTRO:NONE_INTRO],registryForChannel:(kind)=>kind==="style"?inlineRegistry:registry,canvasBundleSpec:{styleRuntime:{kind:"none"},onlyWithRepository:!0,components:(ids,context)=>{let inline=context?.channel==="style";return ids.flatMap((id)=>{let own=PRIMITIVES.has(id)||inline&&INLINE_TYPOGRAPHY.has(id)?join(srcDir,inline?"components-inline.tsx":"components.tsx"):helperSourcePath(id);return own?[{id,sources:[{importPath:own,exportName:id,fidelity:"exact",note:"Velloo primitive, mounted beside the app's components."}]}]:[]})}}}}
|
|
3
3
|
export{NONE_MANIFEST2,inlineRegistry,entryCssPath2,componentsDir2,createProvider2};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{styleObjectFromCss}from"./chunk-
|
|
2
|
+
import{styleObjectFromCss}from"./chunk-xxw67jpk.js";import{NONE_MANIFEST2,inlineRegistry,entryCssPath2,componentsDir2}from"./chunk-majd3gx9.js";import{STYLE_PROP,require_react_development}from"./chunk-xg49s85z.js";import{__toESM}from"./chunk-2smsg2ct.js";import{HTML_VERSION}from"./chunk-6k05kqnc.js";var import_react=__toESM(require_react_development(),1),SAFE_TAG=/^(?:a|abbr|address|article|aside|b|bdi|bdo|blockquote|br|button|caption|circle|cite|clipPath|code|col|colgroup|data|dd|defs|del|details|dfn|div|dl|dt|ellipse|em|fieldset|figcaption|figure|footer|form|g|h[1-6]|header|hr|i|img|input|ins|kbd|label|legend|li|line|linearGradient|main|mark|mask|meter|nav|ol|optgroup|option|output|p|path|picture|polygon|polyline|pre|progress|q|radialGradient|rect|s|samp|section|select|small|source|span|stop|strong|sub|summary|sup|svg|table|tbody|td|text|textarea|tfoot|th|thead|time|tr|tspan|u|ul|var|wbr)$/,URL_ATTRIBUTES=new Set(["href","src","action","formaction","poster","cite","xlinkhref","xlink:href"]),SCRIPT_URL=/^(?:javascript|vbscript):|^data:text\/html/i,withoutControls=(value)=>[...value].filter((char)=>char.charCodeAt(0)>32).join(""),REACT_PROP={class:"className",for:"htmlFor",autocomplete:"autoComplete",autofocus:"autoFocus",tabindex:"tabIndex",readonly:"readOnly",maxlength:"maxLength",minlength:"minLength",colspan:"colSpan",rowspan:"rowSpan",enctype:"encType",novalidate:"noValidate",datetime:"dateTime",srcset:"srcSet",crossorigin:"crossOrigin",accesskey:"accessKey",contenteditable:"contentEditable",spellcheck:"spellCheck",formaction:"formAction",formmethod:"formMethod",inputmode:"inputMode",referrerpolicy:"referrerPolicy"};function safeAttributeValue(name,value){let key=name.toLowerCase();if(key.startsWith("on")||key==="dangerouslysetinnerhtml")return!1;if(URL_ATTRIBUTES.has(key)&&typeof value==="string")return!SCRIPT_URL.test(withoutControls(value));return!0}function safeTag(component,as){if(!SAFE_TAG.test(as))throw Error(`${component}: unsupported HTML tag ${JSON.stringify(as)}`);return as}function nativeAttributes(props){return Object.fromEntries(Object.entries(props).map(([name,value])=>[REACT_PROP[name]??name,value]).filter(([name,value])=>safeAttributeValue(name,value)).flatMap(([name,value])=>{if(name!=="style"||typeof value!=="string")return[[name,value]];let style=styleObjectFromCss(value);return style?[[name,style]]:[]}))}function Html({as="div",children,...props}){return import_react.createElement(safeTag("Html",as),nativeAttributes(props),children)}var registry={...inlineRegistry,Html};var htmlDescriptors=[{id:"Html",category:"ui",source:"velloo",group:"layout",family:"Html",allowUnknownProps:!0,designModeNotes:"Use for a native HTML element. Set as to a semantic tag and pass ordinary HTML or hx-* attributes as props.",props:[{name:"as",type:"string",optional:!0,control:"string",defaultValue:"div"},{name:"className",type:"string",optional:!0,control:"string"},{name:"style",type:"CSSProperties",optional:!0,control:"string"},{name:"children",type:"ReactNode",optional:!0,control:"string"}]}],HTML_MANIFEST=[...NONE_MANIFEST2,...htmlDescriptors],HTML_INTRO=["**This is a server-rendered HTML/htmx app.** Compose semantic HTML with `Html` nodes (`as=\"form\"`, \u2026), styled by the app's own CSS classes or inline `style` \u2014 there is no Tailwind; new classes need CSS authored in the app. Give forms and controls the real `hx-*` attributes: the canvas never fires them, and `emit_code` keeps them in the native HTML it returns for the app's templates.","","A design never contacts the running app: it is styled by copies of the app's stylesheets, which `store_host_files` refreshes from source or from a capture (including built CSS a `screenshot` reports missing). Reference the app's files by their real paths (`src=\"/static/logo.png\"`), not as Velloo assets. Theme tokens are CSS variables (`var(--color-primary)`); `emit_theme` writes the stylesheet that defines them.","","To reproduce a page, capture it from the running app with `start_capture_session` (the user signs in if needed), rebuild it from `get_capture` with the content written into the nodes, and verify with `compare_to_url { captureId }`.","","On a form, a custom `hx-trigger` replaces htmx's default submit trigger \u2014 include `submit` when a submit button must swap a response instead of navigating.",""];function createProvider(){return{id:"html",version:HTML_VERSION,label:"HTML + htmx",componentsDir:componentsDir2,styleEntryPath:entryCssPath2,registry,loadManifest:async()=>HTML_MANIFEST,styleChannel:STYLE_PROP,styleChannels:["style"],themeRoles:["background","foreground","card","muted","border","input"],registryForChannel:()=>registry,mcpIntro:()=>HTML_INTRO,hostStylesheets:!0,codegenFormat:"html",elementComponent:"Html"}}export{createProvider};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{CURRENT_SCHEMA_VERSION}from"./chunk-
|
|
2
|
+
import{CURRENT_SCHEMA_VERSION}from"./chunk-xxw67jpk.js";import{localDesignOf,recordedDesignName}from"./chunk-9g45c5md.js";import{AGENTS,designArgumentFor,agentRootCandidates,writeAgentConfig,refreshAgentArtifacts}from"./chunk-07fxzrx2.js";import{daemonRoot,readLock,isLive,stopDaemon}from"./chunk-qgbat4fv.js";import{fail}from"./chunk-s23gtejf.js";import{installedVellooBin,upgradeInstalledVelloo}from"./chunk-d19ttv1a.js";import{createProgress}from"./chunk-pjtg3wnm.js";import{upgradeFolder}from"./chunk-ez720ked.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign,checkoutDesigns}from"./chunk-6w42sr61.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM,defineCommand}from"./chunk-2smsg2ct.js";import{resolve}from"path";var import_picocolors=__toESM(require_picocolors(),1);import{readFile}from"fs/promises";import{homedir}from"os";var isStrings=(value)=>Array.isArray(value)&&value.every((item)=>typeof item==="string");function asEntry(value){if(value===null||typeof value!=="object")return null;let{command,args}=value;return typeof command==="string"&&isStrings(args)?{command,args}:null}function readStdioEntry(content,format){try{switch(format){case"json":return asEntry(JSON.parse(content).mcpServers?.velloo);case"vscode-json":return asEntry(JSON.parse(content).servers?.velloo);case"opencode-json":{let command=JSON.parse(content).mcp?.velloo?.command;return isStrings(command)&&command[0]?{command:command[0],args:command.slice(1)}:null}case"codex-toml":return asEntry(Bun.TOML.parse(content).mcp_servers?.velloo);case"continue-block":return asEntry(Bun.YAML.parse(content).mcpServers?.[0]);case"continue-config":return null}}catch{return null}}async function repinAgentConfigs(opts){if(localDesignOf(opts.designFolder))return[];let homeDir=opts.homeDir??homedir(),names=new Set(opts.names),rewritten=[];for(let projectRoot of opts.projectRoots){let designArg=await designArgumentFor(projectRoot,opts.designFolder),desired=designArg?["mcp",designArg]:["mcp"];for(let agent of Object.values(AGENTS)){if(agent.scope!=="project"||agent.gui)continue;let path=agent.path(projectRoot,homeDir),content;try{content=await readFile(path,"utf8")}catch{continue}let entry=readStdioEntry(content,agent.format),pinned=entry?.args.length===2&&entry.args[0]==="mcp"?entry.args[1]:void 0;if(!entry||pinned===void 0||!names.has(pinned)||pinned===desired[1])continue;await writeAgentConfig(projectRoot,agent,{transport:"stdio",command:entry.command,args:desired},homeDir),rewritten.push(path)}}return rewritten}async function targetFolders(arg){if(arg)return[await resolveDesign(arg,"upgrade",{requireConfig:!0})];return checkoutDesigns(resolve("."))}var upgrade_default=defineCommand({meta:{name:"upgrade",description:"Upgrade Velloo and migrate designs to the current format \u2014 every design in this checkout, or the one named"},args:{design:{type:"positional",required:!1,description:DESIGN_ARG_DESCRIPTION},"dry-run":{type:"boolean",default:!1,description:"Show what would change without writing"},check:{type:"boolean",default:!1,description:"Check for a Velloo update without installing it"},"binary-only":{type:"boolean",default:!1,description:"Upgrade the Velloo installation and leave the designs alone"},"design-only":{type:"boolean",default:!1,description:"Migrate the designs with this Velloo, without self-upgrading first (same as `velloo design upgrade`)"},skills:{type:"boolean",default:!0,description:"Also refresh the installed agent skills / plugin / rules to this velloo's versions"}},async run({args}){let dryRun=args["dry-run"]||args.check,folders=args["binary-only"]?[]:await targetFolders(args.design),outcome=null;if(!(args["design-only"]||args["folder-only"]===!0))try{outcome=await upgradeInstalledVelloo({checkOnly:dryRun})}catch(error){let message=error instanceof Error?error.message:String(error);if(folders.length===0)fail("upgrade",message);console.log(import_picocolors.default.dim(`velloo: skipping the self-upgrade \u2014 ${message}`))}if(folders.length===0)return;if(outcome?.upgraded){let bin=installedVellooBin();if(bin){for(let folder of folders){let argv=[bin,"upgrade",folder,"--design-only",...args.skills?[]:["--no-skills"]];if(await Bun.spawn(argv,{stdin:"inherit",stdout:"inherit",stderr:"inherit",env:{...process.env,VELLOO_DISABLE_UPDATE_CHECK:"1"}}).exited!==0)fail("upgrade",`the upgraded velloo could not migrate ${folder}`)}return}console.log(import_picocolors.default.dim(`velloo: could not locate the upgraded velloo \u2014 run \`velloo upgrade\` again to migrate ${folders.length===1?"the design":"the designs"}.`));return}for(let folder of folders)await migrateFolder2(folder,{dryRun,skills:args.skills})}});async function migrateFolder2(folder,opts){let{dryRun}=opts,progress=createProgress();progress.start(dryRun?"checking upgrade":"preparing upgrade");let stopped=!1,result;try{if(!dryRun){let root=daemonRoot(folder),running=await readLock(root);if(running&&await isLive(running))progress.step("stopping running canvas");stopped=await stopDaemon(root)}progress.step(dryRun?"checking design folder":"upgrading design folder"),result=await upgradeFolder(folder,{dryRun})}catch(err){progress.fail("upgrade failed"),fail("upgrade",err instanceof Error?err.message:String(err))}let refreshed=[],repinned=[];try{let name=recordedDesignName(folder);if(!dryRun&&name)repinned=await repinAgentConfigs({projectRoots:await agentRootCandidates(folder),designFolder:folder,names:[name]});if(opts.skills&&!dryRun){progress.step("refreshing agent guidance");let projectRoots=await agentRootCandidates(folder);({refreshed}=await refreshAgentArtifacts({projectRoots,designFolder:folder}))}progress.succeed(dryRun?"upgrade check complete":"upgrade complete")}catch(error){throw progress.fail("upgrade failed"),error}if(stopped)console.log("velloo: stopped the running canvas for this folder.");if(result.applied.length===0){console.log(`velloo: ${folder} is already at schema version ${CURRENT_SCHEMA_VERSION}.`);for(let file of result.changedFiles)console.log(` ${dryRun?"~":"\u2713"} ${file} (designs list format)`)}else{console.log(`velloo: ${dryRun?"would migrate":"migrated"} ${folder} from schema version ${result.from} to ${result.to}:`);for(let step of result.applied)console.log(` - ${step}`);for(let file of result.changedFiles)console.log(` ${dryRun?"~":"\u2713"} ${file}`);if(!dryRun)console.log("velloo: folder validated against the current schemas.")}if(repinned.length>0){console.log(""),console.log(import_picocolors.default.green("\u2713 Agent MCP configs now find the design without naming it:"));for(let path of repinned)console.log(` ${import_picocolors.default.cyan(path)}`)}if(refreshed.length>0){console.log(""),console.log(import_picocolors.default.green("\u2713 Refreshed agent guidance to this velloo:"));for(let line of refreshed)console.log(` ${import_picocolors.default.cyan(line)}`)}}
|
|
3
3
|
export{repinAgentConfigs,upgrade_default,migrateFolder2};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{CHROMIUM_INSTALL_ARGV,CHROMIUM_FULL_INSTALL_ARGV,CHROMIUM_DEPS_INSTALL_ARGV}from"./chunk-
|
|
2
|
+
import{CHROMIUM_INSTALL_ARGV,CHROMIUM_FULL_INSTALL_ARGV,CHROMIUM_DEPS_INSTALL_ARGV}from"./chunk-xg49s85z.js";import"./chunk-xxw67jpk.js";import{fail}from"./chunk-s23gtejf.js";import{defineCommand}from"./chunk-2smsg2ct.js";async function run(argv){let code=await Bun.spawn([...argv],{stdin:"inherit",stdout:"inherit",stderr:"inherit"}).exited;if(code!==0)fail("browser install",`browser setup exited with status ${code}`)}var install=defineCommand({meta:{name:"install",description:"Install the browser used for screenshots"},args:{full:{type:"boolean",default:!1,description:"Install full Chromium instead of the smaller headless shell"},"with-deps":{type:"boolean",default:!1,description:"Also install required Linux system packages (may use sudo)"}},async run({args}){if(args["with-deps"]&&process.platform==="linux")await run(CHROMIUM_DEPS_INSTALL_ARGV);await run(args.full?CHROMIUM_FULL_INSTALL_ARGV:CHROMIUM_INSTALL_ARGV)}}),browser_default=defineCommand({meta:{name:"browser",description:"Manage the optional browser used for screenshots"},subCommands:{install}});export{browser_default as default};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{signInRequired,boardLimitReached,topUpTokens,createServer}from"./chunk-brnkprt5.js";import"./chunk-5x4nw0zz.js";import"./chunk-ex36z3b3.js";import{ok,err,GUESTS_UNAVAILABLE,GuestsResponseSchema,GuestInviteResponseSchema,GuestLinkResponseSchema,unreachable,httpFailureFrom,boardLimitFrom,describeCloudError,cloudFetch}from"./chunk-bys7pqdb.js";import{loadCredential,saveCredential,deleteCredential,fetchAccount,revokeCredential,performDeviceLogin}from"./chunk-kkvf0xk2.js";import{listPublishedDesigns,unpublishDesign,listPublishDestinations,describePublishError,PUBLISH_VIEWPORT,gitContext,publishableTeams,resolvePublishTeam,listTeams,publishDesign}from"./chunk-snak5zpr.js";import{TOOL_VERSION}from"./chunk-3m28pvzr.js";import{updateStatus,upgradeInstalledVelloo}from"./chunk-s84vxcdv.js";import{assertLoopbackHost,daemonRoot,writeLock,removeLock,readRememberedPort,rememberPort,portCandidates,registryUpsert,registryRemove}from"./chunk-xzf52wvn.js";import"./chunk-zv17t1n7.js";import{defaultCloudUrl,fetchCloudAppUrl}from"./chunk-abr2hgay.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{existsSync as existsSync2}from"fs";import{existsSync}from"fs";import{dirname,join}from"path";import{fileURLToPath}from"url";var here=dirname(fileURLToPath(import.meta.url));function resolveCanvasDist(){let devLayout=join(here,"..","dist");return[process.env.VELLOO_CANVAS_DIST,join(here,"canvas"),devLayout].filter((p)=>Boolean(p)).find((p)=>existsSync(join(p,"index.html")))??devLayout}var canvasDistPath=resolveCanvasDist();var ACCOUNT_TTL_MS=60000,ACCOUNT_TIMEOUT_MS=5000;function createCanvasAuth(cloudUrl,dependencies={}){let runDeviceLogin=dependencies.performDeviceLogin??performDeviceLogin,login={state:"idle"},pending=null,cached=null,cachedApp=null,describe=async(token,email)=>{if(cached&&cached.token===token&&Date.now()-cached.at<ACCOUNT_TTL_MS)return{account:cached.account,verified:cached.verified};let found=await fetchAccount(cloudUrl,token,ACCOUNT_TIMEOUT_MS),resolved=found.status==="ok"?{account:found.account,verified:!0}:{account:{email},verified:found.status==="rejected"?!1:null};return cached={token,at:Date.now(),...resolved},resolved},resolveAppUrl=async()=>{if(cachedApp&&Date.now()-cachedApp.at<ACCOUNT_TTL_MS)return cachedApp.url;let url=await fetchCloudAppUrl(cloudUrl,ACCOUNT_TIMEOUT_MS);return cachedApp={at:Date.now(),url},url},status=async()=>{let cred=await loadCredential(cloudUrl),appUrlP=resolveAppUrl();if(!cred?.token)return{loggedIn:!1,cloudUrl,appUrl:await appUrlP,verified:null,login};let[{account,verified},appUrl]=await Promise.all([describe(cred.token,cred.email),appUrlP]);return{loggedIn:!0,cloudUrl,appUrl,verified,login,...account?{account}:{}}};return{status,async beginLogin(){if(login.state==="pending")return status();let attempt=new AbortController;pending=attempt,login={state:"idle"};let settle=()=>{},ready=new Promise((resolve)=>{settle=resolve});return runDeviceLogin(cloudUrl,({verificationUrl,userCode,expiresIn})=>{login={state:"pending",userCode,verificationUrl,expiresAt:new Date(Date.now()+expiresIn*1000).toISOString()},settle()},attempt.signal).then(async(result)=>{await saveCredential(cloudUrl,result),cached=null,login={state:"idle"},await topUpTokens({url:cloudUrl,token:result.token},10).catch(()=>{return})}).catch((err)=>{login=attempt.signal.aborted?{state:"idle"}:{state:"error",message:err instanceof Error?err.message:String(err)}}).finally(()=>{if(pending===attempt)pending=null;settle()}),await ready,status()},async cancelLogin(){pending?.abort(),pending=null,login={state:"idle"}},async logout(){pending?.abort(),pending=null,login={state:"idle"},cached=null;let stored=await loadCredential(cloudUrl);if(stored)await revokeCredential(cloudUrl,stored.token);await deleteCredential(cloudUrl)}}}var guestsUrl=({baseUrl,slug},rest="")=>`${baseUrl}/v1/links/${encodeURIComponent(slug)}/guests${rest}`,json=(body)=>({method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(body)});async function listGuests(target){let body=await cloudFetch(guestsUrl(target),GuestsResponseSchema,{operation:"listing guests",token:target.token});return body.ok?ok(body.value.guests):body}function inviteGuest(target,guest){return cloudFetch(guestsUrl(target),GuestInviteResponseSchema,{operation:"inviting a guest",token:target.token,...json({email:guest.email,...guest.name?{name:guest.name}:{}})})}function resendGuestLink(target,guestId){return cloudFetch(guestsUrl(target,`/${encodeURIComponent(guestId)}/resend`),GuestInviteResponseSchema,{operation:"resending a guest's link",token:target.token,...json({})})}async function mintGuestLink(target,guestId){let body=await cloudFetch(guestsUrl(target,`/${encodeURIComponent(guestId)}/link`),GuestLinkResponseSchema,{operation:"making a guest link",token:target.token,...json({})});return body.ok?ok(body.value.guestUrl):body}async function removeGuest(target,guestId){let res=await fetch(guestsUrl(target,`/${encodeURIComponent(guestId)}`),{method:"DELETE",headers:{authorization:`Bearer ${target.token}`}}).catch((error)=>error);if(!(res instanceof Response))return err(unreachable(res,{url:target.baseUrl}));if(!res.ok)return err(await httpFailureFrom("removing a guest",res));return ok(void 0)}function createCanvasPublish(cloudUrl,auth){let tokenFor=async()=>(await loadCredential(cloudUrl))?.token,access=async()=>{if(!await tokenFor())return{state:"signed-out"};return(await auth.status().catch(()=>null))?.verified===!1?{state:"expired"}:{state:"ready"}},rejection=(error)=>error.kind==="LoggedOut"?signInRequired("expired",describeCloudError(error)):Error(describeCloudError(error)),guestRejection=(error)=>error.kind==="HttpFailure"&&error.status===403&&/\bguests requires\b/.test(error.detail)?Error(GUESTS_UNAVAILABLE):rejection(error),guestTarget=async(slug)=>{let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");return{baseUrl:cloudUrl,token,slug}},settled=(result)=>{if(!result.ok)throw guestRejection(result.error);return result.value},publishedAt=(value)=>{let parsed=value?Date.parse(value):Number.NaN;return Number.isFinite(parsed)?parsed:Number.NEGATIVE_INFINITY},soleTeamId=async(token)=>{let listed=await listTeams(cloudUrl,token);if(!listed.ok)return null;let resolved=resolvePublishTeam(listed.value);return resolved.ok&&resolved.value.kind==="team"?resolved.value.team.id:null};return{access,async teams(){let token=await tokenFor();if(!token)return[];let listed=await listTeams(cloudUrl,token);return listed.ok?publishableTeams(listed.value):[]},async blocked(){let token=await tokenFor();if(!token)return null;let listed=await listTeams(cloudUrl,token);if(!listed.ok)return null;let resolved=resolvePublishTeam(listed.value);return!resolved.ok&&resolved.error.kind==="NoPublishableTeam"?describePublishError(resolved.error):null},async published(){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let listed=await listPublishedDesigns({baseUrl:cloudUrl,token});if(!listed.ok)throw rejection(listed.error);return listed.value.map((design)=>({slug:design.slug,title:design.title??"",url:design.url,visibility:design.visibility,passwordProtected:design.passwordProtected,canManage:design.canManage,lastPublishedAt:design.lastPublishedAt,...design.guestCount!==void 0?{guestCount:design.guestCount}:{},...design.visibility==="private"&&design.teamName&&design.audience?.some((entry)=>entry.type==="team")?{onlyTeam:design.teamName}:{}})).sort((left,right)=>publishedAt(right.lastPublishedAt)-publishedAt(left.lastPublishedAt))},async unpublish(slug){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let removed=await unpublishDesign({baseUrl:cloudUrl,token,slug});if(!removed.ok)throw rejection(removed.error)},guests:{async list(slug){return settled(await listGuests(await guestTarget(slug))).map(canvasGuest)},async invite(slug,guest){return canvasInvite(settled(await inviteGuest(await guestTarget(slug),guest)))},async resend(slug,guestId){return canvasInvite(settled(await resendGuestLink(await guestTarget(slug),guestId)))},async link(slug,guestId){return settled(await mintGuestLink(await guestTarget(slug),guestId))},async remove(slug,guestId){settled(await removeGuest(await guestTarget(slug),guestId))}},async destinations(host){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let provenance=gitContext(host.folder.root),folderId=host.folder.config.folderId;if(!folderId){let teams=await listTeams(cloudUrl,token);if(!teams.ok)throw rejection(teams.error);let publishable=publishableTeams(teams.value);return{effectiveTeamId:publishable.length===1?publishable[0]?.id??null:null,provenance,slots:[]}}let listed=await listPublishDestinations({baseUrl:cloudUrl,token,folderId});if(!listed.ok)throw rejection(listed.error);return{...listed.value,provenance}},async run(host,request,onProgress,onWarning){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud \u2014 sign in from the account menu first.");let teamOnlyId=request.teamOnly?request.teamId??await soleTeamId(token):null;if(request.teamOnly&&!teamOnlyId)throw Error("a team-only link needs a team to publish into \u2014 choose one");let step="start",message="starting",published=await publishDesign({baseUrl:cloudUrl,token},{folder:host.folder,providers:host.providers,defaultProvider:host.defaultProvider,snapshotCss:host.snapshotCss},{boardIds:request.boardIds,...request.title?{title:request.title}:{},visibility:teamOnlyId?"private":request.visibility,...request.password?{password:request.password}:{},destination:request.destination,...request.teamId?{teamId:request.teamId}:{},...teamOnlyId?{audience:[{type:"team",id:teamOnlyId}]}:{},...request.publicComments!==void 0?{publicComments:request.publicComments}:{},provenance:gitContext(host.folder.root),viewport:PUBLISH_VIEWPORT},(event)=>{if(event.kind==="warn"){onWarning(event.message);return}if(event.kind==="note"){onWarning(event.message);return}if(event.kind==="info")return;if(event.kind==="capture"){onProgress({step,message,capture:{done:event.done,total:event.total}});return}step=event.step,message=event.message,onProgress({step,message})});if(!published.ok){let reason=describePublishError(published.error);if(published.error.kind==="LoggedOut")throw signInRequired("expired",reason);let limit=published.error.kind==="HttpFailure"?boardLimitFrom(published.error):null;if(limit)throw boardLimitReached(limit,reason);throw Error(reason)}let outcome=published.value,teamAudience=outcome.audience?.find((entry)=>entry.type==="team");return{shareUrl:outcome.shareUrl,slug:outcome.slug,visibility:outcome.visibility,passwordProtected:outcome.passwordProtected,...teamAudience?{onlyTeam:teamAudience.name||"your team"}:{},files:outcome.files,bytes:outcome.bytes,screenshots:outcome.screenshots,boards:outcome.boards,screens:outcome.screens,created:outcome.created,...outcome.tier!==void 0?{tier:outcome.tier}:{},...outcome.history!==void 0?{history:outcome.history}:{}}}}}function canvasGuest(guest){return{id:guest.id,name:guest.name,...guest.email!==void 0?{email:guest.email}:{},createdAt:guest.createdAt,lastSeenAt:guest.lastSeenAt,linkExpiresAt:guest.linkExpiresAt??null}}function canvasInvite(invite){return{guest:canvasGuest(invite.guest),emailed:invite.delivery.sent,...invite.delivery.reason?{reason:invite.delivery.reason}:{},...invite.guestUrl?{guestUrl:invite.guestUrl}:{}}}function createCanvasUpdates(){return{async status(opts={}){let status=await updateStatus(opts);return{current:status.current,latest:status.latest,available:status.available,method:status.method,channel:status.channel,upgradable:status.upgradable,...status.reason===void 0?{}:{reason:status.reason}}},async upgrade(){let outcome=await upgradeInstalledVelloo();return{upgraded:outcome.upgraded,from:outcome.from,to:outcome.to,restartRequired:outcome.upgraded}}}}var IDLE_MS=300000;function portFree(port,host){try{return Bun.serve({port,hostname:host,fetch:()=>new Response("")}).stop(!0),!0}catch{return!1}}var daemon_default=defineCommand({meta:{name:"__daemon",hidden:!0,description:"(internal) Run the persistent canvas daemon. Spawned by `velloo run` / `velloo mcp`."},args:{folder:{type:"positional",required:!0,description:"Design folder (absolute)"},port:{type:"string",description:"Preferred canvas port"},host:{type:"string",description:"Bind hostname (default 127.0.0.1)"}},async run({args}){let root=daemonRoot(args.folder),host=args.host??"127.0.0.1";assertLoopbackHost(host);let cloudUrl=defaultCloudUrl(),cred=await loadCredential(cloudUrl),cloud={url:cloudUrl,token:cred?.token,resolveToken:async()=>(await loadCredential(cloudUrl))?.token},auth=createCanvasAuth(cloudUrl),publish=createCanvasPublish(cloudUrl,auth),updates=createCanvasUpdates(),canvasPort=portCandidates({explicit:args.port?Number(args.port):void 0,remembered:await readRememberedPort(root),root}).find((port)=>portFree(port,host))??0,handle;try{handle=await createServer({folder:root,port:canvasPort,host,mcp:{transport:"http",port:0},canvasDist:canvasDistPath,cloud,auth,publish,updates})}catch(err){if(canvasPort===0)throw err;handle=await createServer({folder:root,port:0,host,mcp:{transport:"http",port:0},canvasDist:canvasDistPath,cloud,auth,publish,updates})}let rec={root,pid:process.pid,canvasUrl:handle.url,canvasPort:handle.port,mcpUrl:handle.mcpUrl??"",mcpPort:handle.mcpPort??0,cloudUrl,version:TOOL_VERSION,startedAt:new Date().toISOString()};await writeLock(rec),await registryUpsert(rec),await rememberPort(root,handle.port).catch(()=>{return}),console.error(`velloo: canvas daemon up at ${handle.url} (mcp ${handle.mcpUrl}), pid ${process.pid}`);let stopped=!1,shutdown=async()=>{if(stopped)return;stopped=!0,removeLock(root),await registryRemove(root).catch(()=>{return}),await handle.close(),process.exit(0)};for(let signal of["SIGTERM","SIGINT"])process.on(signal,()=>{console.error(`velloo: received ${signal} \u2014 shutting down.`),shutdown()});let rootMissing=0;setInterval(()=>{if(existsSync2(root)){rootMissing=0;return}if(rootMissing+=1,rootMissing>=2)console.error(`velloo: design folder ${root} is gone \u2014 shutting down.`),shutdown()},1e4);let idleSince=Date.now();setInterval(()=>{let{canvas,mcp}=handle.connections();if(canvas+mcp>0){idleSince=null;return}if(idleSince===null){idleSince=Date.now();return}if(Date.now()-idleSince>=IDLE_MS)console.error("velloo: canvas idle for 5 min \u2014 shutting down."),shutdown()},30000),await new Promise(()=>{})}});export{daemon_default as default};
|
|
2
|
+
import{signInRequired,boardLimitReached,topUpTokens,createServer}from"./chunk-9g45c5md.js";import"./chunk-xxw67jpk.js";import"./chunk-xg49s85z.js";import{ok,err,GUESTS_UNAVAILABLE,GuestsResponseSchema,GuestInviteResponseSchema,GuestLinkResponseSchema,unreachable,httpFailureFrom,boardLimitFrom,describeCloudError,cloudFetch}from"./chunk-bntsn3wj.js";import{loadCredential,saveCredential,deleteCredential,fetchAccount,revokeCredential,performDeviceLogin}from"./chunk-rg86bhtb.js";import{listPublishedDesigns,unpublishDesign,listPublishDestinations,describePublishError,PUBLISH_VIEWPORT,gitContext,publishableTeams,resolvePublishTeam,listTeams,publishDesign}from"./chunk-jxgwdz2r.js";import{TOOL_VERSION}from"./chunk-rrrn1mkq.js";import{updateStatus,upgradeInstalledVelloo}from"./chunk-d19ttv1a.js";import{assertLoopbackHost,daemonRoot,writeLock,removeLock,readRememberedPort,rememberPort,portCandidates,registryUpsert,registryRemove}from"./chunk-qgbat4fv.js";import"./chunk-hsk91jms.js";import{defaultCloudUrl,fetchCloudAppUrl}from"./chunk-w30zfv3m.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{existsSync as existsSync2}from"fs";import{existsSync}from"fs";import{dirname,join}from"path";import{fileURLToPath}from"url";var here=dirname(fileURLToPath(import.meta.url));function resolveCanvasDist(){let devLayout=join(here,"..","dist");return[process.env.VELLOO_CANVAS_DIST,join(here,"canvas"),devLayout].filter((p)=>Boolean(p)).find((p)=>existsSync(join(p,"index.html")))??devLayout}var canvasDistPath=resolveCanvasDist();var ACCOUNT_TTL_MS=60000,ACCOUNT_TIMEOUT_MS=5000;function createCanvasAuth(cloudUrl,dependencies={}){let runDeviceLogin=dependencies.performDeviceLogin??performDeviceLogin,login={state:"idle"},pending=null,cached=null,cachedApp=null,describe=async(token,email)=>{if(cached&&cached.token===token&&Date.now()-cached.at<ACCOUNT_TTL_MS)return{account:cached.account,verified:cached.verified};let found=await fetchAccount(cloudUrl,token,ACCOUNT_TIMEOUT_MS),resolved=found.status==="ok"?{account:found.account,verified:!0}:{account:{email},verified:found.status==="rejected"?!1:null};return cached={token,at:Date.now(),...resolved},resolved},resolveAppUrl=async()=>{if(cachedApp&&Date.now()-cachedApp.at<ACCOUNT_TTL_MS)return cachedApp.url;let url=await fetchCloudAppUrl(cloudUrl,ACCOUNT_TIMEOUT_MS);return cachedApp={at:Date.now(),url},url},status=async()=>{let cred=await loadCredential(cloudUrl),appUrlP=resolveAppUrl();if(!cred?.token)return{loggedIn:!1,cloudUrl,appUrl:await appUrlP,verified:null,login};let[{account,verified},appUrl]=await Promise.all([describe(cred.token,cred.email),appUrlP]);return{loggedIn:!0,cloudUrl,appUrl,verified,login,...account?{account}:{}}};return{status,async beginLogin(){if(login.state==="pending")return status();let attempt=new AbortController;pending=attempt,login={state:"idle"};let settle=()=>{},ready=new Promise((resolve)=>{settle=resolve});return runDeviceLogin(cloudUrl,({verificationUrl,userCode,expiresIn})=>{login={state:"pending",userCode,verificationUrl,expiresAt:new Date(Date.now()+expiresIn*1000).toISOString()},settle()},attempt.signal).then(async(result)=>{await saveCredential(cloudUrl,result),cached=null,login={state:"idle"},await topUpTokens({url:cloudUrl,token:result.token},10).catch(()=>{return})}).catch((err)=>{login=attempt.signal.aborted?{state:"idle"}:{state:"error",message:err instanceof Error?err.message:String(err)}}).finally(()=>{if(pending===attempt)pending=null;settle()}),await ready,status()},async cancelLogin(){pending?.abort(),pending=null,login={state:"idle"}},async logout(){pending?.abort(),pending=null,login={state:"idle"},cached=null;let stored=await loadCredential(cloudUrl);if(stored)await revokeCredential(cloudUrl,stored.token);await deleteCredential(cloudUrl)}}}var guestsUrl=({baseUrl,slug},rest="")=>`${baseUrl}/v1/links/${encodeURIComponent(slug)}/guests${rest}`,json=(body)=>({method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(body)});async function listGuests(target){let body=await cloudFetch(guestsUrl(target),GuestsResponseSchema,{operation:"listing guests",token:target.token});return body.ok?ok(body.value.guests):body}function inviteGuest(target,guest){return cloudFetch(guestsUrl(target),GuestInviteResponseSchema,{operation:"inviting a guest",token:target.token,...json({email:guest.email,...guest.name?{name:guest.name}:{}})})}function resendGuestLink(target,guestId){return cloudFetch(guestsUrl(target,`/${encodeURIComponent(guestId)}/resend`),GuestInviteResponseSchema,{operation:"resending a guest's link",token:target.token,...json({})})}async function mintGuestLink(target,guestId){let body=await cloudFetch(guestsUrl(target,`/${encodeURIComponent(guestId)}/link`),GuestLinkResponseSchema,{operation:"making a guest link",token:target.token,...json({})});return body.ok?ok(body.value.guestUrl):body}async function removeGuest(target,guestId){let res=await fetch(guestsUrl(target,`/${encodeURIComponent(guestId)}`),{method:"DELETE",headers:{authorization:`Bearer ${target.token}`}}).catch((error)=>error);if(!(res instanceof Response))return err(unreachable(res,{url:target.baseUrl}));if(!res.ok)return err(await httpFailureFrom("removing a guest",res));return ok(void 0)}function createCanvasPublish(cloudUrl,auth){let tokenFor=async()=>(await loadCredential(cloudUrl))?.token,access=async()=>{if(!await tokenFor())return{state:"signed-out"};return(await auth.status().catch(()=>null))?.verified===!1?{state:"expired"}:{state:"ready"}},rejection=(error)=>error.kind==="LoggedOut"?signInRequired("expired",describeCloudError(error)):Error(describeCloudError(error)),guestRejection=(error)=>error.kind==="HttpFailure"&&error.status===403&&/\bguests requires\b/.test(error.detail)?Error(GUESTS_UNAVAILABLE):rejection(error),guestTarget=async(slug)=>{let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");return{baseUrl:cloudUrl,token,slug}},settled=(result)=>{if(!result.ok)throw guestRejection(result.error);return result.value},publishedAt=(value)=>{let parsed=value?Date.parse(value):Number.NaN;return Number.isFinite(parsed)?parsed:Number.NEGATIVE_INFINITY},soleTeamId=async(token)=>{let listed=await listTeams(cloudUrl,token);if(!listed.ok)return null;let resolved=resolvePublishTeam(listed.value);return resolved.ok&&resolved.value.kind==="team"?resolved.value.team.id:null};return{access,async teams(){let token=await tokenFor();if(!token)return[];let listed=await listTeams(cloudUrl,token);return listed.ok?publishableTeams(listed.value):[]},async blocked(){let token=await tokenFor();if(!token)return null;let listed=await listTeams(cloudUrl,token);if(!listed.ok)return null;let resolved=resolvePublishTeam(listed.value);return!resolved.ok&&resolved.error.kind==="NoPublishableTeam"?describePublishError(resolved.error):null},async published(){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let listed=await listPublishedDesigns({baseUrl:cloudUrl,token});if(!listed.ok)throw rejection(listed.error);return listed.value.map((design)=>({slug:design.slug,title:design.title??"",url:design.url,visibility:design.visibility,passwordProtected:design.passwordProtected,canManage:design.canManage,lastPublishedAt:design.lastPublishedAt,...design.guestCount!==void 0?{guestCount:design.guestCount}:{},...design.visibility==="private"&&design.teamName&&design.audience?.some((entry)=>entry.type==="team")?{onlyTeam:design.teamName}:{}})).sort((left,right)=>publishedAt(right.lastPublishedAt)-publishedAt(left.lastPublishedAt))},async unpublish(slug){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let removed=await unpublishDesign({baseUrl:cloudUrl,token,slug});if(!removed.ok)throw rejection(removed.error)},guests:{async list(slug){return settled(await listGuests(await guestTarget(slug))).map(canvasGuest)},async invite(slug,guest){return canvasInvite(settled(await inviteGuest(await guestTarget(slug),guest)))},async resend(slug,guestId){return canvasInvite(settled(await resendGuestLink(await guestTarget(slug),guestId)))},async link(slug,guestId){return settled(await mintGuestLink(await guestTarget(slug),guestId))},async remove(slug,guestId){settled(await removeGuest(await guestTarget(slug),guestId))}},async destinations(host){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud");let provenance=gitContext(host.folder.root),folderId=host.folder.config.folderId;if(!folderId){let teams=await listTeams(cloudUrl,token);if(!teams.ok)throw rejection(teams.error);let publishable=publishableTeams(teams.value);return{effectiveTeamId:publishable.length===1?publishable[0]?.id??null:null,provenance,slots:[]}}let listed=await listPublishDestinations({baseUrl:cloudUrl,token,folderId});if(!listed.ok)throw rejection(listed.error);return{...listed.value,provenance}},async run(host,request,onProgress,onWarning){let token=await tokenFor();if(!token)throw signInRequired("signed-out","not signed in to velloo-cloud \u2014 sign in from the account menu first.");let teamOnlyId=request.teamOnly?request.teamId??await soleTeamId(token):null;if(request.teamOnly&&!teamOnlyId)throw Error("a team-only link needs a team to publish into \u2014 choose one");let step="start",message="starting",published=await publishDesign({baseUrl:cloudUrl,token},{folder:host.folder,providers:host.providers,defaultProvider:host.defaultProvider,snapshotCss:host.snapshotCss},{boardIds:request.boardIds,...request.title?{title:request.title}:{},visibility:teamOnlyId?"private":request.visibility,...request.password?{password:request.password}:{},destination:request.destination,...request.teamId?{teamId:request.teamId}:{},...teamOnlyId?{audience:[{type:"team",id:teamOnlyId}]}:{},...request.publicComments!==void 0?{publicComments:request.publicComments}:{},provenance:gitContext(host.folder.root),viewport:PUBLISH_VIEWPORT},(event)=>{if(event.kind==="warn"){onWarning(event.message);return}if(event.kind==="note"){onWarning(event.message);return}if(event.kind==="info")return;if(event.kind==="capture"){onProgress({step,message,capture:{done:event.done,total:event.total}});return}step=event.step,message=event.message,onProgress({step,message})});if(!published.ok){let reason=describePublishError(published.error);if(published.error.kind==="LoggedOut")throw signInRequired("expired",reason);let limit=published.error.kind==="HttpFailure"?boardLimitFrom(published.error):null;if(limit)throw boardLimitReached(limit,reason);throw Error(reason)}let outcome=published.value,teamAudience=outcome.audience?.find((entry)=>entry.type==="team");return{shareUrl:outcome.shareUrl,slug:outcome.slug,visibility:outcome.visibility,passwordProtected:outcome.passwordProtected,...teamAudience?{onlyTeam:teamAudience.name||"your team"}:{},files:outcome.files,bytes:outcome.bytes,screenshots:outcome.screenshots,boards:outcome.boards,screens:outcome.screens,created:outcome.created,...outcome.tier!==void 0?{tier:outcome.tier}:{},...outcome.history!==void 0?{history:outcome.history}:{}}}}}function canvasGuest(guest){return{id:guest.id,name:guest.name,...guest.email!==void 0?{email:guest.email}:{},createdAt:guest.createdAt,lastSeenAt:guest.lastSeenAt,linkExpiresAt:guest.linkExpiresAt??null}}function canvasInvite(invite){return{guest:canvasGuest(invite.guest),emailed:invite.delivery.sent,...invite.delivery.reason?{reason:invite.delivery.reason}:{},...invite.guestUrl?{guestUrl:invite.guestUrl}:{}}}function createCanvasUpdates(){return{async status(opts={}){let status=await updateStatus(opts);return{current:status.current,latest:status.latest,available:status.available,method:status.method,channel:status.channel,upgradable:status.upgradable,...status.reason===void 0?{}:{reason:status.reason}}},async upgrade(){let outcome=await upgradeInstalledVelloo();return{upgraded:outcome.upgraded,from:outcome.from,to:outcome.to,restartRequired:outcome.upgraded}}}}var IDLE_MS=300000;function portFree(port,host){try{return Bun.serve({port,hostname:host,fetch:()=>new Response("")}).stop(!0),!0}catch{return!1}}var daemon_default=defineCommand({meta:{name:"__daemon",hidden:!0,description:"(internal) Run the persistent canvas daemon. Spawned by `velloo run` / `velloo mcp`."},args:{folder:{type:"positional",required:!0,description:"Design folder (absolute)"},port:{type:"string",description:"Preferred canvas port"},host:{type:"string",description:"Bind hostname (default 127.0.0.1)"}},async run({args}){let root=daemonRoot(args.folder),host=args.host??"127.0.0.1";assertLoopbackHost(host);let cloudUrl=defaultCloudUrl(),cred=await loadCredential(cloudUrl),cloud={url:cloudUrl,token:cred?.token,resolveToken:async()=>(await loadCredential(cloudUrl))?.token},auth=createCanvasAuth(cloudUrl),publish=createCanvasPublish(cloudUrl,auth),updates=createCanvasUpdates(),canvasPort=portCandidates({explicit:args.port?Number(args.port):void 0,remembered:await readRememberedPort(root),root}).find((port)=>portFree(port,host))??0,handle;try{handle=await createServer({folder:root,port:canvasPort,host,mcp:{transport:"http",port:0},canvasDist:canvasDistPath,cloud,auth,publish,updates})}catch(err){if(canvasPort===0)throw err;handle=await createServer({folder:root,port:0,host,mcp:{transport:"http",port:0},canvasDist:canvasDistPath,cloud,auth,publish,updates})}let rec={root,pid:process.pid,canvasUrl:handle.url,canvasPort:handle.port,mcpUrl:handle.mcpUrl??"",mcpPort:handle.mcpPort??0,cloudUrl,version:TOOL_VERSION,startedAt:new Date().toISOString()};await writeLock(rec),await registryUpsert(rec),await rememberPort(root,handle.port).catch(()=>{return}),console.error(`velloo: canvas daemon up at ${handle.url} (mcp ${handle.mcpUrl}), pid ${process.pid}`);let stopped=!1,shutdown=async()=>{if(stopped)return;stopped=!0,removeLock(root),await registryRemove(root).catch(()=>{return}),await handle.close(),process.exit(0)};for(let signal of["SIGTERM","SIGINT"])process.on(signal,()=>{console.error(`velloo: received ${signal} \u2014 shutting down.`),shutdown()});let rootMissing=0;setInterval(()=>{if(existsSync2(root)){rootMissing=0;return}if(rootMissing+=1,rootMissing>=2)console.error(`velloo: design folder ${root} is gone \u2014 shutting down.`),shutdown()},1e4);let idleSince=Date.now();setInterval(()=>{let{canvas,mcp}=handle.connections();if(canvas+mcp>0){idleSince=null;return}if(idleSince===null){idleSince=Date.now();return}if(Date.now()-idleSince>=IDLE_MS)console.error("velloo: canvas idle for 5 min \u2014 shutting down."),shutdown()},30000),await new Promise(()=>{})}});export{daemon_default as default};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{colorizeDiff,emitTheme,emitNativeTheme,loadDesignFolder,emitDesignMdPair,resolveProviders}from"./chunk-
|
|
2
|
+
import{colorizeDiff,emitTheme,emitNativeTheme,loadDesignFolder,emitDesignMdPair,resolveProviders}from"./chunk-9g45c5md.js";import{ThemeSchema}from"./chunk-xxw67jpk.js";import"./chunk-xg49s85z.js";import"./chunk-bntsn3wj.js";import"./chunk-80fjfyha.js";import"./chunk-s23gtejf.js";import{detectHost}from"./chunk-cg0sjdqt.js";import{DESIGN_ARG_DESCRIPTION,resolveDesign}from"./chunk-6w42sr61.js";import{defineCommand}from"./chunk-2smsg2ct.js";import{readFile}from"fs/promises";import{isAbsolute,join,resolve}from"path";import{stdin,stdout}from"process";import{createInterface}from"readline/promises";async function readMaybe(path){try{return await readFile(path,"utf8")}catch{return}}async function themeEmitter(folderRoot,theme,outDir,cssOnly,tailwind3){let design=await loadDesignFolder(folderRoot),{defaultProvider}=await resolveProviders(design.config,folderRoot),adapter=defaultProvider;if(adapter.themeToNative&&adapter.themeModule){let toNative=adapter.themeToNative.bind(adapter),spec=adapter.themeModule;return{native:!0,produce:(apply)=>emitNativeTheme(toNative(theme),{spec,outputDir:outDir,apply,...theme.colorsDark?{darkThemeOptions:toNative(theme,!0)}:{},sourceTheme:theme})}}let customCss=await readMaybe(join(folderRoot,"theme","custom.css"));return{native:!1,produce:(apply)=>emitTheme(theme,{outputDir:outDir,apply,cssOnly,...customCss?{customCss}:{},...tailwind3?{tailwindMajor:3}:{}})}}async function report(produce,apply){let result=await produce(apply),useColor=stdout.isTTY===!0,anyChange=!1;for(let warning of result.warnings)console.error(`velloo theme export: warning: ${warning}`);for(let file of result.files){if(file.diff.identical){console.log(`velloo theme export: ${file.path} is already up to date.`);continue}if(anyChange=!0,file.applied)console.log(`velloo theme export: wrote ${file.path}`);else{let rendered=useColor?colorizeDiff(file.diff.diff):file.diff.diff;stdout.write(`${rendered}
|
|
3
3
|
`),stdout.write(`Would write to: ${file.path}
|
|
4
4
|
|
|
5
5
|
`)}}for(let note of result.notes)console.log(`velloo theme export: ${note}`);if(!anyChange||apply)return;if(!stdin.isTTY){console.log("(non-TTY) re-run with --apply to write the files.");return}let rl=createInterface({input:stdin,output:stdout}),answer=(await rl.question("Apply all? (y/N) ")).trim().toLowerCase();if(rl.close(),answer==="y"||answer==="yes"){let final=await produce(!0);for(let file of final.files)if(file.applied)console.log(`velloo theme export: wrote ${file.path}`)}else console.log("velloo theme export: skipped (no changes written).")}var exportTheme=defineCommand({meta:{name:"export",description:"Export DTCG tokens.json plus the framework theme in diff mode \u2014 Tailwind v4 globals.css by default, or v3 CSS + preset when detected"},args:{to:{type:"string",required:!0,description:"Target app directory (writes <to>/app/globals.css and <to>/tailwind.config.ts)"},design:{type:"string",description:DESIGN_ARG_DESCRIPTION},theme:{type:"string",description:"Path to theme JSON (default: the design's theme/default.json)"},apply:{type:"boolean",description:"Write files instead of printing diffs. Default: dry-run."},"css-only":{type:"boolean",description:"Skip tailwind.config.ts (CSS-only export)."},"force-v4":{type:"boolean",description:"Emit the v4 artifacts even when the target app looks like Tailwind v3."},format:{type:"enum",options:["framework","design-md"],default:"framework",description:'Output format: "framework", or "design-md" for a Google Labs DESIGN.md.'}},async run({args}){let folderRoot=await resolveDesign(args.design,"theme export",{designFlag:"--design"}),themePath=args.theme?resolve(args.theme):join(folderRoot,"theme","default.json"),outDir=isAbsolute(args.to)?args.to:resolve(args.to),themeJson=JSON.parse(await readFile(themePath,"utf8")),theme=ThemeSchema.parse(themeJson);if(args.format==="design-md"){let design=await loadDesignFolder(folderRoot);await report((apply)=>emitDesignMdPair(design,theme,{outputDir:outDir,apply}),Boolean(args.apply));return}let tailwind3=!args["force-v4"]&&detectHost(outDir).tailwindMajor===3,{native,produce}=await themeEmitter(folderRoot,theme,outDir,Boolean(args["css-only"]),tailwind3);if(!native&&tailwind3)console.log("velloo theme export: target looks like Tailwind v3 \u2014 emitting velloo-theme.css + velloo.preset (pass --force-v4 for the v4 artifacts).");await report(produce,Boolean(args.apply))}}),theme_default=defineCommand({meta:{name:"theme",description:"Work with a design's theme"},subCommands:{export:exportTheme}});export{theme_default as default};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{string,number,object,CURRENT_SCHEMA_VERSION,schemaVersionOf}from"./chunk-
|
|
2
|
+
import{string,number,object,CURRENT_SCHEMA_VERSION,schemaVersionOf}from"./chunk-xxw67jpk.js";import{writeJsonAtomic}from"./chunk-9g45c5md.js";import{TOOL_VERSION}from"./chunk-rrrn1mkq.js";import{defaultCloudUrl}from"./chunk-w30zfv3m.js";import{selfCommand}from"./chunk-skk6yvnw.js";function isLoopbackHost(host){let normalized=host.trim().toLowerCase().replace(/^\[|\]$/g,"").replace(/\.$/,"");if(normalized==="localhost"||normalized==="::1")return!0;let octets=normalized.split(".");return octets.length===4&&octets[0]==="127"&&octets.every((part)=>/^\d+$/.test(part))}function assertLoopbackHost(host){if(isLoopbackHost(host))return;throw Error(`refusing to bind ${JSON.stringify(host)}: the canvas and MCP endpoints have no authentication and only serve loopback (use 127.0.0.1, localhost or ::1)`)}import{closeSync,existsSync,mkdirSync,openSync,readFileSync,realpathSync,statSync,unlinkSync,writeSync}from"fs";import{mkdir,readFile}from"fs/promises";import{homedir}from"os";import{dirname,join,resolve}from"path";function spawnOutliving(cmd,output){let proc=Bun.spawn(cmd,{stdin:"ignore",stdout:output,stderr:output,detached:!0,windowsHide:!0});return proc.unref(),proc}var DaemonRecordSchema=object({root:string().min(1),pid:number().int().positive(),canvasUrl:string().min(1),canvasPort:number().int().positive(),mcpUrl:string().min(1),mcpPort:number().int().positive(),cloudUrl:string().min(1),version:string().min(1),startedAt:string().min(1)});function daemonMatchesRuntime(rec,cloudUrl=defaultCloudUrl()){return rec.version===TOOL_VERSION&&rec.cloudUrl===cloudUrl}var MUTEX_STALE_MS=15000,HEALTHY_TIMEOUT_MS=15000,cacheDir=(root)=>join(root,".design","cache"),lockPath=(root)=>join(cacheDir(root),"runtime.json"),mutexPath=(root)=>join(cacheDir(root),"runtime.lock"),logPath=(root)=>join(cacheDir(root),"daemon.log"),portMemoPath=(root)=>join(cacheDir(root),"port.json"),registryPath=()=>process.env.VELLOO_DAEMONS_PATH??join(homedir(),".velloo","daemons.json");function daemonRoot(folder){let abs=resolve(folder);return existsSync(abs)?realpathSync(abs):abs}class DesignFolderFormatError extends Error{root;found;current;constructor(message,root,found,current){super(message);this.root=root;this.found=found;this.current=current;this.name="DesignFolderFormatError"}}function assertFolderFormatCurrent(root){let raw;try{raw=JSON.parse(readFileSync(join(root,".design","config.json"),"utf8"))}catch{return}let found=schemaVersionOf(raw);if(found===CURRENT_SCHEMA_VERSION)return;let message=found>CURRENT_SCHEMA_VERSION?`velloo: ${root} uses design-folder schema version ${found}, but this velloo only knows version ${CURRENT_SCHEMA_VERSION}. Upgrade velloo to open it.`:`velloo: ${root} uses design-folder schema version ${found} (current: ${CURRENT_SCHEMA_VERSION}). Run \`velloo upgrade ${root}\` to migrate it.`;throw new DesignFolderFormatError(message,root,found,CURRENT_SCHEMA_VERSION)}async function readLock(root){try{let parsed=DaemonRecordSchema.safeParse(JSON.parse(await readFile(lockPath(root),"utf8")));return parsed.success?parsed.data:null}catch{return null}}async function writeLock(rec){await writeJsonAtomic(lockPath(rec.root),rec)}function removeLock(root){try{unlinkSync(lockPath(root))}catch{}}var DEFAULT_CANVAS_PORT=7300,DERIVED_BAND={start:7310,size:90},PortMemoSchema=object({canvasPort:number().int().min(1).max(65535)});async function readRememberedPort(root){try{let parsed=PortMemoSchema.safeParse(JSON.parse(await readFile(portMemoPath(root),"utf8")));return parsed.success?parsed.data.canvasPort:null}catch{return null}}async function rememberPort(root,canvasPort){await writeJsonAtomic(portMemoPath(root),{canvasPort})}function derivedPort(root){let digest=Bun.CryptoHasher.hash("sha256",root,"hex");return DERIVED_BAND.start+Number.parseInt(digest.slice(0,8),16)%DERIVED_BAND.size}function portCandidates(opts){if(opts.explicit!==void 0)return[opts.explicit];let wanted=[opts.remembered,DEFAULT_CANVAS_PORT,derivedPort(opts.root)];return[...new Set(wanted.filter((p)=>typeof p==="number"))]}var HealthSchema=object({app:string().optional(),root:string().optional()});async function isLive(rec){try{let res=await fetch(`http://127.0.0.1:${rec.canvasPort}/api/health`,{signal:AbortSignal.timeout(1000)});if(!res.ok)return!1;let body=await res.json(),health=HealthSchema.safeParse(body);return health.success&&health.data.app==="velloo"&&health.data.root===rec.root}catch{return!1}}async function registryRead(){try{let raw=JSON.parse(await readFile(registryPath(),"utf8"));if(!Array.isArray(raw))return[];return raw.flatMap((entry)=>{let parsed=DaemonRecordSchema.safeParse(entry);return parsed.success?[parsed.data]:[]})}catch{return[]}}async function registryWrite(records){let p=registryPath();await mkdir(dirname(p),{recursive:!0}),await writeJsonAtomic(p,records)}async function registryUpsert(rec){let others=(await registryRead()).filter((r)=>r.root!==rec.root);await registryWrite([...others,rec])}async function registryRemove(root){await registryWrite((await registryRead()).filter((r)=>r.root!==root))}async function listDaemons(){let all=await registryRead(),live=[];for(let rec of all)if(await isLive(rec))live.push(rec);if(live.length!==all.length)await registryWrite(live);return live}function daemonSpawnCmd(root,preferredPort,host){let args=["__daemon",root,"--host",host];if(preferredPort!==void 0)args.push("--port",String(preferredPort));return selfCommand(args)}function spawnDetached(root,preferredPort,host){mkdirSync(cacheDir(root),{recursive:!0});let logStart=0;try{logStart=statSync(logPath(root)).size}catch{}let log=openSync(logPath(root),"a");return{exited:spawnOutliving(daemonSpawnCmd(root,preferredPort,host),log).exited,logStart}}function claimMutex(root){let path=mutexPath(root);try{let fd=openSync(path,"wx");return writeSync(fd,String(process.pid)),closeSync(fd),!0}catch{try{if(Date.now()-statSync(path).mtimeMs>MUTEX_STALE_MS)return unlinkSync(path),claimMutex(root)}catch{}return!1}}function releaseMutex(root){try{unlinkSync(mutexPath(root))}catch{}}function startupFailure(root,logStart){let appended="";try{appended=readFileSync(logPath(root),"utf8").slice(logStart)}catch{}let lines=appended.split(`
|
|
3
3
|
`).map((l)=>l.replace(/^velloo __daemon: /,"").trimEnd()).filter((l)=>l.trim().length>0).slice(-8);if(lines.length===0)return`velloo: the canvas daemon for ${root} exited during startup with no output \u2014 see ${logPath(root)}`;return`velloo: the canvas daemon for ${root} exited during startup:
|
|
4
4
|
${lines.join(`
|
|
5
5
|
`)}`}async function waitForHealthy(root,spawned){let deadline=Date.now()+HEALTHY_TIMEOUT_MS,died=!1;if(spawned)spawned.exited.then(()=>died=!0);while(Date.now()<deadline){let rec=await readLock(root);if(rec&&await isLive(rec))return rec;if(died)throw Error(startupFailure(root,spawned?.logStart??0));await new Promise((r)=>setTimeout(r,150))}throw Error(`velloo: canvas daemon for ${root} didn't come up \u2014 see ${logPath(root)}`)}async function ensureDaemon(folder,opts={}){let root=daemonRoot(folder);assertFolderFormatCurrent(root);let host=opts.host??"127.0.0.1";assertLoopbackHost(host),mkdirSync(cacheDir(root),{recursive:!0});let deadline=Date.now()+HEALTHY_TIMEOUT_MS+5000;while(Date.now()<deadline){let existing=await readLock(root);if(existing&&await isLive(existing)){if(daemonMatchesRuntime(existing))return existing;await stopDaemon(root)}if(claimMutex(root))try{let again=await readLock(root);if(again&&await isLive(again)){if(daemonMatchesRuntime(again))return again;await stopDaemon(root)}let spawned=spawnDetached(root,opts.preferredPort,host);return opts.onSpawn?.(),await waitForHealthy(root,spawned)}finally{releaseMutex(root)}await new Promise((r)=>setTimeout(r,200))}throw Error(`velloo: timed out ensuring a canvas daemon for ${root}`)}async function stopDaemon(root){let rec=await readLock(root);if(!rec)return!1;try{process.kill(rec.pid,"SIGTERM")}catch{}for(let i=0;i<30;i++){if(!await isLive(rec))break;await new Promise((r)=>setTimeout(r,100))}return removeLock(root),await registryRemove(root),!0}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{isCancel,select}from"./chunk-80fjfyha.js";import{preflightScreens}from"./chunk-
|
|
2
|
+
import{isCancel,select}from"./chunk-80fjfyha.js";import{preflightScreens}from"./chunk-9g45c5md.js";import{fail}from"./chunk-s23gtejf.js";import{copyToClipboard}from"./chunk-vbk1qhdz.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM}from"./chunk-2smsg2ct.js";import{stripVTControlCharacters}from"util";var import_picocolors=__toESM(require_picocolors(),1);function plural(count,noun){return`${count} ${noun}${count===1?"":"s"}`}function formatFailures(command,failures){let byScreen=new Map;for(let failure of failures)byScreen.set(failure.screenId,[...byScreen.get(failure.screenId)??[],failure]);let notDrawn=[...byScreen.values()].filter((group)=>group.some((failure)=>failure.componentId===null)),placeholders=[...byScreen.values()].filter((group)=>!notDrawn.includes(group)).reduce((sum,group)=>sum+group.length,0),consequences=[placeholders>0&&`${plural(placeholders,"component")} will appear as placeholders`,notDrawn.length>0&&`${plural(notDrawn.length,"screen")} will not render at all`].filter(Boolean),lines=[`${import_picocolors.default.yellow(`velloo ${command}:`)} render failures on ${plural(byScreen.size,"screen")} \u2014 ${consequences.join(", and ")}:`];for(let group of byScreen.values()){let[first]=group;if(!first)continue;let boards=first.boards.length>0?first.boards.map((board)=>board.name).join(", "):"no board";lines.push("",` ${import_picocolors.default.dim(`${boards} \u203A`)} ${import_picocolors.default.bold(first.screenName)} ${import_picocolors.default.dim(`(${first.screenId})`)}`);let pinned=group.some((failure)=>failure.componentId!==null);for(let failure of group)if(failure.componentId!==null)lines.push(` ${import_picocolors.default.cyan(failure.componentId)}: ${failure.reason}`);else{let label=pinned?"screen not drawn":"screen not drawn \u2014 the error could not be pinned on one component";lines.push(` ${import_picocolors.default.red(label)}: ${failure.reason}`)}}return lines}async function confirmRenderFailures(command,source,screens,yes){let failures=preflightScreens(source,screens);if(failures.length===0)return;let report=formatFailures(command,failures);for(let line of report)console.error(line);if(console.error(""),yes)return;if(!process.stdin.isTTY)fail(command,"refusing to continue \u2014 re-run with --yes to accept the placeholders.");for(;;){let choice=await select({message:"Continue anyway?",options:[{value:"cancel",label:"No, cancel"},{value:"continue",label:"Yes, continue with the failures"},{value:"copy",label:"Copy errors to clipboard"}],initialValue:"cancel"});if(isCancel(choice)||choice==="cancel")fail(command,"cancelled.");if(choice==="continue")return;let copied=await copyToClipboard(stripVTControlCharacters(report.join(`
|
|
3
3
|
`)));console.error(copied?` ${import_picocolors.default.green("\u2713")} Errors copied to the clipboard.`:import_picocolors.default.dim(" Couldn't reach a clipboard tool \u2014 copy the errors printed above."))}}
|
|
4
4
|
export{confirmRenderFailures};
|