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