bunny-move
Version:
Move files to and from your storage zones with bunny.net in a single cli command 🐰
3 lines (2 loc) • 9.98 kB
JavaScript
import { createRequire } from 'module';const require = createRequire(import.meta.url);
import{argument as it}from"pastel";import st from"react";import{z as he}from"zod";import A from"figures";import{Newline as f,Text as s}from"ink";import xe from"ink-spinner";import{Fragment as Ce,jsx as a,jsxs as p}from"react/jsx-runtime";function B({feedback:e}){let t=p(Ce,{children:[a(f,{}),e.pastStories.map(r=>p(s,{children:[a(s,{color:"green",children:A.tick}),p(s,{color:"white",children:[" ",r]}),a(f,{})]},r))]});return e.error?p(s,{children:[t,p(s,{children:[a(s,{color:"red",children:A.cross}),p(s,{color:"white",children:[" ",e.story]}),a(f,{}),a(f,{}),a(s,{color:"red",children:e.error}),a(f,{})]})]}):e.done?p(s,{children:[t,p(s,{children:[a(s,{color:"magenta",children:A.heart}),a(s,{color:"white",children:" Done"}),a(f,{})]})]}):p(s,{children:[t,p(s,{children:[a(s,{color:"cyan",children:a(xe,{})}),p(s,{color:"white",children:[" ",e.story]}),a(s,{children:e.tasks.map(r=>p(s,{children:[a(f,{}),a(s,{color:"gray",children:r})]},r))}),a(f,{})]})]})}import{createAction as b,createReducer as Se}from"@reduxjs/toolkit";import D from"react";function L(e){return e.at(0).toUpperCase()+e.slice(1)}function ke(e,t){return Object.fromEntries(Object.entries(t).map(([r,o])=>[`dispatch${L(r)}`,(...n)=>{e(o(...n))}]))}function K(e,t,r){let[o,n]=D.useReducer(e,t),i=D.useMemo(()=>ke(n,r),[n,r]);return[o,i]}var N=b("feedback/epic/end"),v=b("feedback/epic/error"),O=b("feedback/story/change"),j=b("feedback/tasks/end"),I=b("feedback/tasks/start"),Ae={epicEnd:N,epicError:v,storyChange:O,taskEnd:j,taskStart:I},z={done:!1,error:null,pastStories:[],story:"",tasks:[]},Te=Se(z,e=>e.addCase(O,(t,r)=>{t.story!==""&&t.pastStories.push(t.story),t.story=r.payload}).addCase(I,(t,r)=>{t.tasks.push(r.payload)}).addCase(j,(t,r)=>{let o=t.tasks.indexOf(r.payload);o!==-1&&t.tasks.splice(o,1)}).addCase(N,t=>{t.story!==""&&t.pastStories.push(t.story),t.story="",t.done=!0}).addCase(v,(t,r)=>{t.error=r.payload}));function $(){return K(Te,z,Ae)}import{useApp as we}from"ink";import Pe from"react";function U(e){let{exit:t}=we();Pe.useEffect(()=>{(e.done||e.error)&&(e.error&&(process.exitCode=1,process.env.CI&&(console.error(e.error),console.error())),t())},[e.done,e.error,t])}function Ee(e){return typeof e=="object"&&e!==null&&"message"in e&&typeof e.message=="string"}function Fe(e){if(Ee(e))return e;try{return new Error(JSON.stringify(e))}catch{return new Error(String(e))}}function M(e){return Fe(e).message}import{option as Ze}from"pastel";import{z as W}from"zod";var G=W.string().trim().uuid(),Re=W.preprocess(e=>process.env.BUNNY_ACCESS_KEY&&!e?process.env.BUNNY_ACCESS_KEY.split(","):e,G.or(G.array()).optional().transform(e=>typeof e=="string"?[e]:e)),_=Re.describe(Ze({alias:"k",description:"Bunny API Access Key",valueDescription:"uuid"}));import{option as Be}from"pastel";import{z as Y}from"zod";var V=Y.string().trim().min(1),Le=Y.preprocess(e=>process.env.BUNNY_PROFILE&&!e?process.env.BUNNY_PROFILE.split(","):e,V.or(V.array()).optional().transform(e=>typeof e=="string"?[e]:e)),q=Le.describe(Be({alias:"p",description:"Bunny user profile name",valueDescription:"string"}));import Ne from"node:path";import{option as ve}from"pastel";import Oe from"untildify";import{z as J}from"zod";import De from"node:path";import Ke from"untildify";import{z as g}from"zod";var T="~/.bunny/credentials",C=De.resolve(Ke(T)),H=g.object({accessKey:g.string(),email:g.string(),id:g.string(),name:g.string().optional(),profile:g.string()});var je=T,Ie=J.preprocess(e=>{if(process.env.BUNNY_SHARED_CREDENTIALS_FILE&&!e){let t=process.env.BUNNY_SHARED_CREDENTIALS_FILE.trim();return Ne.resolve(Oe(t))}return e},J.string().trim().optional().default(C)),X=Ie.describe(ve({alias:"c",defaultValueDescription:je,description:"Bunny shared credentials file path",valueDescription:"file-path"}));import{createBunnyApiClient as He}from"bunny-sdk";import Je from"chalk";var Q=new Intl.ListFormat("en",{style:"long",type:"conjunction"});import ze from"tildify";var ee=process.cwd();function h(e){return e.startsWith(ee)?"."+e.slice(ee.length):ze(e)}function d(){}import $e from"fs-extra";async function te({absoluteDir:e}){await $e.emptyDir(e)}import Ge from"p-map";import Ue from"node:os";var y=Ue.cpus().length;function k(e){if(!e.ok)throw new Error(`${e.status} ${e.statusText}`,{cause:e});return e}import Me from"camelcase-keys";function S({file:e,folder:t,storageZone:r}){let o=e??t;return o?o.isDirectory?"https://"+r.storageHostname+o.path+o.objectName+"/":"https://"+r.storageHostname+o.path+o.objectName:"https://"+r.storageHostname+"/"+r.name+"/"}async function re({folder:e,storageZone:t}){let r=S({folder:e,storageZone:t});return await fetch(r,{headers:{AccessKey:t.password}}).then(k).then(async n=>n.json()).then(n=>Me(n))}async function oe({dispatchTaskEnd:e=d,dispatchTaskStart:t=d,storageZone:r}){let o=await re({storageZone:r});await Ge(o,async n=>{let i=`${n.path}${n.objectName}`.replace(`/${n.storageZoneName}`,".");t(i),await fetch(S({file:n,storageZone:r}),{headers:{AccessKey:r.password},method:"DELETE"}).then(k),e(i)},{concurrency:y})}import Ve from"fs-extra";import Ye from"p-map";function ne(e){return typeof e=="number"?Number.isInteger(e):typeof e=="string"&&e.trim()!==""?Number.isInteger(Number(e)):!1}import dr from"tiny-invariant";async function ie({bunnyApiClient:e,id:t}){return e.storagezone.byId(t).get()}import ur from"tiny-invariant";async function se({bunnyApiClient:e,includeDeleted:t=!1,name:r}){let o=await e.storagezone.get({queryParameters:{includeDeleted:t,page:1,perPage:1,search:r}});return o?.items?.[0]?.name===r?o?.items?.[0]:void 0}import We from"node:path";import _e from"untildify";function ae(e){return[...new Set(e.map(t=>{if(t.at(0)==="/"||t.startsWith("./")||t.startsWith("../")||t.startsWith("~/")||t==="."||t==="~"){let r=We.resolve(_e(t));return r.at(-1)!=="/"?r+"/":r}return t}))]}async function ce({bunnyApiClients:e,dispatchTaskEnd:t=d,dispatchTaskStart:r=d,locations:o}){return o=ae(o),await Ye(o,async i=>{r(i.at(0)==="/"?h(i):i);let l=await qe({bunnyApiClients:e,input:i});return t(i.at(0)==="/"?h(i):i),l},{concurrency:y})}async function qe({bunnyApiClients:e,input:t}){if(t.at(0)==="/")return await Ve.ensureDir(t),{path:t,type:"local"};if(t.includes("/"))throw new Error(`Location "${t}" is invalid. Local paths must be a relative path starting with "./" or an absolute path starting with "/". Storage zone names cannot include "/".`);for(let r of e){if(ne(t)){let n=await ie({bunnyApiClient:r,id:Number.parseInt(t,10)});if(n)return{bunnyApiClient:r,storageZone:n,type:"storage-zone"};continue}let o=await se({bunnyApiClient:r,name:t});if(o)return{bunnyApiClient:r,storageZone:o,type:"storage-zone"}}throw new Error(`Storage zone "${t}" cannot be found. Does it exist in your account?`)}async function pe({accessKeys:e,dispatchStoryChange:t=d,dispatchTaskEnd:r=d,dispatchTaskStart:o=d,highlight:n=Je.white,locations:i}){t(`Validate locations ${Q.format(i.map(c=>`"${n(h(c))}"`))}`);let l=e.map(c=>He({accessKey:c})),u=await ce({bunnyApiClients:l,dispatchTaskEnd:r,dispatchTaskStart:o,locations:i});for(let c of u)c.type==="local"&&(t(`Empty "${n(h(c.path))}"`),await te({absoluteDir:c.path})),c.type==="storage-zone"&&(t(`Empty "${n(c.storageZone.name)}" storage zone`),await oe({dispatchTaskEnd:r,dispatchTaskStart:o,storageZone:c.storageZone}))}import tt from"camelcase-keys";import rt from"fast-deep-equal/es6/index.js";import P from"fs-extra";import ot from"is-obj";import ye from"p-map";import{parse as nt}from"smol-toml";function me(e,t){return e.filter((r,o)=>o===e.findIndex(n=>n[t]===r[t]))}import{createBunnyApiClient as Xe}from"bunny-sdk";import Qe from"is-obj";function le({firstName:e,lastName:t}){if(e&&t)return`${e} ${t}`;if(t)return t;if(e)return e}async function w({accessKey:e,profile:t=e}){let o=await Xe({accessKey:e}).user.get().catch(i=>{throw Qe(i)&&"responseStatusCode"in i&&i.responseStatusCode===401?new Error(`Cannot find user with accessKey "${e}"`):i});if(!o)throw new Error(`Cannot find user with accessKey "${e}"`);let n=le({firstName:o.firstName,lastName:o.lastName});return{accessKey:e,email:o.email,id:o.id,...n&&{name:n},profile:t}}import{stringify as et}from"smol-toml";function de(e,t){return e.reduce((r,o)=>{let{[t]:n,...i}=o;return(typeof n=="string"||typeof n=="number"||typeof n=="symbol")&&(r[n]=i),r},{})}function fe(e){return et(de(e.map(t=>({...t,profile:t.profile??t.accessKey})),"profile"))}async function ue({accessKey:e=[],credentialsPath:t=C,profile:r=[]}={}){let o=typeof e=="string"?[e]:e,n=typeof r=="string"?[r]:r,i=await P.pathExists(t),l=[];if(i){let m=await P.readFile(t,"utf8"),be=nt(m),E=!1;if(l=await ye(Object.entries(be),async([x,F])=>{let Z=H.parse({...ot(F)?tt({...F,profile:x}):{}}),R=await w({accessKey:Z.accessKey,profile:x});return rt(Z,R)||(E=!0),R},{concurrency:y}),E){let x=fe(l);await P.outputFile(t,x)}}let u=await ye(o,async m=>w({accessKey:m,profile:m}),{concurrency:y}),c=me([...l,...u],"profile");return n.length>0?c.filter(m=>n.includes(m.profile??"")):c}async function ge(e){let t=await ue(e);return[...new Set(t.map(o=>o.accessKey))]}import{jsx as mt}from"react/jsx-runtime";var at=he.string().describe(it({description:"Location to clear all contents",name:"location"})).array(),ct=he.object({accessKey:_,profile:q,sharedCredentialsFile:X});function pt({args:e,options:t}){let[r,{dispatchEpicEnd:o,dispatchEpicError:n,dispatchStoryChange:i,dispatchTaskEnd:l,dispatchTaskStart:u}]=$();return U(r),st.useEffect(()=>{async function c(){try{i("Validate credentials");let m=await ge({accessKey:t.accessKey,credentialsPath:t.sharedCredentialsFile,profile:t.profile});if(m.length===0)throw new Error("No accessKeys found");await pe({accessKeys:m,dispatchStoryChange:i,dispatchTaskEnd:l,dispatchTaskStart:u,locations:e}),o()}catch(m){n(M(m))}}c()},[e,t.accessKey,t.profile,t.sharedCredentialsFile,o,n,i,l,u]),mt(B,{feedback:r})}export{at as args,pt as default,ct as options};