pixelvault-cli 0.5.1 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
var
|
|
1
|
+
var oe=Object.defineProperty;var c=(e,r)=>()=>(e&&(r=e(e=0)),r);var _=(e,r)=>{for(var i in r)oe(e,i,{get:r[i],enumerable:!0})};var p,$=c(()=>{"use strict";p=class extends Error{exitCode;constructor(r,i=1){super(r),this.name="CliError",this.exitCode=i}}});function u(e){process.stdout.write(e+`
|
|
2
2
|
`)}function n(e){process.stderr.write(e+`
|
|
3
|
-
`)}function
|
|
4
|
-
`,{mode:384})}function
|
|
5
|
-
`||
|
|
6
|
-
`),r(o)):i===""?(process.stdin.setRawMode(!1),process.exit(130)):i==="\x7F"||i==="\b"?o=o.slice(0,-1):o+=i};process.stdin.on("data",t)}):j(e)}var I=m(()=>{"use strict"});var U={};x(U,{default:()=>ce});import{defineCommand as me}from"citty";var ce,F=m(()=>{"use strict";_();g();I();w();ce=me({meta:{name:"register",description:"Create a new PixelVault account"},args:{email:{type:"string",description:"Email address"},password:{type:"string",description:"Password (min 8 characters). Omit for a passwordless account."},passwordless:{type:"boolean",description:"Create the account without a password (for agents/automation). Set a password later via the web 'Forgot password' flow."}},async run({args:e}){let r=!!process.stdin.isTTY,o=e.email||(r?await j("Email: "):"");o||(n("Email is required. Pass --email <email>."),process.exit(1));let t;e.password?t=e.password:e.passwordless?t=void 0:r?t=await S("Password (leave blank for a passwordless account): ")||void 0:t=void 0,t!==void 0&&t.length<8&&(n("Password must be at least 8 characters."),process.exit(1)),n("Creating account...");let i=await f({method:"POST",path:"/v1/auth/register",body:{email:o,...t?{password:t}:{},attribution:{source:"cli"}}});b({api_key:i.data.default_project.api_keys.live,default_project:i.data.default_project.id,email:i.data.email}),n("Account created. API key saved to ~/.pixelvault/config.json"),n(`Email: ${i.data.email}`),n(`Project: ${i.data.default_project.id}`),(i.data.password_set===!1||!t)&&n("No password set. To enable dashboard login, use 'Forgot password' at https://pixelvault.dev/forgot-password to set one."),i.data.email_verified||n("Verify your email to lift the upload limit for the free tier.")}})});var q={};x(q,{default:()=>ye});import{defineCommand as ge}from"citty";var ye,N=m(()=>{"use strict";_();g();I();w();ye=ge({meta:{name:"login",description:"Log in to your PixelVault account"},args:{email:{type:"string",description:"Email address"},password:{type:"string",description:"Password"}},async run({args:e}){let r=e.email||await j("Email: "),o=e.password||await S("Password: ");(!r||!o)&&(n("Email and password are required."),process.exit(1)),n("Logging in...");let t=await f({method:"POST",path:"/v1/auth/login",body:{email:r,password:o}}),i=t.data.token,s;try{s=(await f({method:"GET",path:"/v1/projects",auth:i})).data[0]?.id}catch{}if(s){let a=await f({method:"POST",path:"/v1/auth/rotate-key",auth:i,body:{project_id:s}});b({api_key:a.data.api_key,default_project:s,email:t.data.email}),n("Logged in. API key saved to ~/.pixelvault/config.json"),n(`Email: ${t.data.email}`),n(`Project: ${s}`)}else n(`Logged in as ${t.data.email}.`),n("Could not auto-configure API key. Set PIXELVAULT_API_KEY manually."),b({email:t.data.email})}})});function D(e){let r=/^(\d+)\s*([smhd]?)$/i.exec(e.trim());if(!r)throw new p(`Invalid --expires "${e}". Use e.g. 30m, 12h, 7d, or a number of seconds.`);let o=(r[2]??"").toLowerCase(),t=o==="d"?86400:o==="h"?3600:o==="m"?60:1,i=Number(r[1]??"")*t;if(i<we||i>he)throw new p(`--expires must be between 60s and 30d (got ${i}s).`);return i}var we,he,K=m(()=>{"use strict";$();we=60,he=720*60*60});var B={};x(B,{default:()=>be});import{defineCommand as xe}from"citty";import{readFileSync as ve}from"fs";import{basename as _e}from"path";var be,V=m(()=>{"use strict";_();g();K();w();be=xe({meta:{name:"upload",description:"Upload one or more images"},args:{files:{type:"positional",description:"File path(s) to upload",required:!0},folder:{type:"string",description:"Folder to organize images in"},private:{type:"boolean",description:"Upload privately \u2014 returns a signed URL only holders of the link can open (needs a secret key)",default:!1},expires:{type:"string",description:"Lifetime of a --private signed link: e.g. 30m, 12h, 7d (default 7d; min 60s, max 30d)"},json:{type:"boolean",description:"Output full JSON response",default:!1}},async run({args:e}){let r=h(),o=null;e.expires!==void 0&&(e.private||(n("--expires only applies to --private uploads (it sets the signed link's lifetime)."),process.exit(1)),o=D(String(e.expires))),e.private&&e.folder&&n("Note: --folder is ignored for --private uploads.");let t=Array.isArray(e.files)?e.files:[e.files],i=!1,s=[];for(let a of t)try{let l=ve(a),C=_e(a),y=new FormData;y.append("file",new File([l],C)),e.folder&&y.append("folder",e.folder),e.private&&(y.append("visibility","private"),o!==null&&y.append("sign_expires_in",String(o)));let d=await f({method:"POST",path:"/v1/images",auth:r,formData:y});if(e.private&&d.data.visibility!=="private"){i=!0,n(`Refusing to report ${a}: server did not confirm a private upload.`);continue}e.json?s.push(d.data):u(d.data.url)}catch(l){i=!0,n(`Failed to upload ${a}: ${l instanceof Error?l.message:String(l)}`)}e.json&&s.length>0&&c(s.length===1?s[0]:s),i&&process.exit(1)}})});var M={};x(M,{default:()=>je});import{defineCommand as $e}from"citty";var je,J=m(()=>{"use strict";_();g();w();je=$e({meta:{name:"list",description:"List uploaded images"},args:{page:{type:"string",description:"Page number",default:"1"},"per-page":{type:"string",description:"Items per page (max 100)",default:"20"},json:{type:"boolean",description:"Output full JSON response",default:!1}},async run({args:e}){let r=h(),o=new URLSearchParams({page:e.page,per_page:e["per-page"]}),t=await f({path:`/v1/images?${o}`,auth:r});if(e.json)c(t);else for(let i of t.data)u(i.url)}})});var G={};x(G,{applyTransform:()=>X,default:()=>Re});import{defineCommand as Ee}from"citty";import{writeFileSync as Se}from"fs";function X(e,r){if(!r)return e;let o=r.trim().replace(/^[?&]+/,"");if(!o)return e;let t=new URLSearchParams(o).toString();return t?e.includes("?")?`${e}&${t}`:`${e}?${t}`:e}var Re,Y=m(()=>{"use strict";_();g();w();$();Re=Ee({meta:{name:"get",description:"Get an image's CDN URL or metadata, or download it \u2014 optionally transformed"},args:{id:{type:"positional",description:"Image ID (e.g. img_abc123)",required:!0},output:{type:"string",description:"Download the image to this file path",alias:"o"},transform:{type:"string",description:'Transform params to apply, e.g. "w=400&fmt=webp", "segment=foreground", "tile=img_logo.png"',alias:"t"},json:{type:"boolean",description:"Output full JSON metadata",default:!1}},async run({args:e}){let r=h(),o=await f({path:`/v1/images/${encodeURIComponent(e.id)}`,auth:r}),t=X(o.data.url,e.transform);if(e.output){let i=e.output,s;try{let a=await fetch(t);if(!a.ok)throw new p(`Failed to download image: HTTP ${a.status}`,1);s=await a.arrayBuffer()}catch(a){throw a instanceof p?a:new p(`Failed to download image: ${a instanceof Error?a.message:String(a)}`,1)}if(s.byteLength===0)throw new p("Downloaded 0 bytes \u2014 refusing to write an empty file",1);try{Se(i,Buffer.from(s))}catch(a){throw new p(`Failed to save ${i}: ${a instanceof Error?a.message:String(a)}`,1)}n(`Saved ${i}`),e.json?c(e.transform?{...o,transformed_url:t,output:i}:{...o,output:i}):u(t);return}e.json?c(e.transform?{...o,transformed_url:t}:o):u(t)}})});var z={};x(z,{default:()=>Pe});import{defineCommand as Ce}from"citty";var Pe,H=m(()=>{"use strict";_();g();Pe=Ce({meta:{name:"delete",description:"Delete an image by ID"},args:{id:{type:"positional",description:"Image ID (e.g. img_abc123)",required:!0}},async run({args:e}){let r=h();await f({method:"DELETE",path:`/v1/images/${e.id}`,auth:r})}})});var Q={};x(Q,{default:()=>Te,defaultOutputPath:()=>W});import{defineCommand as ke}from"citty";import{writeFileSync as Ae,mkdirSync as Ie}from"fs";import{execFileSync as Le}from"child_process";function W(e,r){return r&&r.length>0?r:`pixelvault-export-${e}.tar`}var Oe,Te,Z=m(()=>{"use strict";_();g();w();$();Oe=e=>new Promise(r=>setTimeout(r,e)),Te=ke({meta:{name:"export",description:"Export every image in your project as a tar archive (manifest.json + all images). Your data is always portable \u2014 no lock-in."},args:{output:{type:"string",description:"Write the archive to this path (default: pixelvault-export-<job>.tar)",alias:"o"},extract:{type:"boolean",description:"Extract the archive into a directory after download (requires `tar`)",default:!1},timeout:{type:"string",description:"Max seconds to wait for the export to finish (default: 600)",default:"600"},json:{type:"boolean",description:"Output the final job JSON to stdout",default:!1}},async run({args:e}){let r=h(),o=(Number(e.timeout)||600)*1e3,t;try{t=await f({method:"POST",path:"/v1/export",auth:r})}catch(d){throw d instanceof p&&/in progress/i.test(d.message)?new p("An export for this project is already in progress. Wait for it to finish, then try again.",1):d}n(`Export started \u2014 ${t.image_count} image(s), job ${t.job_id}`);let i=Date.now()+o,s,a=1e3;for(;s=await f({path:`/v1/export-jobs/${encodeURIComponent(t.job_id)}`,auth:r}),s.status!=="complete";){if(s.status==="failed")throw new p(`Export failed: ${s.error??"unknown error"}`,1);if(s.status==="expired")throw new p("Export expired before it could be downloaded. Start a new one.",1);if(Date.now()>i)throw new p(`Timed out after ${e.timeout}s (job still ${s.status}). It may still finish \u2014 re-run to poll, or raise --timeout.`,1);n(` ${s.status}\u2026 ${s.processed_count}/${s.image_count}`),await Oe(a),a=Math.min(Math.round(a*1.5),5e3)}let l=W(t.job_id,e.output),C=`${E()}/v1/export-jobs/${encodeURIComponent(t.job_id)}/download`,y;try{let d=await fetch(C,{headers:{Authorization:`Bearer ${r}`}});if(!d.ok)throw new p(`Failed to download export: HTTP ${d.status}`,1);y=await d.arrayBuffer()}catch(d){throw d instanceof p?d:new p(`Failed to download export: ${d instanceof Error?d.message:String(d)}`,1)}if(y.byteLength===0)throw new p("Downloaded 0 bytes \u2014 refusing to write an empty archive.",1);try{Ae(l,Buffer.from(y))}catch(d){throw new p(`Failed to save ${l}: ${d instanceof Error?d.message:String(d)}`,1)}if(n(`Saved ${l} \u2014 ${s.image_count} image(s), ${y.byteLength} bytes`),e.extract){let d=l.replace(/\.tar$/,"")||`${l}-extracted`;try{Ie(d,{recursive:!0}),Le("tar",["-xf",l,"-C",d],{stdio:"ignore"}),n(`Extracted into ${d}/`)}catch(P){throw new p(`Saved ${l}, but extraction failed (is \`tar\` installed?): ${P instanceof Error?P.message:String(P)}`,1)}}e.json?c({...s,output:l}):u(l)}})});var ee={};x(ee,{default:()=>Fe});import{defineCommand as Ue}from"citty";var Fe,te=m(()=>{"use strict";g();w();Fe=Ue({meta:{name:"whoami",description:"Show current authentication state"},args:{json:{type:"boolean",description:"Output as JSON",default:!1}},async run({args:e}){let r=v(),o=A();!o&&!r.email&&(n("Not authenticated. Run `pixelvault register` or `pixelvault login`."),process.exit(1));let t={email:r.email||"(unknown)",project:r.default_project||"(unknown)",api_key:o?`${o.slice(0,12)}...${o.slice(-4)}`:"(not set)",source:process.env.PIXELVAULT_API_KEY?"env":"config"};e.json?c(t):(u(`Email: ${t.email}`),u(`Project: ${t.project}`),u(`API Key: ${t.api_key} (${t.source})`))}})});var re={};x(re,{default:()=>Ke});import{defineCommand as R}from"citty";var qe,Ne,De,Ke,oe=m(()=>{"use strict";g();w();qe=R({meta:{name:"get",description:"Get a config value"},args:{key:{type:"positional",description:"Config key (api_key, default_project, email, api_url)",required:!0}},async run({args:e}){let o=v()[e.key];o===void 0&&(n(`Key "${e.key}" is not set.`),process.exit(1)),u(String(o))}}),Ne=R({meta:{name:"set",description:"Set a config value"},args:{key:{type:"positional",description:"Config key",required:!0},value:{type:"positional",description:"Config value",required:!0}},async run({args:e}){let r=["api_key","default_project","email","api_url"];r.includes(e.key)||(n(`Invalid key. Valid keys: ${r.join(", ")}`),process.exit(1)),b({[e.key]:e.value}),n(`Set ${e.key} = ${e.key==="api_key"?"***":e.value}`)}}),De=R({meta:{name:"show",description:"Show all config values"},args:{json:{type:"boolean",description:"Output as JSON",default:!1}},async run({args:e}){let r=v();if(e.json)c(r);else{n(`Config: ${T()}`);for(let[o,t]of Object.entries(r)){let i=o==="api_key"&&t?`${t.slice(0,12)}...`:t;u(`${o} = ${i}`)}}}}),Ke=R({meta:{name:"config",description:"Manage CLI configuration"},subCommands:{get:qe,set:Ne,show:De}})});$();w();import{defineCommand as Be,runMain as Ve}from"citty";var Me=Be({meta:{name:"pixelvault",version:"0.2.0",description:"CLI for PixelVault \u2014 agent-first image hosting"},subCommands:{register:()=>Promise.resolve().then(()=>(F(),U)).then(e=>e.default),login:()=>Promise.resolve().then(()=>(N(),q)).then(e=>e.default),upload:()=>Promise.resolve().then(()=>(V(),B)).then(e=>e.default),list:()=>Promise.resolve().then(()=>(J(),M)).then(e=>e.default),get:()=>Promise.resolve().then(()=>(Y(),G)).then(e=>e.default),delete:()=>Promise.resolve().then(()=>(H(),z)).then(e=>e.default),export:()=>Promise.resolve().then(()=>(Z(),Q)).then(e=>e.default),whoami:()=>Promise.resolve().then(()=>(te(),ee)).then(e=>e.default),config:()=>Promise.resolve().then(()=>(oe(),re)).then(e=>e.default)}});Ve(Me).catch(e=>{e instanceof p&&(n(`Error: ${e.message}`),process.exit(e.exitCode)),n(`Error: ${e instanceof Error?e.message:String(e)}`),process.exit(1)});
|
|
3
|
+
`)}function m(e){u(JSON.stringify(e,null,2))}var w=c(()=>{"use strict"});import{readFileSync as ne,writeFileSync as ae,mkdirSync as se}from"fs";import{join as L}from"path";import{homedir as pe}from"os";function T(){return P}function g(){try{let e=ne(P,"utf-8");return JSON.parse(e)}catch{return{}}}function le(e){se(O,{recursive:!0,mode:448}),ae(P,JSON.stringify(e,null,2)+`
|
|
4
|
+
`,{mode:384})}function v(e){let r=g();le({...r,...e})}function I(){return process.env.PIXELVAULT_API_KEY||g().api_key}function k(){return process.env.PIXELVAULT_API_URL||g().api_url||de}function x(){let e=I();if(!e)throw new Error("Not authenticated. Run `pixelvault register` or `pixelvault login`, or set PIXELVAULT_API_KEY.");return e}var O,P,de,y=c(()=>{"use strict";O=L(pe(),".pixelvault"),P=L(O,"config.json"),de="https://api.pixelvault.dev"});async function f(e){let i=`${k()}${e.path}`,t={...e.headers};t["X-PixelVault-Client"]||(t["X-PixelVault-Client"]=ue),e.auth&&(t.Authorization=`Bearer ${e.auth}`);let o;e.formData?o=e.formData:e.body&&(t["Content-Type"]="application/json",o=JSON.stringify(e.body));let a;try{a=await fetch(i,{method:e.method||"GET",headers:t,body:o})}catch(s){throw new p(`Network error: ${s instanceof Error?s.message:"Failed to connect"}`,1)}if(!a.ok){let s;try{s=await a.json()}catch{}let l=s?.error?.message||`HTTP ${a.status}: ${a.statusText}`;throw new p(l,1)}return await a.json()}var ue,b=c(()=>{"use strict";y();$();ue="pixelvault-cli/0.5.2"});import{createInterface as fe}from"readline";function j(e){let r=fe({input:process.stdin,output:process.stderr});return new Promise(i=>{r.question(e,t=>{r.close(),i(t.trim())})})}async function E(e){return process.stdin.isTTY?new Promise(r=>{process.stderr.write(e),process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding("utf-8");let i="",t=o=>{o===`
|
|
5
|
+
`||o==="\r"||o===""?(process.stdin.setRawMode(!1),process.stdin.pause(),process.stdin.removeListener("data",t),process.stderr.write(`
|
|
6
|
+
`),r(i)):o===""?(process.stdin.setRawMode(!1),process.exit(130)):o==="\x7F"||o==="\b"?i=i.slice(0,-1):i+=o};process.stdin.on("data",t)}):j(e)}var A=c(()=>{"use strict"});var U={};_(U,{default:()=>me});import{defineCommand as ce}from"citty";var me,F=c(()=>{"use strict";b();y();A();w();me=ce({meta:{name:"register",description:"Create a new PixelVault account"},args:{email:{type:"string",description:"Email address"},password:{type:"string",description:"Password (min 8 characters). Omit for a passwordless account."},passwordless:{type:"boolean",description:"Create the account without a password (for agents/automation). Set a password later via the web 'Forgot password' flow."}},async run({args:e}){let r=!!process.stdin.isTTY,i=e.email||(r?await j("Email: "):"");i||(n("Email is required. Pass --email <email>."),process.exit(1));let t;e.password?t=e.password:e.passwordless?t=void 0:r?t=await E("Password (leave blank for a passwordless account): ")||void 0:t=void 0,t!==void 0&&t.length<8&&(n("Password must be at least 8 characters."),process.exit(1)),n("Creating account...");let o=await f({method:"POST",path:"/v1/auth/register",body:{email:i,...t?{password:t}:{},attribution:{source:"cli"}}});v({api_key:o.data.default_project.api_keys.live,default_project:o.data.default_project.id,email:o.data.email}),n("Account created. API key saved to ~/.pixelvault/config.json"),n(`Email: ${o.data.email}`),n(`Project: ${o.data.default_project.id}`),(o.data.password_set===!1||!t)&&n("No password set. To enable dashboard login, use 'Forgot password' at https://pixelvault.dev/forgot-password to set one."),o.data.email_verified||n("Verify your email to lift the upload limit for the free tier.")}})});var q={};_(q,{default:()=>ye});import{defineCommand as ge}from"citty";var ye,N=c(()=>{"use strict";b();y();A();w();ye=ge({meta:{name:"login",description:"Log in to your PixelVault account"},args:{email:{type:"string",description:"Email address"},password:{type:"string",description:"Password"}},async run({args:e}){let r=e.email||await j("Email: "),i=e.password||await E("Password: ");(!r||!i)&&(n("Email and password are required."),process.exit(1)),n("Logging in...");let t=await f({method:"POST",path:"/v1/auth/login",body:{email:r,password:i}}),o=t.data.token,a;try{a=(await f({method:"GET",path:"/v1/projects",auth:o})).data[0]?.id}catch{}if(a){let s=await f({method:"POST",path:"/v1/auth/rotate-key",auth:o,body:{project_id:a}});v({api_key:s.data.api_key,default_project:a,email:t.data.email}),n("Logged in. API key saved to ~/.pixelvault/config.json"),n(`Email: ${t.data.email}`),n(`Project: ${a}`)}else n(`Logged in as ${t.data.email}.`),n("Could not auto-configure API key. Set PIXELVAULT_API_KEY manually."),v({email:t.data.email,default_project:void 0}),g().api_key&&n("Warning: the saved api_key may belong to a previous login. Replace it with `pixelvault config set api_key <key>`.")}})});function D(e){let r=/^(\d+)\s*([smhd]?)$/i.exec(e.trim());if(!r)throw new p(`Invalid --expires "${e}". Use e.g. 30m, 12h, 7d, or a number of seconds.`);let i=(r[2]??"").toLowerCase(),t=i==="d"?86400:i==="h"?3600:i==="m"?60:1,o=Number(r[1]??"")*t;if(o<he||o>we)throw new p(`--expires must be between 60s and 30d (got ${o}s).`);return o}var he,we,K=c(()=>{"use strict";$();he=60,we=720*60*60});var B={};_(B,{default:()=>be});import{defineCommand as xe}from"citty";import{readFileSync as _e}from"fs";import{basename as ve}from"path";var be,V=c(()=>{"use strict";b();y();K();w();be=xe({meta:{name:"upload",description:"Upload one or more images"},args:{files:{type:"positional",description:"File path(s) to upload",required:!0},folder:{type:"string",description:"Folder to organize images in"},private:{type:"boolean",description:"Upload privately \u2014 returns a signed URL only holders of the link can open (needs a secret key)",default:!1},expires:{type:"string",description:"Lifetime of a --private signed link: e.g. 30m, 12h, 7d (default 7d; min 60s, max 30d)"},json:{type:"boolean",description:"Output full JSON response",default:!1}},async run({args:e}){let r=x(),i=null;e.expires!==void 0&&(e.private||(n("--expires only applies to --private uploads (it sets the signed link's lifetime)."),process.exit(1)),i=D(String(e.expires))),e.private&&e.folder&&n("Note: --folder is ignored for --private uploads.");let t=e._.length?e._.map(String):[String(e.files)],o=!1,a=[];for(let s of t)try{let l=_e(s),R=ve(s),h=new FormData;h.append("file",new File([l],R)),e.folder&&h.append("folder",e.folder),e.private&&(h.append("visibility","private"),i!==null&&h.append("sign_expires_in",String(i)));let d=await f({method:"POST",path:"/v1/images",auth:r,formData:h});if(e.private&&d.data.visibility!=="private"){o=!0,n(`Refusing to report ${s}: server did not confirm a private upload.`);continue}e.json?a.push(d.data):u(d.data.url)}catch(l){o=!0,n(`Failed to upload ${s}: ${l instanceof Error?l.message:String(l)}`)}e.json&&a.length>0&&m(a.length===1?a[0]:a),o&&process.exit(1)}})});var M={};_(M,{default:()=>je});import{defineCommand as $e}from"citty";var je,J=c(()=>{"use strict";b();y();w();je=$e({meta:{name:"list",description:"List uploaded images"},args:{page:{type:"string",description:"Page number",default:"1"},"per-page":{type:"string",description:"Items per page (max 100)",default:"20"},json:{type:"boolean",description:"Output full JSON response",default:!1}},async run({args:e}){let r=x(),i=new URLSearchParams({page:e.page,per_page:e["per-page"]}),t=await f({path:`/v1/images?${i}`,auth:r});if(e.json)m(t);else for(let o of t.data)u(o.url)}})});var G={};_(G,{applyTransform:()=>X,default:()=>Se});import{defineCommand as ke}from"citty";import{writeFileSync as Ee}from"fs";function X(e,r){if(!r)return e;let i=r.trim().replace(/^[?&]+/,"");if(!i)return e;let t=new URLSearchParams(i).toString();return t?e.includes("?")?`${e}&${t}`:`${e}?${t}`:e}var Se,Y=c(()=>{"use strict";b();y();w();$();Se=ke({meta:{name:"get",description:"Get an image's CDN URL or metadata, or download it \u2014 optionally transformed"},args:{id:{type:"positional",description:"Image ID (e.g. img_abc123)",required:!0},output:{type:"string",description:"Download the image to this file path",alias:"o"},transform:{type:"string",description:'Transform params to apply, e.g. "w=400&fmt=webp", "segment=foreground", "tile=img_logo.png"',alias:"t"},json:{type:"boolean",description:"Output full JSON metadata",default:!1}},async run({args:e}){let r=x(),i=await f({path:`/v1/images/${encodeURIComponent(e.id)}`,auth:r}),t=X(i.data.url,e.transform);if(e.output){let o=e.output,a;try{let s=await fetch(t);if(!s.ok)throw new p(`Failed to download image: HTTP ${s.status}`,1);a=await s.arrayBuffer()}catch(s){throw s instanceof p?s:new p(`Failed to download image: ${s instanceof Error?s.message:String(s)}`,1)}if(a.byteLength===0)throw new p("Downloaded 0 bytes \u2014 refusing to write an empty file",1);try{Ee(o,Buffer.from(a))}catch(s){throw new p(`Failed to save ${o}: ${s instanceof Error?s.message:String(s)}`,1)}n(`Saved ${o}`),e.json?m(e.transform?{...i,transformed_url:t,output:o}:{...i,output:o}):u(t);return}e.json?m(e.transform?{...i,transformed_url:t}:i):u(t)}})});var z={};_(z,{default:()=>Ce});import{defineCommand as Re}from"citty";var Ce,H=c(()=>{"use strict";b();y();Ce=Re({meta:{name:"delete",description:"Delete an image by ID"},args:{id:{type:"positional",description:"Image ID (e.g. img_abc123)",required:!0}},async run({args:e}){let r=x();await f({method:"DELETE",path:`/v1/images/${e.id}`,auth:r})}})});var Q={};_(Q,{default:()=>Te,defaultOutputPath:()=>W});import{defineCommand as Pe}from"citty";import{writeFileSync as Ie,mkdirSync as Ae}from"fs";import{execFileSync as Le}from"child_process";function W(e,r){return r&&r.length>0?r:`pixelvault-export-${e}.tar`}var Oe,Te,Z=c(()=>{"use strict";b();y();w();$();Oe=e=>new Promise(r=>setTimeout(r,e)),Te=Pe({meta:{name:"export",description:"Export every image in your project as a tar archive (manifest.json + all images). Your data is always portable \u2014 no lock-in."},args:{output:{type:"string",description:"Write the archive to this path (default: pixelvault-export-<job>.tar)",alias:"o"},extract:{type:"boolean",description:"Extract the archive into a directory after download (requires `tar`)",default:!1},timeout:{type:"string",description:"Max seconds to wait for the export to finish (default: 600)",default:"600"},json:{type:"boolean",description:"Output the final job JSON to stdout",default:!1}},async run({args:e}){let r=x(),i=(Number(e.timeout)||600)*1e3,t;try{t=await f({method:"POST",path:"/v1/export",auth:r})}catch(d){throw d instanceof p&&/in progress/i.test(d.message)?new p("An export for this project is already in progress. Wait for it to finish, then try again.",1):d}n(`Export started \u2014 ${t.image_count} image(s), job ${t.job_id}`);let o=Date.now()+i,a,s=1e3;for(;a=await f({path:`/v1/export-jobs/${encodeURIComponent(t.job_id)}`,auth:r}),a.status!=="complete";){if(a.status==="failed")throw new p(`Export failed: ${a.error??"unknown error"}`,1);if(a.status==="expired")throw new p("Export expired before it could be downloaded. Start a new one.",1);if(Date.now()>o)throw new p(`Timed out after ${e.timeout}s (job still ${a.status}). It may still finish \u2014 re-run to poll, or raise --timeout.`,1);n(` ${a.status}\u2026 ${a.processed_count}/${a.image_count}`),await Oe(s),s=Math.min(Math.round(s*1.5),5e3)}let l=W(t.job_id,e.output),R=`${k()}/v1/export-jobs/${encodeURIComponent(t.job_id)}/download`,h;try{let d=await fetch(R,{headers:{Authorization:`Bearer ${r}`}});if(!d.ok)throw new p(`Failed to download export: HTTP ${d.status}`,1);h=await d.arrayBuffer()}catch(d){throw d instanceof p?d:new p(`Failed to download export: ${d instanceof Error?d.message:String(d)}`,1)}if(h.byteLength===0)throw new p("Downloaded 0 bytes \u2014 refusing to write an empty archive.",1);try{Ie(l,Buffer.from(h))}catch(d){throw new p(`Failed to save ${l}: ${d instanceof Error?d.message:String(d)}`,1)}if(n(`Saved ${l} \u2014 ${a.image_count} image(s), ${h.byteLength} bytes`),e.extract){let d=l.replace(/\.tar$/,"")||`${l}-extracted`;try{Ae(d,{recursive:!0}),Le("tar",["-xf",l,"-C",d],{stdio:"ignore"}),n(`Extracted into ${d}/`)}catch(C){throw new p(`Saved ${l}, but extraction failed (is \`tar\` installed?): ${C instanceof Error?C.message:String(C)}`,1)}}e.json?m({...a,output:l}):u(l)}})});var ee={};_(ee,{default:()=>Fe});import{defineCommand as Ue}from"citty";var Fe,te=c(()=>{"use strict";y();w();Fe=Ue({meta:{name:"whoami",description:"Show current authentication state"},args:{json:{type:"boolean",description:"Output as JSON",default:!1}},async run({args:e}){let r=g(),i=I();!i&&!r.email&&(n("Not authenticated. Run `pixelvault register` or `pixelvault login`."),process.exit(1));let t={email:r.email||"(unknown)",project:r.default_project||"(unknown)",api_key:i?`${i.slice(0,12)}...${i.slice(-4)}`:"(not set)",source:process.env.PIXELVAULT_API_KEY?"env":"config",identity_source:"cached"};if(e.json)m(t);else{let o=a=>a?" (cached, not verified for this key)":"";u(`Email: ${t.email}${o(r.email)}`),u(`Project: ${t.project}${o(r.default_project)}`),u(`API Key: ${t.api_key} (${t.source})`)}}})});var re={};_(re,{default:()=>Ke});import{defineCommand as S}from"citty";var qe,Ne,De,Ke,ie=c(()=>{"use strict";y();w();qe=S({meta:{name:"get",description:"Get a config value"},args:{key:{type:"positional",description:"Config key (api_key, default_project, email, api_url)",required:!0}},async run({args:e}){let i=g()[e.key];i===void 0&&(n(`Key "${e.key}" is not set.`),process.exit(1)),u(String(i))}}),Ne=S({meta:{name:"set",description:"Set a config value"},args:{key:{type:"positional",description:"Config key",required:!0},value:{type:"positional",description:"Config value",required:!0}},async run({args:e}){let r=["api_key","default_project","email","api_url"];r.includes(e.key)||(n(`Invalid key. Valid keys: ${r.join(", ")}`),process.exit(1)),e.key==="api_key"&&e.value!==g().api_key?v({api_key:e.value,email:void 0,default_project:void 0}):v({[e.key]:e.value}),n(`Set ${e.key} = ${e.key==="api_key"?"***":e.value}`)}}),De=S({meta:{name:"show",description:"Show all config values"},args:{json:{type:"boolean",description:"Output as JSON",default:!1}},async run({args:e}){let r=g();if(e.json)m(r);else{n(`Config: ${T()}`);for(let[i,t]of Object.entries(r)){let o=i==="api_key"&&t?`${t.slice(0,12)}...`:t;u(`${i} = ${o}`)}}}}),Ke=S({meta:{name:"config",description:"Manage CLI configuration"},subCommands:{get:qe,set:Ne,show:De}})});$();w();import{defineCommand as Be,runMain as Ve}from"citty";var Me=Be({meta:{name:"pixelvault",version:"0.2.0",description:"CLI for PixelVault \u2014 agent-first image hosting"},subCommands:{register:()=>Promise.resolve().then(()=>(F(),U)).then(e=>e.default),login:()=>Promise.resolve().then(()=>(N(),q)).then(e=>e.default),upload:()=>Promise.resolve().then(()=>(V(),B)).then(e=>e.default),list:()=>Promise.resolve().then(()=>(J(),M)).then(e=>e.default),get:()=>Promise.resolve().then(()=>(Y(),G)).then(e=>e.default),delete:()=>Promise.resolve().then(()=>(H(),z)).then(e=>e.default),export:()=>Promise.resolve().then(()=>(Z(),Q)).then(e=>e.default),whoami:()=>Promise.resolve().then(()=>(te(),ee)).then(e=>e.default),config:()=>Promise.resolve().then(()=>(ie(),re)).then(e=>e.default)}});Ve(Me).catch(e=>{e instanceof p&&(n(`Error: ${e.message}`),process.exit(e.exitCode)),n(`Error: ${e instanceof Error?e.message:String(e)}`),process.exit(1)});
|
|
7
7
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/errors.ts","../src/lib/output.ts","../src/lib/config.ts","../src/lib/client.ts","../src/lib/prompt.ts","../src/commands/register.ts","../src/commands/login.ts","../src/lib/duration.ts","../src/commands/upload.ts","../src/commands/list.ts","../src/commands/get.ts","../src/commands/delete.ts","../src/commands/export.ts","../src/commands/whoami.ts","../src/commands/config.ts","../src/index.ts"],"sourcesContent":["export class CliError extends Error {\n exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"CliError\";\n this.exitCode = exitCode;\n }\n}\n","/**\n * Write to stdout (for machine-parseable output — URLs, JSON).\n */\nexport function stdout(text: string): void {\n process.stdout.write(text + \"\\n\");\n}\n\n/**\n * Write to stderr (for human messages — prompts, progress, errors).\n */\nexport function stderr(text: string): void {\n process.stderr.write(text + \"\\n\");\n}\n\n/**\n * Output data as JSON to stdout.\n */\nexport function jsonOut(data: unknown): void {\n stdout(JSON.stringify(data, null, 2));\n}\n\n/**\n * Print an error message to stderr and exit.\n */\nexport function fatal(message: string, exitCode = 1): never {\n stderr(`Error: ${message}`);\n process.exit(exitCode);\n}\n","import { readFileSync, writeFileSync, mkdirSync, chmodSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport interface Config {\n api_key?: string;\n default_project?: string;\n email?: string;\n api_url?: string;\n}\n\nconst CONFIG_DIR = join(homedir(), \".pixelvault\");\nconst CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\nconst DEFAULT_API_URL = \"https://api.pixelvault.dev\";\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n\nexport function readConfig(): Config {\n try {\n const raw = readFileSync(CONFIG_FILE, \"utf-8\");\n return JSON.parse(raw) as Config;\n } catch {\n return {};\n }\n}\n\nexport function writeConfig(config: Config): void {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\nexport function updateConfig(updates: Partial<Config>): void {\n const config = readConfig();\n writeConfig({ ...config, ...updates });\n}\n\nexport function getApiKey(): string | undefined {\n return process.env[\"PIXELVAULT_API_KEY\"] || readConfig().api_key;\n}\n\nexport function getApiUrl(): string {\n return (\n process.env[\"PIXELVAULT_API_URL\"] ||\n readConfig().api_url ||\n DEFAULT_API_URL\n );\n}\n\nexport function requireApiKey(): string {\n const key = getApiKey();\n if (!key) {\n throw new Error(\n \"Not authenticated. Run `pixelvault register` or `pixelvault login`, or set PIXELVAULT_API_KEY.\"\n );\n }\n return key;\n}\n","import { getApiUrl } from \"./config.js\";\nimport { CliError } from \"./errors.js\";\n\ninterface RequestOptions {\n method?: string;\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n formData?: FormData;\n}\n\ninterface ApiError {\n error: { code: string; message: string };\n}\n\n// Identifies the CLI to the API so signups made through it can be attributed to\n// this channel (server reads X-PixelVault-Client at register/device-login — see\n// pixelvault docs/specs/lead-attribution.md). Keep the version in sync with\n// package.json on release.\nconst CLIENT_ID = \"pixelvault-cli/0.5.1\";\n\nexport async function apiRequest<T>(\n options: RequestOptions & { auth?: string }\n): Promise<T> {\n const baseUrl = getApiUrl();\n const url = `${baseUrl}${options.path}`;\n\n const headers: Record<string, string> = { ...options.headers };\n\n if (!headers[\"X-PixelVault-Client\"]) {\n headers[\"X-PixelVault-Client\"] = CLIENT_ID;\n }\n\n if (options.auth) {\n headers[\"Authorization\"] = `Bearer ${options.auth}`;\n }\n\n let fetchBody: BodyInit | undefined;\n\n if (options.formData) {\n fetchBody = options.formData;\n } else if (options.body) {\n headers[\"Content-Type\"] = \"application/json\";\n fetchBody = JSON.stringify(options.body);\n }\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: options.method || \"GET\",\n headers,\n body: fetchBody,\n });\n } catch (err) {\n throw new CliError(\n `Network error: ${err instanceof Error ? err.message : \"Failed to connect\"}`,\n 1\n );\n }\n\n if (!res.ok) {\n let errorBody: ApiError | undefined;\n try {\n errorBody = (await res.json()) as ApiError;\n } catch {\n // ignore parse failures\n }\n\n const message =\n errorBody?.error?.message || `HTTP ${res.status}: ${res.statusText}`;\n throw new CliError(message, 1);\n }\n\n return (await res.json()) as T;\n}\n","import { createInterface } from \"node:readline\";\n\n/**\n * Prompt the user for input via stderr (keeps stdout clean for agents).\n */\nexport function prompt(question: string): Promise<string> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\n/**\n * Prompt for a password (input is not echoed).\n * Uses raw mode to suppress echo when available, falls back to regular prompt.\n */\nexport async function promptPassword(question: string): Promise<string> {\n if (!process.stdin.isTTY) {\n return prompt(question);\n }\n\n return new Promise((resolve) => {\n process.stderr.write(question);\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.setEncoding(\"utf-8\");\n\n let password = \"\";\n\n const onData = (char: string) => {\n if (char === \"\\n\" || char === \"\\r\" || char === \"\\u0004\") {\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.stdin.removeListener(\"data\", onData);\n process.stderr.write(\"\\n\");\n resolve(password);\n } else if (char === \"\\u0003\") {\n // Ctrl+C\n process.stdin.setRawMode(false);\n process.exit(130);\n } else if (\n char === \"\\u007F\" ||\n char === \"\\b\"\n ) {\n // Backspace\n password = password.slice(0, -1);\n } else {\n password += char;\n }\n };\n\n process.stdin.on(\"data\", onData);\n });\n}\n","import { defineCommand } from \"citty\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { updateConfig } from \"../lib/config.js\";\nimport { prompt, promptPassword } from \"../lib/prompt.js\";\nimport { stderr } from \"../lib/output.js\";\n\ninterface RegisterResponse {\n data: {\n account_id: string;\n email: string;\n email_verified: boolean;\n // Optional: older API versions omit it. Absent → treat as \"unknown\".\n password_set?: boolean;\n plan: string;\n default_project: {\n id: string;\n name: string;\n api_keys: { live: string };\n };\n };\n}\n\nexport default defineCommand({\n meta: {\n name: \"register\",\n description: \"Create a new PixelVault account\",\n },\n args: {\n email: {\n type: \"string\",\n description: \"Email address\",\n },\n password: {\n type: \"string\",\n description: \"Password (min 8 characters). Omit for a passwordless account.\",\n },\n passwordless: {\n type: \"boolean\",\n description:\n \"Create the account without a password (for agents/automation). Set a password later via the web 'Forgot password' flow.\",\n },\n },\n async run({ args }) {\n const interactive = Boolean(process.stdin.isTTY);\n\n // Email is always required. Only prompt when we have a TTY — in a headless\n // (agent) run, missing --email is a hard error rather than a hung prompt.\n const email = args.email || (interactive ? await prompt(\"Email: \") : \"\");\n if (!email) {\n stderr(\"Email is required. Pass --email <email>.\");\n process.exit(1);\n }\n\n // Resolve the password. Precedence: explicit --password > --passwordless >\n // interactive prompt (blank = passwordless) > headless default (passwordless,\n // so a non-TTY run never blocks on a hidden prompt).\n let password: string | undefined;\n if (args.password) {\n password = args.password;\n } else if (args.passwordless) {\n password = undefined;\n } else if (interactive) {\n const entered = await promptPassword(\n \"Password (leave blank for a passwordless account): \"\n );\n password = entered || undefined;\n } else {\n password = undefined;\n }\n\n if (password !== undefined && password.length < 8) {\n stderr(\"Password must be at least 8 characters.\");\n process.exit(1);\n }\n\n stderr(\"Creating account...\");\n\n const res = await apiRequest<RegisterResponse>({\n method: \"POST\",\n path: \"/v1/auth/register\",\n // Only send the password field when one was chosen — omitting it creates\n // a passwordless account server-side. `attribution.source: \"cli\"` buckets\n // the signup to this channel (server treats it as an untrusted hint that\n // wins over the derived source — see lead-attribution spec).\n body: {\n email,\n ...(password ? { password } : {}),\n attribution: { source: \"cli\" },\n },\n });\n\n updateConfig({\n api_key: res.data.default_project.api_keys.live,\n default_project: res.data.default_project.id,\n email: res.data.email,\n });\n\n stderr(`Account created. API key saved to ~/.pixelvault/config.json`);\n stderr(`Email: ${res.data.email}`);\n stderr(`Project: ${res.data.default_project.id}`);\n\n // password_set === false (or a passwordless request on an older API) means\n // there's no dashboard login yet — tell the user how to claim one.\n const passwordless = res.data.password_set === false || !password;\n if (passwordless) {\n stderr(\n \"No password set. To enable dashboard login, use 'Forgot password' at \" +\n \"https://pixelvault.dev/forgot-password to set one.\"\n );\n }\n\n if (!res.data.email_verified) {\n stderr(\"Verify your email to lift the upload limit for the free tier.\");\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { updateConfig, getApiUrl } from \"../lib/config.js\";\nimport { prompt, promptPassword } from \"../lib/prompt.js\";\nimport { stderr } from \"../lib/output.js\";\n\ninterface LoginResponse {\n data: {\n token: string;\n account_id: string;\n email: string;\n email_verified: boolean;\n };\n}\n\ninterface RotateKeyResponse {\n data: {\n key_id: string;\n api_key: string;\n project_id: string;\n environment: string;\n };\n}\n\ninterface ProjectsResponse {\n data: Array<{ id: string; name: string }>;\n}\n\nexport default defineCommand({\n meta: {\n name: \"login\",\n description: \"Log in to your PixelVault account\",\n },\n args: {\n email: {\n type: \"string\",\n description: \"Email address\",\n },\n password: {\n type: \"string\",\n description: \"Password\",\n },\n },\n async run({ args }) {\n const email = args.email || (await prompt(\"Email: \"));\n const password = args.password || (await promptPassword(\"Password: \"));\n\n if (!email || !password) {\n stderr(\"Email and password are required.\");\n process.exit(1);\n }\n\n stderr(\"Logging in...\");\n\n // Step 1: Login to get JWT\n const loginRes = await apiRequest<LoginResponse>({\n method: \"POST\",\n path: \"/v1/auth/login\",\n body: { email, password },\n });\n\n const token = loginRes.data.token;\n\n // Step 2: Get projects to find default project ID\n let projectId: string | undefined;\n try {\n const projectsRes = await apiRequest<ProjectsResponse>({\n method: \"GET\",\n path: \"/v1/projects\",\n auth: token,\n });\n projectId = projectsRes.data[0]?.id;\n } catch {\n // Projects endpoint may not exist yet — continue without project ID\n }\n\n // Step 3: Rotate key to get a fresh API key\n if (projectId) {\n const rotateRes = await apiRequest<RotateKeyResponse>({\n method: \"POST\",\n path: \"/v1/auth/rotate-key\",\n auth: token,\n body: { project_id: projectId },\n });\n\n updateConfig({\n api_key: rotateRes.data.api_key,\n default_project: projectId,\n email: loginRes.data.email,\n });\n\n stderr(`Logged in. API key saved to ~/.pixelvault/config.json`);\n stderr(`Email: ${loginRes.data.email}`);\n stderr(`Project: ${projectId}`);\n } else {\n // Fallback: save JWT for manual key setup\n stderr(`Logged in as ${loginRes.data.email}.`);\n stderr(\n `Could not auto-configure API key. Set PIXELVAULT_API_KEY manually.`\n );\n updateConfig({ email: loginRes.data.email });\n }\n },\n});\n","import { CliError } from \"./errors.js\";\n\n/** Signed-URL lifetime bounds, matching the API's `sign_expires_in` (60s..30d). */\nexport const MIN_EXPIRES_SECONDS = 60;\nexport const MAX_EXPIRES_SECONDS = 30 * 24 * 60 * 60;\n\n/**\n * Parse a signed-link lifetime like `30m`, `12h`, `7d`, `90s`, or a bare number\n * of seconds, into seconds. Rejects anything outside the API's accepted range so\n * a bad value fails locally with a clear message instead of a 400 from the server.\n */\nexport function parseExpires(input: string): number {\n const match = /^(\\d+)\\s*([smhd]?)$/i.exec(input.trim());\n if (!match) {\n throw new CliError(\n `Invalid --expires \"${input}\". Use e.g. 30m, 12h, 7d, or a number of seconds.`\n );\n }\n\n const unit = (match[2] ?? \"\").toLowerCase();\n const multiplier = unit === \"d\" ? 86400 : unit === \"h\" ? 3600 : unit === \"m\" ? 60 : 1;\n const seconds = Number(match[1] ?? \"\") * multiplier;\n\n if (seconds < MIN_EXPIRES_SECONDS || seconds > MAX_EXPIRES_SECONDS) {\n throw new CliError(\n `--expires must be between 60s and 30d (got ${seconds}s).`\n );\n }\n\n return seconds;\n}\n","import { defineCommand } from \"citty\";\nimport { readFileSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { requireApiKey } from \"../lib/config.js\";\nimport { parseExpires } from \"../lib/duration.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\n\ninterface UploadResponse {\n data: {\n id: string;\n url: string;\n visibility?: \"public\" | \"private\";\n mime_type: string;\n size: number;\n filename: string;\n folder: string | null;\n created_at: string;\n signed_expires?: number;\n };\n}\n\nexport default defineCommand({\n meta: {\n name: \"upload\",\n description: \"Upload one or more images\",\n },\n args: {\n files: {\n type: \"positional\",\n description: \"File path(s) to upload\",\n required: true,\n },\n folder: {\n type: \"string\",\n description: \"Folder to organize images in\",\n },\n private: {\n type: \"boolean\",\n description:\n \"Upload privately — returns a signed URL only holders of the link can open (needs a secret key)\",\n default: false,\n },\n expires: {\n type: \"string\",\n description:\n \"Lifetime of a --private signed link: e.g. 30m, 12h, 7d (default 7d; min 60s, max 30d)\",\n },\n json: {\n type: \"boolean\",\n description: \"Output full JSON response\",\n default: false,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n\n // Resolve the signed-link lifetime up front so a bad value fails before any\n // upload happens. `--expires` only makes sense for a private (signed) URL.\n let signExpires: number | null = null;\n if (args.expires !== undefined) {\n if (!args.private) {\n stderr(\"--expires only applies to --private uploads (it sets the signed link's lifetime).\");\n process.exit(1);\n }\n signExpires = parseExpires(String(args.expires));\n }\n\n if (args.private && args.folder) {\n stderr(\"Note: --folder is ignored for --private uploads.\");\n }\n\n // citty passes positional as a single string; we handle globs via shell expansion\n const files = Array.isArray(args.files) ? args.files : [args.files];\n let hadError = false;\n\n const results: UploadResponse[\"data\"][] = [];\n\n for (const filePath of files) {\n try {\n const buffer = readFileSync(filePath);\n const fileName = basename(filePath);\n\n const formData = new FormData();\n formData.append(\n \"file\",\n new File([buffer], fileName)\n );\n\n if (args.folder) {\n formData.append(\"folder\", args.folder);\n }\n\n if (args.private) {\n // The server routes private images to a signed-URL-only path and\n // returns the ready-to-share signed URL in `data.url`. A user-supplied\n // folder is ignored for private uploads (server-side).\n formData.append(\"visibility\", \"private\");\n if (signExpires !== null) {\n formData.append(\"sign_expires_in\", String(signExpires));\n }\n }\n\n const res = await apiRequest<UploadResponse>({\n method: \"POST\",\n path: \"/v1/images\",\n auth: apiKey,\n formData,\n });\n\n // Fail closed: if we asked for private but the server didn't confirm it,\n // don't hand back a URL the user would wrongly trust as private.\n if (args.private && res.data.visibility !== \"private\") {\n hadError = true;\n stderr(`Refusing to report ${filePath}: server did not confirm a private upload.`);\n continue;\n }\n\n if (args.json) {\n results.push(res.data);\n } else {\n stdout(res.data.url);\n }\n } catch (err) {\n hadError = true;\n stderr(\n `Failed to upload ${filePath}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n if (args.json && results.length > 0) {\n jsonOut(results.length === 1 ? results[0] : results);\n }\n\n if (hadError) {\n process.exit(1);\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { requireApiKey } from \"../lib/config.js\";\nimport { stdout, jsonOut } from \"../lib/output.js\";\n\ninterface ListResponse {\n data: Array<{\n id: string;\n url: string;\n mime_type: string;\n size: number;\n filename: string;\n folder: string | null;\n created_at: string;\n }>;\n meta: {\n total: number;\n page: number;\n per_page: number;\n };\n}\n\nexport default defineCommand({\n meta: {\n name: \"list\",\n description: \"List uploaded images\",\n },\n args: {\n page: {\n type: \"string\",\n description: \"Page number\",\n default: \"1\",\n },\n \"per-page\": {\n type: \"string\",\n description: \"Items per page (max 100)\",\n default: \"20\",\n },\n json: {\n type: \"boolean\",\n description: \"Output full JSON response\",\n default: false,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n\n const params = new URLSearchParams({\n page: args.page,\n per_page: args[\"per-page\"],\n });\n\n const res = await apiRequest<ListResponse>({\n path: `/v1/images?${params}`,\n auth: apiKey,\n });\n\n if (args.json) {\n jsonOut(res);\n } else {\n for (const img of res.data) {\n stdout(img.url);\n }\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { writeFileSync } from \"node:fs\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { requireApiKey } from \"../lib/config.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\nimport { CliError } from \"../lib/errors.js\";\n\ninterface GetResponse {\n data: {\n id: string;\n url: string;\n mime_type: string;\n size: number;\n filename: string;\n folder: string | null;\n created_at: string;\n };\n}\n\n/**\n * Append a transform query string to a CDN URL. Accepts params with or without a\n * leading `?`/`&` (e.g. `w=400&fmt=webp`, `?segment=foreground`). See the transform\n * docs: https://pixelvault.dev/docs#transforms\n *\n * The params are reserialized through URLSearchParams so reserved characters in\n * values are percent-encoded — without this a hex color like `background=#ffaa00`\n * would be parsed as a URL fragment and lost. Idempotent for already-encoded input.\n */\nexport function applyTransform(url: string, transform?: string): string {\n if (!transform) return url;\n const raw = transform.trim().replace(/^[?&]+/, \"\");\n if (!raw) return url;\n const params = new URLSearchParams(raw).toString();\n if (!params) return url;\n return url.includes(\"?\") ? `${url}&${params}` : `${url}?${params}`;\n}\n\nexport default defineCommand({\n meta: {\n name: \"get\",\n description:\n \"Get an image's CDN URL or metadata, or download it — optionally transformed\",\n },\n args: {\n id: {\n type: \"positional\",\n description: \"Image ID (e.g. img_abc123)\",\n required: true,\n },\n output: {\n type: \"string\",\n description: \"Download the image to this file path\",\n alias: \"o\",\n },\n transform: {\n type: \"string\",\n description:\n 'Transform params to apply, e.g. \"w=400&fmt=webp\", \"segment=foreground\", \"tile=img_logo.png\"',\n alias: \"t\",\n },\n json: {\n type: \"boolean\",\n description: \"Output full JSON metadata\",\n default: false,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n\n const res = await apiRequest<GetResponse>({\n path: `/v1/images/${encodeURIComponent(args.id)}`,\n auth: apiKey,\n });\n\n const url = applyTransform(res.data.url, args.transform as string | undefined);\n\n // Download mode: fetch the (possibly transformed) bytes to disk.\n if (args.output) {\n const output = args.output as string;\n let bytes: ArrayBuffer;\n try {\n const dl = await fetch(url);\n if (!dl.ok) {\n throw new CliError(`Failed to download image: HTTP ${dl.status}`, 1);\n }\n bytes = await dl.arrayBuffer();\n } catch (err) {\n if (err instanceof CliError) throw err;\n throw new CliError(\n `Failed to download image: ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n // Refuse to write an empty file — a 200 with an empty/truncated body would\n // otherwise report success and leave a broken image that agents chain on.\n if (bytes.byteLength === 0) {\n throw new CliError(\"Downloaded 0 bytes — refusing to write an empty file\", 1);\n }\n try {\n writeFileSync(output, Buffer.from(bytes));\n } catch (err) {\n throw new CliError(\n `Failed to save ${output}: ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n stderr(`Saved ${output}`);\n // Honor --json even in download mode so a caller that always requests JSON\n // gets a stable stdout contract regardless of -o.\n if (args.json) {\n jsonOut(\n args.transform ? { ...res, transformed_url: url, output } : { ...res, output },\n );\n } else {\n stdout(url); // URL to stdout (machine-parseable), confirmation to stderr\n }\n return;\n }\n\n if (args.json) {\n // When a transform is applied there's no separate record for it, so surface\n // the resolved URL alongside the raw metadata.\n jsonOut(args.transform ? { ...res, transformed_url: url } : res);\n } else {\n stdout(url);\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { requireApiKey } from \"../lib/config.js\";\nimport { stderr } from \"../lib/output.js\";\n\nexport default defineCommand({\n meta: {\n name: \"delete\",\n description: \"Delete an image by ID\",\n },\n args: {\n id: {\n type: \"positional\",\n description: \"Image ID (e.g. img_abc123)\",\n required: true,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n\n await apiRequest<{ success: boolean }>({\n method: \"DELETE\",\n path: `/v1/images/${args.id}`,\n auth: apiKey,\n });\n\n // Silent on success (agent-friendly)\n },\n});\n","import { defineCommand } from \"citty\";\nimport { writeFileSync, mkdirSync } from \"node:fs\";\nimport { execFileSync } from \"node:child_process\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { getApiUrl, requireApiKey } from \"../lib/config.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\nimport { CliError } from \"../lib/errors.js\";\n\ninterface StartResponse {\n job_id: string;\n status: string;\n image_count: number;\n status_url: string;\n}\n\ninterface StatusResponse {\n id: string;\n status: \"pending\" | \"processing\" | \"complete\" | \"failed\" | \"expired\";\n image_count: number;\n processed_count: number;\n bytes: number;\n created_at: string;\n expires_at: string;\n download_url?: string;\n error?: string;\n}\n\n/** Default archive filename when `--output` isn't given. Pure, for tests. */\nexport function defaultOutputPath(jobId: string, out?: string): string {\n return out && out.length > 0 ? out : `pixelvault-export-${jobId}.tar`;\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport default defineCommand({\n meta: {\n name: \"export\",\n description:\n \"Export every image in your project as a tar archive (manifest.json + all images). Your data is always portable — no lock-in.\",\n },\n args: {\n output: {\n type: \"string\",\n description: \"Write the archive to this path (default: pixelvault-export-<job>.tar)\",\n alias: \"o\",\n },\n extract: {\n type: \"boolean\",\n description: \"Extract the archive into a directory after download (requires `tar`)\",\n default: false,\n },\n timeout: {\n type: \"string\",\n description: \"Max seconds to wait for the export to finish (default: 600)\",\n default: \"600\",\n },\n json: {\n type: \"boolean\",\n description: \"Output the final job JSON to stdout\",\n default: false,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n const timeoutMs = (Number(args.timeout) || 600) * 1000;\n\n // 1. Start the async export job (project-scoped by the secret key).\n let start: StartResponse;\n try {\n start = await apiRequest<StartResponse>({ method: \"POST\", path: \"/v1/export\", auth: apiKey });\n } catch (err) {\n // Surface the \"already running\" case helpfully.\n if (err instanceof CliError && /in progress/i.test(err.message)) {\n throw new CliError(\n \"An export for this project is already in progress. Wait for it to finish, then try again.\",\n 1,\n );\n }\n throw err;\n }\n stderr(`Export started — ${start.image_count} image(s), job ${start.job_id}`);\n\n // 2. Poll until the archive is ready (backoff 1s → 5s).\n const deadline = Date.now() + timeoutMs;\n let status: StatusResponse;\n let delay = 1000;\n for (;;) {\n status = await apiRequest<StatusResponse>({\n path: `/v1/export-jobs/${encodeURIComponent(start.job_id)}`,\n auth: apiKey,\n });\n if (status.status === \"complete\") break;\n if (status.status === \"failed\") {\n throw new CliError(`Export failed: ${status.error ?? \"unknown error\"}`, 1);\n }\n if (status.status === \"expired\") {\n throw new CliError(\"Export expired before it could be downloaded. Start a new one.\", 1);\n }\n if (Date.now() > deadline) {\n throw new CliError(\n `Timed out after ${args.timeout}s (job still ${status.status}). It may still finish — re-run to poll, or raise --timeout.`,\n 1,\n );\n }\n stderr(` ${status.status}… ${status.processed_count}/${status.image_count}`);\n await sleep(delay);\n delay = Math.min(Math.round(delay * 1.5), 5000);\n }\n\n // 3. Download the tar. apiRequest parses JSON, so fetch the raw bytes directly\n // (the endpoint requires the same Bearer auth).\n const out = defaultOutputPath(start.job_id, args.output as string | undefined);\n const downloadUrl = `${getApiUrl()}/v1/export-jobs/${encodeURIComponent(start.job_id)}/download`;\n let bytes: ArrayBuffer;\n try {\n const dl = await fetch(downloadUrl, { headers: { Authorization: `Bearer ${apiKey}` } });\n if (!dl.ok) throw new CliError(`Failed to download export: HTTP ${dl.status}`, 1);\n bytes = await dl.arrayBuffer();\n } catch (err) {\n if (err instanceof CliError) throw err;\n throw new CliError(\n `Failed to download export: ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n // A 200 with an empty/truncated body must not report success for a backup.\n if (bytes.byteLength === 0) {\n throw new CliError(\"Downloaded 0 bytes — refusing to write an empty archive.\", 1);\n }\n try {\n writeFileSync(out, Buffer.from(bytes));\n } catch (err) {\n throw new CliError(\n `Failed to save ${out}: ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n stderr(`Saved ${out} — ${status.image_count} image(s), ${bytes.byteLength} bytes`);\n\n // 4. Optional extraction via the system `tar`.\n if (args.extract) {\n const dir = out.replace(/\\.tar$/, \"\") || `${out}-extracted`;\n try {\n mkdirSync(dir, { recursive: true });\n execFileSync(\"tar\", [\"-xf\", out, \"-C\", dir], { stdio: \"ignore\" });\n stderr(`Extracted into ${dir}/`);\n } catch (err) {\n throw new CliError(\n `Saved ${out}, but extraction failed (is \\`tar\\` installed?): ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n }\n\n if (args.json) {\n jsonOut({ ...status, output: out });\n } else {\n stdout(out); // machine-parseable path on stdout; progress went to stderr\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { readConfig, getApiKey } from \"../lib/config.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\n\nexport default defineCommand({\n meta: {\n name: \"whoami\",\n description: \"Show current authentication state\",\n },\n args: {\n json: {\n type: \"boolean\",\n description: \"Output as JSON\",\n default: false,\n },\n },\n async run({ args }) {\n const config = readConfig();\n const apiKey = getApiKey();\n\n if (!apiKey && !config.email) {\n stderr(\"Not authenticated. Run `pixelvault register` or `pixelvault login`.\");\n process.exit(1);\n }\n\n const info = {\n email: config.email || \"(unknown)\",\n project: config.default_project || \"(unknown)\",\n api_key: apiKey\n ? `${apiKey.slice(0, 12)}...${apiKey.slice(-4)}`\n : \"(not set)\",\n source: process.env[\"PIXELVAULT_API_KEY\"] ? \"env\" : \"config\",\n };\n\n if (args.json) {\n jsonOut(info);\n } else {\n stdout(`Email: ${info.email}`);\n stdout(`Project: ${info.project}`);\n stdout(`API Key: ${info.api_key} (${info.source})`);\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { readConfig, updateConfig, getConfigPath } from \"../lib/config.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\n\nconst configGet = defineCommand({\n meta: {\n name: \"get\",\n description: \"Get a config value\",\n },\n args: {\n key: {\n type: \"positional\",\n description: \"Config key (api_key, default_project, email, api_url)\",\n required: true,\n },\n },\n async run({ args }) {\n const config = readConfig();\n const value = config[args.key as keyof typeof config];\n\n if (value === undefined) {\n stderr(`Key \"${args.key}\" is not set.`);\n process.exit(1);\n }\n\n stdout(String(value));\n },\n});\n\nconst configSet = defineCommand({\n meta: {\n name: \"set\",\n description: \"Set a config value\",\n },\n args: {\n key: {\n type: \"positional\",\n description: \"Config key\",\n required: true,\n },\n value: {\n type: \"positional\",\n description: \"Config value\",\n required: true,\n },\n },\n async run({ args }) {\n const validKeys = [\"api_key\", \"default_project\", \"email\", \"api_url\"];\n if (!validKeys.includes(args.key)) {\n stderr(`Invalid key. Valid keys: ${validKeys.join(\", \")}`);\n process.exit(1);\n }\n\n updateConfig({ [args.key]: args.value });\n stderr(`Set ${args.key} = ${args.key === \"api_key\" ? \"***\" : args.value}`);\n },\n});\n\nconst configShow = defineCommand({\n meta: {\n name: \"show\",\n description: \"Show all config values\",\n },\n args: {\n json: {\n type: \"boolean\",\n description: \"Output as JSON\",\n default: false,\n },\n },\n async run({ args }) {\n const config = readConfig();\n\n if (args.json) {\n jsonOut(config);\n } else {\n stderr(`Config: ${getConfigPath()}`);\n for (const [key, value] of Object.entries(config)) {\n const display = key === \"api_key\" && value\n ? `${(value as string).slice(0, 12)}...`\n : value;\n stdout(`${key} = ${display}`);\n }\n }\n },\n});\n\nexport default defineCommand({\n meta: {\n name: \"config\",\n description: \"Manage CLI configuration\",\n },\n subCommands: {\n get: configGet,\n set: configSet,\n show: configShow,\n },\n});\n","import { defineCommand, runMain } from \"citty\";\nimport { CliError } from \"./lib/errors.js\";\nimport { stderr } from \"./lib/output.js\";\n\nconst main = defineCommand({\n meta: {\n name: \"pixelvault\",\n version: \"0.2.0\",\n description: \"CLI for PixelVault — agent-first image hosting\",\n },\n subCommands: {\n register: () => import(\"./commands/register.js\").then((m) => m.default),\n login: () => import(\"./commands/login.js\").then((m) => m.default),\n upload: () => import(\"./commands/upload.js\").then((m) => m.default),\n list: () => import(\"./commands/list.js\").then((m) => m.default),\n get: () => import(\"./commands/get.js\").then((m) => m.default),\n delete: () => import(\"./commands/delete.js\").then((m) => m.default),\n export: () => import(\"./commands/export.js\").then((m) => m.default),\n whoami: () => import(\"./commands/whoami.js\").then((m) => m.default),\n config: () => import(\"./commands/config.js\").then((m) => m.default),\n },\n});\n\nrunMain(main).catch((err: unknown) => {\n if (err instanceof CliError) {\n stderr(`Error: ${err.message}`);\n process.exit(err.exitCode);\n }\n stderr(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n});\n"],"mappings":"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","names":["CliError","init_errors","__esmMin","message","exitCode","stdout","text","stderr","jsonOut","data","init_output","__esmMin","readFileSync","writeFileSync","mkdirSync","join","homedir","getConfigPath","CONFIG_FILE","readConfig","raw","writeConfig","config","CONFIG_DIR","updateConfig","updates","getApiKey","getApiUrl","DEFAULT_API_URL","requireApiKey","key","init_config","__esmMin","apiRequest","options","url","getApiUrl","headers","CLIENT_ID","fetchBody","res","err","CliError","errorBody","message","init_client","__esmMin","init_config","init_errors","createInterface","prompt","question","rl","resolve","answer","promptPassword","password","onData","char","init_prompt","__esmMin","register_exports","__export","register_default","defineCommand","init_register","__esmMin","init_client","init_config","init_prompt","init_output","args","interactive","email","prompt","stderr","password","promptPassword","res","apiRequest","updateConfig","login_exports","__export","login_default","defineCommand","init_login","__esmMin","init_client","init_config","init_prompt","init_output","args","email","prompt","password","promptPassword","stderr","loginRes","apiRequest","token","projectId","rotateRes","updateConfig","parseExpires","input","match","CliError","unit","multiplier","seconds","MIN_EXPIRES_SECONDS","MAX_EXPIRES_SECONDS","init_duration","__esmMin","init_errors","upload_exports","__export","upload_default","defineCommand","readFileSync","basename","init_upload","__esmMin","init_client","init_config","init_duration","init_output","args","apiKey","requireApiKey","signExpires","stderr","parseExpires","files","hadError","results","filePath","buffer","fileName","formData","res","apiRequest","stdout","err","jsonOut","list_exports","__export","list_default","defineCommand","init_list","__esmMin","init_client","init_config","init_output","args","apiKey","requireApiKey","params","res","apiRequest","jsonOut","img","stdout","get_exports","__export","applyTransform","get_default","defineCommand","writeFileSync","url","transform","raw","params","init_get","__esmMin","init_client","init_config","init_output","init_errors","args","apiKey","requireApiKey","res","apiRequest","output","bytes","dl","CliError","err","stderr","jsonOut","stdout","delete_exports","__export","delete_default","defineCommand","init_delete","__esmMin","init_client","init_config","args","apiKey","requireApiKey","apiRequest","export_exports","__export","export_default","defaultOutputPath","defineCommand","writeFileSync","mkdirSync","execFileSync","jobId","out","sleep","init_export","__esmMin","init_client","init_config","init_output","init_errors","ms","resolve","args","apiKey","requireApiKey","timeoutMs","start","apiRequest","err","CliError","stderr","deadline","status","delay","downloadUrl","getApiUrl","bytes","dl","dir","jsonOut","stdout","whoami_exports","__export","whoami_default","defineCommand","init_whoami","__esmMin","init_config","init_output","args","config","readConfig","apiKey","getApiKey","stderr","info","jsonOut","stdout","config_exports","__export","config_default","defineCommand","configGet","configSet","configShow","init_config","__esmMin","init_output","args","value","readConfig","stderr","stdout","validKeys","updateConfig","config","jsonOut","getConfigPath","key","display","init_errors","init_output","defineCommand","runMain","main","m","err","CliError","stderr"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/errors.ts","../src/lib/output.ts","../src/lib/config.ts","../src/lib/client.ts","../src/lib/prompt.ts","../src/commands/register.ts","../src/commands/login.ts","../src/lib/duration.ts","../src/commands/upload.ts","../src/commands/list.ts","../src/commands/get.ts","../src/commands/delete.ts","../src/commands/export.ts","../src/commands/whoami.ts","../src/commands/config.ts","../src/index.ts"],"sourcesContent":["export class CliError extends Error {\n exitCode: number;\n\n constructor(message: string, exitCode = 1) {\n super(message);\n this.name = \"CliError\";\n this.exitCode = exitCode;\n }\n}\n","/**\n * Write to stdout (for machine-parseable output — URLs, JSON).\n */\nexport function stdout(text: string): void {\n process.stdout.write(text + \"\\n\");\n}\n\n/**\n * Write to stderr (for human messages — prompts, progress, errors).\n */\nexport function stderr(text: string): void {\n process.stderr.write(text + \"\\n\");\n}\n\n/**\n * Output data as JSON to stdout.\n */\nexport function jsonOut(data: unknown): void {\n stdout(JSON.stringify(data, null, 2));\n}\n\n/**\n * Print an error message to stderr and exit.\n */\nexport function fatal(message: string, exitCode = 1): never {\n stderr(`Error: ${message}`);\n process.exit(exitCode);\n}\n","import { readFileSync, writeFileSync, mkdirSync, chmodSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nexport interface Config {\n api_key?: string;\n default_project?: string;\n email?: string;\n api_url?: string;\n}\n\nconst CONFIG_DIR = join(homedir(), \".pixelvault\");\nconst CONFIG_FILE = join(CONFIG_DIR, \"config.json\");\nconst DEFAULT_API_URL = \"https://api.pixelvault.dev\";\n\nexport function getConfigPath(): string {\n return CONFIG_FILE;\n}\n\nexport function readConfig(): Config {\n try {\n const raw = readFileSync(CONFIG_FILE, \"utf-8\");\n return JSON.parse(raw) as Config;\n } catch {\n return {};\n }\n}\n\nexport function writeConfig(config: Config): void {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });\n writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + \"\\n\", {\n mode: 0o600,\n });\n}\n\nexport function updateConfig(updates: Partial<Config>): void {\n const config = readConfig();\n writeConfig({ ...config, ...updates });\n}\n\nexport function getApiKey(): string | undefined {\n return process.env[\"PIXELVAULT_API_KEY\"] || readConfig().api_key;\n}\n\nexport function getApiUrl(): string {\n return (\n process.env[\"PIXELVAULT_API_URL\"] ||\n readConfig().api_url ||\n DEFAULT_API_URL\n );\n}\n\nexport function requireApiKey(): string {\n const key = getApiKey();\n if (!key) {\n throw new Error(\n \"Not authenticated. Run `pixelvault register` or `pixelvault login`, or set PIXELVAULT_API_KEY.\"\n );\n }\n return key;\n}\n","import { getApiUrl } from \"./config.js\";\nimport { CliError } from \"./errors.js\";\n\ninterface RequestOptions {\n method?: string;\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n formData?: FormData;\n}\n\ninterface ApiError {\n error: { code: string; message: string };\n}\n\n// Identifies the CLI to the API so signups made through it can be attributed to\n// this channel (server reads X-PixelVault-Client at register/device-login — see\n// pixelvault docs/specs/lead-attribution.md). Keep the version in sync with\n// package.json on release.\nconst CLIENT_ID = \"pixelvault-cli/0.5.2\";\n\nexport async function apiRequest<T>(\n options: RequestOptions & { auth?: string }\n): Promise<T> {\n const baseUrl = getApiUrl();\n const url = `${baseUrl}${options.path}`;\n\n const headers: Record<string, string> = { ...options.headers };\n\n if (!headers[\"X-PixelVault-Client\"]) {\n headers[\"X-PixelVault-Client\"] = CLIENT_ID;\n }\n\n if (options.auth) {\n headers[\"Authorization\"] = `Bearer ${options.auth}`;\n }\n\n let fetchBody: BodyInit | undefined;\n\n if (options.formData) {\n fetchBody = options.formData;\n } else if (options.body) {\n headers[\"Content-Type\"] = \"application/json\";\n fetchBody = JSON.stringify(options.body);\n }\n\n let res: Response;\n try {\n res = await fetch(url, {\n method: options.method || \"GET\",\n headers,\n body: fetchBody,\n });\n } catch (err) {\n throw new CliError(\n `Network error: ${err instanceof Error ? err.message : \"Failed to connect\"}`,\n 1\n );\n }\n\n if (!res.ok) {\n let errorBody: ApiError | undefined;\n try {\n errorBody = (await res.json()) as ApiError;\n } catch {\n // ignore parse failures\n }\n\n const message =\n errorBody?.error?.message || `HTTP ${res.status}: ${res.statusText}`;\n throw new CliError(message, 1);\n }\n\n return (await res.json()) as T;\n}\n","import { createInterface } from \"node:readline\";\n\n/**\n * Prompt the user for input via stderr (keeps stdout clean for agents).\n */\nexport function prompt(question: string): Promise<string> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\n/**\n * Prompt for a password (input is not echoed).\n * Uses raw mode to suppress echo when available, falls back to regular prompt.\n */\nexport async function promptPassword(question: string): Promise<string> {\n if (!process.stdin.isTTY) {\n return prompt(question);\n }\n\n return new Promise((resolve) => {\n process.stderr.write(question);\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.setEncoding(\"utf-8\");\n\n let password = \"\";\n\n const onData = (char: string) => {\n if (char === \"\\n\" || char === \"\\r\" || char === \"\\u0004\") {\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.stdin.removeListener(\"data\", onData);\n process.stderr.write(\"\\n\");\n resolve(password);\n } else if (char === \"\\u0003\") {\n // Ctrl+C\n process.stdin.setRawMode(false);\n process.exit(130);\n } else if (\n char === \"\\u007F\" ||\n char === \"\\b\"\n ) {\n // Backspace\n password = password.slice(0, -1);\n } else {\n password += char;\n }\n };\n\n process.stdin.on(\"data\", onData);\n });\n}\n","import { defineCommand } from \"citty\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { updateConfig } from \"../lib/config.js\";\nimport { prompt, promptPassword } from \"../lib/prompt.js\";\nimport { stderr } from \"../lib/output.js\";\n\ninterface RegisterResponse {\n data: {\n account_id: string;\n email: string;\n email_verified: boolean;\n // Optional: older API versions omit it. Absent → treat as \"unknown\".\n password_set?: boolean;\n plan: string;\n default_project: {\n id: string;\n name: string;\n api_keys: { live: string };\n };\n };\n}\n\nexport default defineCommand({\n meta: {\n name: \"register\",\n description: \"Create a new PixelVault account\",\n },\n args: {\n email: {\n type: \"string\",\n description: \"Email address\",\n },\n password: {\n type: \"string\",\n description: \"Password (min 8 characters). Omit for a passwordless account.\",\n },\n passwordless: {\n type: \"boolean\",\n description:\n \"Create the account without a password (for agents/automation). Set a password later via the web 'Forgot password' flow.\",\n },\n },\n async run({ args }) {\n const interactive = Boolean(process.stdin.isTTY);\n\n // Email is always required. Only prompt when we have a TTY — in a headless\n // (agent) run, missing --email is a hard error rather than a hung prompt.\n const email = args.email || (interactive ? await prompt(\"Email: \") : \"\");\n if (!email) {\n stderr(\"Email is required. Pass --email <email>.\");\n process.exit(1);\n }\n\n // Resolve the password. Precedence: explicit --password > --passwordless >\n // interactive prompt (blank = passwordless) > headless default (passwordless,\n // so a non-TTY run never blocks on a hidden prompt).\n let password: string | undefined;\n if (args.password) {\n password = args.password;\n } else if (args.passwordless) {\n password = undefined;\n } else if (interactive) {\n const entered = await promptPassword(\n \"Password (leave blank for a passwordless account): \"\n );\n password = entered || undefined;\n } else {\n password = undefined;\n }\n\n if (password !== undefined && password.length < 8) {\n stderr(\"Password must be at least 8 characters.\");\n process.exit(1);\n }\n\n stderr(\"Creating account...\");\n\n const res = await apiRequest<RegisterResponse>({\n method: \"POST\",\n path: \"/v1/auth/register\",\n // Only send the password field when one was chosen — omitting it creates\n // a passwordless account server-side. `attribution.source: \"cli\"` buckets\n // the signup to this channel (server treats it as an untrusted hint that\n // wins over the derived source — see lead-attribution spec).\n body: {\n email,\n ...(password ? { password } : {}),\n attribution: { source: \"cli\" },\n },\n });\n\n updateConfig({\n api_key: res.data.default_project.api_keys.live,\n default_project: res.data.default_project.id,\n email: res.data.email,\n });\n\n stderr(`Account created. API key saved to ~/.pixelvault/config.json`);\n stderr(`Email: ${res.data.email}`);\n stderr(`Project: ${res.data.default_project.id}`);\n\n // password_set === false (or a passwordless request on an older API) means\n // there's no dashboard login yet — tell the user how to claim one.\n const passwordless = res.data.password_set === false || !password;\n if (passwordless) {\n stderr(\n \"No password set. To enable dashboard login, use 'Forgot password' at \" +\n \"https://pixelvault.dev/forgot-password to set one.\"\n );\n }\n\n if (!res.data.email_verified) {\n stderr(\"Verify your email to lift the upload limit for the free tier.\");\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { readConfig, updateConfig, getApiUrl } from \"../lib/config.js\";\nimport { prompt, promptPassword } from \"../lib/prompt.js\";\nimport { stderr } from \"../lib/output.js\";\n\ninterface LoginResponse {\n data: {\n token: string;\n account_id: string;\n email: string;\n email_verified: boolean;\n };\n}\n\ninterface RotateKeyResponse {\n data: {\n key_id: string;\n api_key: string;\n project_id: string;\n environment: string;\n };\n}\n\ninterface ProjectsResponse {\n data: Array<{ id: string; name: string }>;\n}\n\nexport default defineCommand({\n meta: {\n name: \"login\",\n description: \"Log in to your PixelVault account\",\n },\n args: {\n email: {\n type: \"string\",\n description: \"Email address\",\n },\n password: {\n type: \"string\",\n description: \"Password\",\n },\n },\n async run({ args }) {\n const email = args.email || (await prompt(\"Email: \"));\n const password = args.password || (await promptPassword(\"Password: \"));\n\n if (!email || !password) {\n stderr(\"Email and password are required.\");\n process.exit(1);\n }\n\n stderr(\"Logging in...\");\n\n // Step 1: Login to get JWT\n const loginRes = await apiRequest<LoginResponse>({\n method: \"POST\",\n path: \"/v1/auth/login\",\n body: { email, password },\n });\n\n const token = loginRes.data.token;\n\n // Step 2: Get projects to find default project ID\n let projectId: string | undefined;\n try {\n const projectsRes = await apiRequest<ProjectsResponse>({\n method: \"GET\",\n path: \"/v1/projects\",\n auth: token,\n });\n projectId = projectsRes.data[0]?.id;\n } catch {\n // Projects endpoint may not exist yet — continue without project ID\n }\n\n // Step 3: Rotate key to get a fresh API key\n if (projectId) {\n const rotateRes = await apiRequest<RotateKeyResponse>({\n method: \"POST\",\n path: \"/v1/auth/rotate-key\",\n auth: token,\n body: { project_id: projectId },\n });\n\n updateConfig({\n api_key: rotateRes.data.api_key,\n default_project: projectId,\n email: loginRes.data.email,\n });\n\n stderr(`Logged in. API key saved to ~/.pixelvault/config.json`);\n stderr(`Email: ${loginRes.data.email}`);\n stderr(`Project: ${projectId}`);\n } else {\n // Fallback: save JWT for manual key setup\n stderr(`Logged in as ${loginRes.data.email}.`);\n stderr(\n `Could not auto-configure API key. Set PIXELVAULT_API_KEY manually.`\n );\n // Any saved key/project may be from a previous account; drop the project\n // so whoami doesn't pair it with this email, and flag the key.\n updateConfig({ email: loginRes.data.email, default_project: undefined });\n if (readConfig().api_key) {\n stderr(\"Warning: the saved api_key may belong to a previous login. Replace it with `pixelvault config set api_key <key>`.\");\n }\n }\n },\n});\n","import { CliError } from \"./errors.js\";\n\n/** Signed-URL lifetime bounds, matching the API's `sign_expires_in` (60s..30d). */\nexport const MIN_EXPIRES_SECONDS = 60;\nexport const MAX_EXPIRES_SECONDS = 30 * 24 * 60 * 60;\n\n/**\n * Parse a signed-link lifetime like `30m`, `12h`, `7d`, `90s`, or a bare number\n * of seconds, into seconds. Rejects anything outside the API's accepted range so\n * a bad value fails locally with a clear message instead of a 400 from the server.\n */\nexport function parseExpires(input: string): number {\n const match = /^(\\d+)\\s*([smhd]?)$/i.exec(input.trim());\n if (!match) {\n throw new CliError(\n `Invalid --expires \"${input}\". Use e.g. 30m, 12h, 7d, or a number of seconds.`\n );\n }\n\n const unit = (match[2] ?? \"\").toLowerCase();\n const multiplier = unit === \"d\" ? 86400 : unit === \"h\" ? 3600 : unit === \"m\" ? 60 : 1;\n const seconds = Number(match[1] ?? \"\") * multiplier;\n\n if (seconds < MIN_EXPIRES_SECONDS || seconds > MAX_EXPIRES_SECONDS) {\n throw new CliError(\n `--expires must be between 60s and 30d (got ${seconds}s).`\n );\n }\n\n return seconds;\n}\n","import { defineCommand } from \"citty\";\nimport { readFileSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { requireApiKey } from \"../lib/config.js\";\nimport { parseExpires } from \"../lib/duration.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\n\ninterface UploadResponse {\n data: {\n id: string;\n url: string;\n visibility?: \"public\" | \"private\";\n mime_type: string;\n size: number;\n filename: string;\n folder: string | null;\n created_at: string;\n signed_expires?: number;\n };\n}\n\nexport default defineCommand({\n meta: {\n name: \"upload\",\n description: \"Upload one or more images\",\n },\n args: {\n files: {\n type: \"positional\",\n description: \"File path(s) to upload\",\n required: true,\n },\n folder: {\n type: \"string\",\n description: \"Folder to organize images in\",\n },\n private: {\n type: \"boolean\",\n description:\n \"Upload privately — returns a signed URL only holders of the link can open (needs a secret key)\",\n default: false,\n },\n expires: {\n type: \"string\",\n description:\n \"Lifetime of a --private signed link: e.g. 30m, 12h, 7d (default 7d; min 60s, max 30d)\",\n },\n json: {\n type: \"boolean\",\n description: \"Output full JSON response\",\n default: false,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n\n // Resolve the signed-link lifetime up front so a bad value fails before any\n // upload happens. `--expires` only makes sense for a private (signed) URL.\n let signExpires: number | null = null;\n if (args.expires !== undefined) {\n if (!args.private) {\n stderr(\"--expires only applies to --private uploads (it sets the signed link's lifetime).\");\n process.exit(1);\n }\n signExpires = parseExpires(String(args.expires));\n }\n\n if (args.private && args.folder) {\n stderr(\"Note: --folder is ignored for --private uploads.\");\n }\n\n // A citty positional binds only the first value; every positional (including\n // the first, and anything a shell glob expanded to) lands in `args._`.\n const files = args._.length ? args._.map(String) : [String(args.files)];\n let hadError = false;\n\n const results: UploadResponse[\"data\"][] = [];\n\n for (const filePath of files) {\n try {\n const buffer = readFileSync(filePath);\n const fileName = basename(filePath);\n\n const formData = new FormData();\n formData.append(\n \"file\",\n new File([buffer], fileName)\n );\n\n if (args.folder) {\n formData.append(\"folder\", args.folder);\n }\n\n if (args.private) {\n // The server routes private images to a signed-URL-only path and\n // returns the ready-to-share signed URL in `data.url`. A user-supplied\n // folder is ignored for private uploads (server-side).\n formData.append(\"visibility\", \"private\");\n if (signExpires !== null) {\n formData.append(\"sign_expires_in\", String(signExpires));\n }\n }\n\n const res = await apiRequest<UploadResponse>({\n method: \"POST\",\n path: \"/v1/images\",\n auth: apiKey,\n formData,\n });\n\n // Fail closed: if we asked for private but the server didn't confirm it,\n // don't hand back a URL the user would wrongly trust as private.\n if (args.private && res.data.visibility !== \"private\") {\n hadError = true;\n stderr(`Refusing to report ${filePath}: server did not confirm a private upload.`);\n continue;\n }\n\n if (args.json) {\n results.push(res.data);\n } else {\n stdout(res.data.url);\n }\n } catch (err) {\n hadError = true;\n stderr(\n `Failed to upload ${filePath}: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n }\n\n if (args.json && results.length > 0) {\n jsonOut(results.length === 1 ? results[0] : results);\n }\n\n if (hadError) {\n process.exit(1);\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { requireApiKey } from \"../lib/config.js\";\nimport { stdout, jsonOut } from \"../lib/output.js\";\n\ninterface ListResponse {\n data: Array<{\n id: string;\n url: string;\n mime_type: string;\n size: number;\n filename: string;\n folder: string | null;\n created_at: string;\n }>;\n meta: {\n total: number;\n page: number;\n per_page: number;\n };\n}\n\nexport default defineCommand({\n meta: {\n name: \"list\",\n description: \"List uploaded images\",\n },\n args: {\n page: {\n type: \"string\",\n description: \"Page number\",\n default: \"1\",\n },\n \"per-page\": {\n type: \"string\",\n description: \"Items per page (max 100)\",\n default: \"20\",\n },\n json: {\n type: \"boolean\",\n description: \"Output full JSON response\",\n default: false,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n\n const params = new URLSearchParams({\n page: args.page,\n per_page: args[\"per-page\"],\n });\n\n const res = await apiRequest<ListResponse>({\n path: `/v1/images?${params}`,\n auth: apiKey,\n });\n\n if (args.json) {\n jsonOut(res);\n } else {\n for (const img of res.data) {\n stdout(img.url);\n }\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { writeFileSync } from \"node:fs\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { requireApiKey } from \"../lib/config.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\nimport { CliError } from \"../lib/errors.js\";\n\ninterface GetResponse {\n data: {\n id: string;\n url: string;\n mime_type: string;\n size: number;\n filename: string;\n folder: string | null;\n created_at: string;\n };\n}\n\n/**\n * Append a transform query string to a CDN URL. Accepts params with or without a\n * leading `?`/`&` (e.g. `w=400&fmt=webp`, `?segment=foreground`). See the transform\n * docs: https://pixelvault.dev/docs#transforms\n *\n * The params are reserialized through URLSearchParams so reserved characters in\n * values are percent-encoded — without this a hex color like `background=#ffaa00`\n * would be parsed as a URL fragment and lost. Idempotent for already-encoded input.\n */\nexport function applyTransform(url: string, transform?: string): string {\n if (!transform) return url;\n const raw = transform.trim().replace(/^[?&]+/, \"\");\n if (!raw) return url;\n const params = new URLSearchParams(raw).toString();\n if (!params) return url;\n return url.includes(\"?\") ? `${url}&${params}` : `${url}?${params}`;\n}\n\nexport default defineCommand({\n meta: {\n name: \"get\",\n description:\n \"Get an image's CDN URL or metadata, or download it — optionally transformed\",\n },\n args: {\n id: {\n type: \"positional\",\n description: \"Image ID (e.g. img_abc123)\",\n required: true,\n },\n output: {\n type: \"string\",\n description: \"Download the image to this file path\",\n alias: \"o\",\n },\n transform: {\n type: \"string\",\n description:\n 'Transform params to apply, e.g. \"w=400&fmt=webp\", \"segment=foreground\", \"tile=img_logo.png\"',\n alias: \"t\",\n },\n json: {\n type: \"boolean\",\n description: \"Output full JSON metadata\",\n default: false,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n\n const res = await apiRequest<GetResponse>({\n path: `/v1/images/${encodeURIComponent(args.id)}`,\n auth: apiKey,\n });\n\n const url = applyTransform(res.data.url, args.transform as string | undefined);\n\n // Download mode: fetch the (possibly transformed) bytes to disk.\n if (args.output) {\n const output = args.output as string;\n let bytes: ArrayBuffer;\n try {\n const dl = await fetch(url);\n if (!dl.ok) {\n throw new CliError(`Failed to download image: HTTP ${dl.status}`, 1);\n }\n bytes = await dl.arrayBuffer();\n } catch (err) {\n if (err instanceof CliError) throw err;\n throw new CliError(\n `Failed to download image: ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n // Refuse to write an empty file — a 200 with an empty/truncated body would\n // otherwise report success and leave a broken image that agents chain on.\n if (bytes.byteLength === 0) {\n throw new CliError(\"Downloaded 0 bytes — refusing to write an empty file\", 1);\n }\n try {\n writeFileSync(output, Buffer.from(bytes));\n } catch (err) {\n throw new CliError(\n `Failed to save ${output}: ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n stderr(`Saved ${output}`);\n // Honor --json even in download mode so a caller that always requests JSON\n // gets a stable stdout contract regardless of -o.\n if (args.json) {\n jsonOut(\n args.transform ? { ...res, transformed_url: url, output } : { ...res, output },\n );\n } else {\n stdout(url); // URL to stdout (machine-parseable), confirmation to stderr\n }\n return;\n }\n\n if (args.json) {\n // When a transform is applied there's no separate record for it, so surface\n // the resolved URL alongside the raw metadata.\n jsonOut(args.transform ? { ...res, transformed_url: url } : res);\n } else {\n stdout(url);\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { requireApiKey } from \"../lib/config.js\";\nimport { stderr } from \"../lib/output.js\";\n\nexport default defineCommand({\n meta: {\n name: \"delete\",\n description: \"Delete an image by ID\",\n },\n args: {\n id: {\n type: \"positional\",\n description: \"Image ID (e.g. img_abc123)\",\n required: true,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n\n await apiRequest<{ success: boolean }>({\n method: \"DELETE\",\n path: `/v1/images/${args.id}`,\n auth: apiKey,\n });\n\n // Silent on success (agent-friendly)\n },\n});\n","import { defineCommand } from \"citty\";\nimport { writeFileSync, mkdirSync } from \"node:fs\";\nimport { execFileSync } from \"node:child_process\";\nimport { apiRequest } from \"../lib/client.js\";\nimport { getApiUrl, requireApiKey } from \"../lib/config.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\nimport { CliError } from \"../lib/errors.js\";\n\ninterface StartResponse {\n job_id: string;\n status: string;\n image_count: number;\n status_url: string;\n}\n\ninterface StatusResponse {\n id: string;\n status: \"pending\" | \"processing\" | \"complete\" | \"failed\" | \"expired\";\n image_count: number;\n processed_count: number;\n bytes: number;\n created_at: string;\n expires_at: string;\n download_url?: string;\n error?: string;\n}\n\n/** Default archive filename when `--output` isn't given. Pure, for tests. */\nexport function defaultOutputPath(jobId: string, out?: string): string {\n return out && out.length > 0 ? out : `pixelvault-export-${jobId}.tar`;\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\nexport default defineCommand({\n meta: {\n name: \"export\",\n description:\n \"Export every image in your project as a tar archive (manifest.json + all images). Your data is always portable — no lock-in.\",\n },\n args: {\n output: {\n type: \"string\",\n description: \"Write the archive to this path (default: pixelvault-export-<job>.tar)\",\n alias: \"o\",\n },\n extract: {\n type: \"boolean\",\n description: \"Extract the archive into a directory after download (requires `tar`)\",\n default: false,\n },\n timeout: {\n type: \"string\",\n description: \"Max seconds to wait for the export to finish (default: 600)\",\n default: \"600\",\n },\n json: {\n type: \"boolean\",\n description: \"Output the final job JSON to stdout\",\n default: false,\n },\n },\n async run({ args }) {\n const apiKey = requireApiKey();\n const timeoutMs = (Number(args.timeout) || 600) * 1000;\n\n // 1. Start the async export job (project-scoped by the secret key).\n let start: StartResponse;\n try {\n start = await apiRequest<StartResponse>({ method: \"POST\", path: \"/v1/export\", auth: apiKey });\n } catch (err) {\n // Surface the \"already running\" case helpfully.\n if (err instanceof CliError && /in progress/i.test(err.message)) {\n throw new CliError(\n \"An export for this project is already in progress. Wait for it to finish, then try again.\",\n 1,\n );\n }\n throw err;\n }\n stderr(`Export started — ${start.image_count} image(s), job ${start.job_id}`);\n\n // 2. Poll until the archive is ready (backoff 1s → 5s).\n const deadline = Date.now() + timeoutMs;\n let status: StatusResponse;\n let delay = 1000;\n for (;;) {\n status = await apiRequest<StatusResponse>({\n path: `/v1/export-jobs/${encodeURIComponent(start.job_id)}`,\n auth: apiKey,\n });\n if (status.status === \"complete\") break;\n if (status.status === \"failed\") {\n throw new CliError(`Export failed: ${status.error ?? \"unknown error\"}`, 1);\n }\n if (status.status === \"expired\") {\n throw new CliError(\"Export expired before it could be downloaded. Start a new one.\", 1);\n }\n if (Date.now() > deadline) {\n throw new CliError(\n `Timed out after ${args.timeout}s (job still ${status.status}). It may still finish — re-run to poll, or raise --timeout.`,\n 1,\n );\n }\n stderr(` ${status.status}… ${status.processed_count}/${status.image_count}`);\n await sleep(delay);\n delay = Math.min(Math.round(delay * 1.5), 5000);\n }\n\n // 3. Download the tar. apiRequest parses JSON, so fetch the raw bytes directly\n // (the endpoint requires the same Bearer auth).\n const out = defaultOutputPath(start.job_id, args.output as string | undefined);\n const downloadUrl = `${getApiUrl()}/v1/export-jobs/${encodeURIComponent(start.job_id)}/download`;\n let bytes: ArrayBuffer;\n try {\n const dl = await fetch(downloadUrl, { headers: { Authorization: `Bearer ${apiKey}` } });\n if (!dl.ok) throw new CliError(`Failed to download export: HTTP ${dl.status}`, 1);\n bytes = await dl.arrayBuffer();\n } catch (err) {\n if (err instanceof CliError) throw err;\n throw new CliError(\n `Failed to download export: ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n // A 200 with an empty/truncated body must not report success for a backup.\n if (bytes.byteLength === 0) {\n throw new CliError(\"Downloaded 0 bytes — refusing to write an empty archive.\", 1);\n }\n try {\n writeFileSync(out, Buffer.from(bytes));\n } catch (err) {\n throw new CliError(\n `Failed to save ${out}: ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n stderr(`Saved ${out} — ${status.image_count} image(s), ${bytes.byteLength} bytes`);\n\n // 4. Optional extraction via the system `tar`.\n if (args.extract) {\n const dir = out.replace(/\\.tar$/, \"\") || `${out}-extracted`;\n try {\n mkdirSync(dir, { recursive: true });\n execFileSync(\"tar\", [\"-xf\", out, \"-C\", dir], { stdio: \"ignore\" });\n stderr(`Extracted into ${dir}/`);\n } catch (err) {\n throw new CliError(\n `Saved ${out}, but extraction failed (is \\`tar\\` installed?): ${err instanceof Error ? err.message : String(err)}`,\n 1,\n );\n }\n }\n\n if (args.json) {\n jsonOut({ ...status, output: out });\n } else {\n stdout(out); // machine-parseable path on stdout; progress went to stderr\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { readConfig, getApiKey } from \"../lib/config.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\n\nexport default defineCommand({\n meta: {\n name: \"whoami\",\n description: \"Show current authentication state\",\n },\n args: {\n json: {\n type: \"boolean\",\n description: \"Output as JSON\",\n default: false,\n },\n },\n async run({ args }) {\n const config = readConfig();\n const apiKey = getApiKey();\n\n if (!apiKey && !config.email) {\n stderr(\"Not authenticated. Run `pixelvault register` or `pixelvault login`.\");\n process.exit(1);\n }\n\n const info = {\n email: config.email || \"(unknown)\",\n project: config.default_project || \"(unknown)\",\n api_key: apiKey\n ? `${apiKey.slice(0, 12)}...${apiKey.slice(-4)}`\n : \"(not set)\",\n source: process.env[\"PIXELVAULT_API_KEY\"] ? \"env\" : \"config\",\n // email/project come from config written at login; nothing checks them\n // against the current key.\n identity_source: \"cached\",\n };\n\n if (args.json) {\n jsonOut(info);\n } else {\n // email/project are read from config, not looked up for the current key.\n const tag = (v?: string) => (v ? \" (cached, not verified for this key)\" : \"\");\n stdout(`Email: ${info.email}${tag(config.email)}`);\n stdout(`Project: ${info.project}${tag(config.default_project)}`);\n stdout(`API Key: ${info.api_key} (${info.source})`);\n }\n },\n});\n","import { defineCommand } from \"citty\";\nimport { readConfig, updateConfig, getConfigPath } from \"../lib/config.js\";\nimport { stdout, stderr, jsonOut } from \"../lib/output.js\";\n\nconst configGet = defineCommand({\n meta: {\n name: \"get\",\n description: \"Get a config value\",\n },\n args: {\n key: {\n type: \"positional\",\n description: \"Config key (api_key, default_project, email, api_url)\",\n required: true,\n },\n },\n async run({ args }) {\n const config = readConfig();\n const value = config[args.key as keyof typeof config];\n\n if (value === undefined) {\n stderr(`Key \"${args.key}\" is not set.`);\n process.exit(1);\n }\n\n stdout(String(value));\n },\n});\n\nconst configSet = defineCommand({\n meta: {\n name: \"set\",\n description: \"Set a config value\",\n },\n args: {\n key: {\n type: \"positional\",\n description: \"Config key\",\n required: true,\n },\n value: {\n type: \"positional\",\n description: \"Config value\",\n required: true,\n },\n },\n async run({ args }) {\n const validKeys = [\"api_key\", \"default_project\", \"email\", \"api_url\"];\n if (!validKeys.includes(args.key)) {\n stderr(`Invalid key. Valid keys: ${validKeys.join(\", \")}`);\n process.exit(1);\n }\n\n if (args.key === \"api_key\" && args.value !== readConfig().api_key) {\n // email and default_project were cached at login for the previous key and\n // may belong to a different account, so drop them rather than mislead.\n updateConfig({ api_key: args.value, email: undefined, default_project: undefined });\n } else {\n updateConfig({ [args.key]: args.value });\n }\n stderr(`Set ${args.key} = ${args.key === \"api_key\" ? \"***\" : args.value}`);\n },\n});\n\nconst configShow = defineCommand({\n meta: {\n name: \"show\",\n description: \"Show all config values\",\n },\n args: {\n json: {\n type: \"boolean\",\n description: \"Output as JSON\",\n default: false,\n },\n },\n async run({ args }) {\n const config = readConfig();\n\n if (args.json) {\n jsonOut(config);\n } else {\n stderr(`Config: ${getConfigPath()}`);\n for (const [key, value] of Object.entries(config)) {\n const display = key === \"api_key\" && value\n ? `${(value as string).slice(0, 12)}...`\n : value;\n stdout(`${key} = ${display}`);\n }\n }\n },\n});\n\nexport default defineCommand({\n meta: {\n name: \"config\",\n description: \"Manage CLI configuration\",\n },\n subCommands: {\n get: configGet,\n set: configSet,\n show: configShow,\n },\n});\n","import { defineCommand, runMain } from \"citty\";\nimport { CliError } from \"./lib/errors.js\";\nimport { stderr } from \"./lib/output.js\";\n\nconst main = defineCommand({\n meta: {\n name: \"pixelvault\",\n version: \"0.2.0\",\n description: \"CLI for PixelVault — agent-first image hosting\",\n },\n subCommands: {\n register: () => import(\"./commands/register.js\").then((m) => m.default),\n login: () => import(\"./commands/login.js\").then((m) => m.default),\n upload: () => import(\"./commands/upload.js\").then((m) => m.default),\n list: () => import(\"./commands/list.js\").then((m) => m.default),\n get: () => import(\"./commands/get.js\").then((m) => m.default),\n delete: () => import(\"./commands/delete.js\").then((m) => m.default),\n export: () => import(\"./commands/export.js\").then((m) => m.default),\n whoami: () => import(\"./commands/whoami.js\").then((m) => m.default),\n config: () => import(\"./commands/config.js\").then((m) => m.default),\n },\n});\n\nrunMain(main).catch((err: unknown) => {\n if (err instanceof CliError) {\n stderr(`Error: ${err.message}`);\n process.exit(err.exitCode);\n }\n stderr(`Error: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n});\n"],"mappings":"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","names":["CliError","init_errors","__esmMin","message","exitCode","stdout","text","stderr","jsonOut","data","init_output","__esmMin","readFileSync","writeFileSync","mkdirSync","join","homedir","getConfigPath","CONFIG_FILE","readConfig","raw","writeConfig","config","CONFIG_DIR","updateConfig","updates","getApiKey","getApiUrl","DEFAULT_API_URL","requireApiKey","key","init_config","__esmMin","apiRequest","options","url","getApiUrl","headers","CLIENT_ID","fetchBody","res","err","CliError","errorBody","message","init_client","__esmMin","init_config","init_errors","createInterface","prompt","question","rl","resolve","answer","promptPassword","password","onData","char","init_prompt","__esmMin","register_exports","__export","register_default","defineCommand","init_register","__esmMin","init_client","init_config","init_prompt","init_output","args","interactive","email","prompt","stderr","password","promptPassword","res","apiRequest","updateConfig","login_exports","__export","login_default","defineCommand","init_login","__esmMin","init_client","init_config","init_prompt","init_output","args","email","prompt","password","promptPassword","stderr","loginRes","apiRequest","token","projectId","rotateRes","updateConfig","readConfig","parseExpires","input","match","CliError","unit","multiplier","seconds","MIN_EXPIRES_SECONDS","MAX_EXPIRES_SECONDS","init_duration","__esmMin","init_errors","upload_exports","__export","upload_default","defineCommand","readFileSync","basename","init_upload","__esmMin","init_client","init_config","init_duration","init_output","args","apiKey","requireApiKey","signExpires","stderr","parseExpires","files","hadError","results","filePath","buffer","fileName","formData","res","apiRequest","stdout","err","jsonOut","list_exports","__export","list_default","defineCommand","init_list","__esmMin","init_client","init_config","init_output","args","apiKey","requireApiKey","params","res","apiRequest","jsonOut","img","stdout","get_exports","__export","applyTransform","get_default","defineCommand","writeFileSync","url","transform","raw","params","init_get","__esmMin","init_client","init_config","init_output","init_errors","args","apiKey","requireApiKey","res","apiRequest","output","bytes","dl","CliError","err","stderr","jsonOut","stdout","delete_exports","__export","delete_default","defineCommand","init_delete","__esmMin","init_client","init_config","args","apiKey","requireApiKey","apiRequest","export_exports","__export","export_default","defaultOutputPath","defineCommand","writeFileSync","mkdirSync","execFileSync","jobId","out","sleep","init_export","__esmMin","init_client","init_config","init_output","init_errors","ms","resolve","args","apiKey","requireApiKey","timeoutMs","start","apiRequest","err","CliError","stderr","deadline","status","delay","downloadUrl","getApiUrl","bytes","dl","dir","jsonOut","stdout","whoami_exports","__export","whoami_default","defineCommand","init_whoami","__esmMin","init_config","init_output","args","config","readConfig","apiKey","getApiKey","stderr","info","jsonOut","tag","v","stdout","config_exports","__export","config_default","defineCommand","configGet","configSet","configShow","init_config","__esmMin","init_output","args","value","readConfig","stderr","stdout","validKeys","updateConfig","config","jsonOut","getConfigPath","key","display","init_errors","init_output","defineCommand","runMain","main","m","err","CliError","stderr"]}
|