@pepitahq/cli 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +8 -3
- package/package.json +12 -11
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {hostname,userInfo,homedir}from'os';import {join,dirname,relative,sep}from'path';import {mkdirSync,writeFileSync,readFileSync,readdirSync,statSync}from'fs';import {createServer}from'http';import {spawn}from'child_process';import {unzipSync}from'fflate';import {createInterface}from'readline/promises';var ve=Object.defineProperty;var l=(e,t)=>()=>(e&&(t=e(e=0)),t);var g=(e,t)=>{for(var n in t)ve(e,n,{get:t[n],enumerable:true});};function L(){return process.env.PEPITA_CONFIG_DIR??join(homedir(),".pepita")}function _(){return join(L(),"config.json")}function x(){return process.env.PEPITA_API_BASE??m().apiBase??S}function m(){try{let e=readFileSync(_(),"utf-8"),t=JSON.parse(e);return {apiBase:S,...t}}catch{return {apiBase:S}}}function T(e){mkdirSync(L(),{recursive:true}),writeFileSync(_(),JSON.stringify(e,null,2),{mode:384});}function F(){let e=m();T({apiBase:e.apiBase});}var S,A=l(()=>{S="https://app.pepita.dev";});var N=l(()=>{});var B=l(()=>{});var H=l(()=>{});async function Te(e){let t=new TextEncoder().encode(e),n=await crypto.subtle.digest("SHA-256",t);return new Uint8Array(n)}function Ae(e){let t="";for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function I(e){return Ae(await Te(e))}var M=l(()=>{});function z(e){let t=e.fetchImpl??fetch,n=e.apiBase.replace(/\/+$/,""),s=i=>encodeURIComponent(i);async function o(i,c={}){let a=new Headers(c.headers);return e.token&&a.set("authorization",`Bearer ${e.token}`),t(`${n}${i}`,{...c,headers:a})}async function r(i,c){let a=await o(i,c);if(!a.ok)throw new d(a.status,`${c?.method??"GET"} ${i} \u2192 ${a.status} ${await a.text()}`);return await a.json()}return {raw:o,json:r,async listSites(){return (await r("/api/sites")).sites},getTree(i,c="develop"){return r(`/api/sites/${s(i)}/tree?branch=${c}`)},async writeFile(i,c,a,y){let h=await o(`/api/sites/${s(i)}/draft/write`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({path:c,content:a,encoding:y})});if(!h.ok)throw new d(h.status,`write ${c} \u2192 ${h.status} ${await h.text()}`)},async deleteFile(i,c){let a=await o(`/api/sites/${s(i)}/draft/delete`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({path:c})});if(!a.ok)throw new d(a.status,`delete ${c} \u2192 ${a.status} ${await a.text()}`)},async flush(i,c){let a=await o(`/api/sites/${s(i)}/flush`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({branch:"develop",...c})});if(a.status===409)throw new d(409,"save conflict \u2014 pull latest and retry");if(!a.ok)throw new d(a.status,`save \u2192 ${a.status} ${await a.text()}`)},publish(i){return r(`/api/sites/${s(i)}/publish`,{method:"POST"})}}}var d,D=l(()=>{d=class extends Error{status;constructor(t,n){super(n),this.name="PepitaHttpError",this.status=t;}};});var k=l(()=>{N();B();H();M();D();});function u(){return z({apiBase:x(),token:m().token??""})}async function J(e,t={}){let n=m(),s=new Headers(t.headers);n.token&&s.set("authorization",`Bearer ${n.token}`);let o=await fetch(`${x()}${e}`,{...t,headers:s});if(o.status===401)throw new P("Not logged in \u2014 run `pepita login`.");return o}var P,p,f=l(()=>{A();k();P=class extends Error{},p=class extends Error{};});function W(e=32){let t=new Uint8Array(e);return globalThis.crypto.getRandomValues(t),[...t].map(n=>n.toString(16).padStart(2,"0")).join("")}function Oe(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",n=process.platform==="win32"?["/c","start",'""',e]:[e];spawn(t,n,{stdio:"ignore",detached:true}).unref();}async function q(){let e=W(32),t=await I(e),n=W(16),s=`${hostname()} (${userInfo().username})`,{code:o}=await new Promise((y,h)=>{let U=0,$=createServer((w,v)=>{let E=new URL(w.url??"","http://127.0.0.1");if(E.pathname!=="/callback"){v.writeHead(404).end();return}let j=E.searchParams.get("code"),$e=E.searchParams.get("state");v.writeHead(200,{"content-type":"text/html"}).end('<html><body style="font-family:sans-serif;text-align:center;padding:3rem"><h2>pepita CLI</h2><p>You can close this tab and return to the terminal.</p></body></html>'),$.close(),clearTimeout(C),!j||$e!==n?h(new Error("Authorization failed (state mismatch).")):y({code:j});}),C=setTimeout(()=>{$.close(),h(new Error("Login timed out (no response). If you clicked Cancel, run `pepita login` again."));},je);$.on("error",w=>{clearTimeout(C),h(w);}),$.listen(0,"127.0.0.1",()=>{let w=$.address();U=typeof w=="object"&&w?w.port:0;let v=`${x()}/auth/cli/authorize?port=${U}&state=${n}&code_challenge=${t}&label=${encodeURIComponent(s)}`;console.log("Opening your browser to authorize\u2026"),console.log(v),Oe(v);});}),r=await fetch(`${x()}/auth/cli/token`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({code:o,code_verifier:e})});if(!r.ok)throw new Error(`Token exchange failed: ${r.status} ${await r.text()}`);let{token:i,user:c}=await r.json(),a=m();T({...a,token:i,email:c.email}),console.log(`Logged in as ${c.email}.`);}async function X(){if(m().token)try{await J("/api/cli-tokens/current",{method:"DELETE"});}catch{}F(),console.log("Logged out.");}function G(){let e=m();console.log(e.token?e.email??"logged in":"Not logged in \u2014 run `pepita login`.");}var je,b=l(()=>{k();A();f();je=18e4;});var Y={};g(Y,{run:()=>Le});var Le,V=l(()=>{b();Le=q;});var Z={};g(Z,{run:()=>_e});var _e,K=l(()=>{b();_e=X;});var Q={};g(Q,{run:()=>Fe});async function Fe(){G();}var ee=l(()=>{b();});var te={};g(te,{run:()=>Ne});async function Ne(){let e=await u().listSites();if(e.length===0)return console.log("No sites yet.");for(let t of e)console.log(t.slug);}var ne=l(()=>{f();});function Ge(e){return e.split("/").pop()??e}function Ye(e){let t=Ge(e);return Xe.has(t)||qe.has(t.split(".").pop()?.toLowerCase()??"")?"utf-8":"base64"}function se(e){if(!e||e.startsWith("/")||e.startsWith("\\"))return false;let t=e.split(/[/\\]/);for(let n of t)if(n==="..")return false;return true}function Ve(e,t){let n=[],s=[];for(let[o,r]of e){let i=t.get(o);(!i||i.content!==r.content||i.encoding!==r.encoding)&&n.push(o);}for(let o of t.keys())e.has(o)||s.push(o);return {writes:n,deletes:s}}async function re(e,t){let n=await u().getTree(e,t);return new Map(n.files.map(s=>[s.path,{content:s.content,encoding:s.encoding}]))}async function Ze(e,t){let n=await u().raw(`/api/sites/${encodeURIComponent(e)}/download?branch=${t}`);if(!n.ok)throw new Error(`GET /download?branch=${t} \u2192 ${n.status} ${await n.text()}`);let s=new Uint8Array(await n.arrayBuffer());return new Map(Object.entries(unzipSync(s)))}async function ae(e,t,n){let s;if(t==="unsaved"){s=new Map;for(let[r,i]of await re(e,"develop"))s.set(r,Buffer.from(i.content,i.encoding==="base64"?"base64":"utf-8"));}else s=await Ze(e,t==="live"?"main":"develop");let o=0;for(let[r,i]of s){if(!se(r)){console.warn(`skipping unsafe remote path: ${r}`);continue}let c=join(n,...r.split("/"));mkdirSync(dirname(c),{recursive:true}),writeFileSync(c,i),o++;}return o}function Ke(e){let t=new Map,n=s=>{for(let o of readdirSync(s)){if(o===".git"||o==="node_modules")continue;let r=join(s,o);if(statSync(r).isDirectory())n(r);else {let i=relative(e,r).split(sep).join("/");if(!se(i)){console.warn(`skipping unsafe local path: ${i}`);continue}let c=Ye(i),a=c==="base64"?readFileSync(r).toString("base64"):readFileSync(r,"utf-8");t.set(i,{content:a,encoding:c});}}};return n(e),t}async function ce(e,t,n,s){let o=Ke(t),r=await re(e,"develop"),i=Ve(o,r);if(i.writes.length===0&&i.deletes.length===0)return {written:0,deleted:0};if(!n&&!await s(i))return {written:0,deleted:0};let c=u();for(let a of i.writes){let y=o.get(a);await c.writeFile(e,a,y.content,y.encoding);}for(let a of i.deletes)await c.deleteFile(e,a);return {written:i.writes.length,deleted:i.deletes.length}}var qe,Xe,R=l(()=>{f();qe=new Set(["txt","xml","html","htm","js","css","webmanifest","svg"]),Xe=new Set(["_headers"]);});var le={};g(le,{run:()=>et});async function et(e){let t=e[0];if(!t)throw new p("usage: pepita pull <slug> [--state live|draft|unsaved] [--dir <path>]");let n=e.includes("--state")?e[e.indexOf("--state")+1]:"live";if(!Qe.includes(n))throw new p(`unknown --state '${n}' (expected: live | draft | unsaved)`);let s=n,o=e.includes("--dir")?e[e.indexOf("--dir")+1]:`./${t}`,r=await ae(t,s,o);console.log(`Pulled ${r} file(s) from ${t} (${s}) into ${o}`);}var Qe,pe=l(()=>{R();f();Qe=["live","draft","unsaved"];});var ue={};g(ue,{run:()=>nt});async function nt(e){let t=e[0];if(!t)throw new p("usage: pepita apply <slug> [--dir <path>] [--yes]");let n=e.includes("--dir")?e[e.indexOf("--dir")+1]:`./${t}`,s=e.includes("--yes"),r=await ce(t,n,s,async i=>{console.log(`Plan for ${t}: +${i.writes.length} write(s), -${i.deletes.length} delete(s)`);let c=createInterface({input:process.stdin,output:process.stdout}),a=(await c.question("Apply as unsaved changes? [y/N] ")).trim().toLowerCase();return c.close(),a==="y"||a==="yes"});console.log(`Applied to ${t}: ${r.written} written, ${r.deleted} deleted (unsaved). Run \`pepita save ${t}\` to save.`);}var de=l(()=>{R();f();});var fe={};g(fe,{run:()=>ot});async function ot(e){let t=e[0];if(!t)throw new p("usage: pepita save <slug>");let n=u(),s=await n.getTree(t,"develop"),o=s.files.filter(r=>r.dirty);await n.flush(t,{expectedHeadSha:s.headSha,files:o.map(r=>({path:r.path,content:r.content,encoding:r.encoding})),deletions:s.deletions}),console.log(`Saved ${t} to draft. Run \`pepita publish ${t}\` to go live.`);}var ge=l(()=>{f();});var me={};g(me,{run:()=>it});async function it(e){let t=e[0];if(!t)throw new p("usage: pepita publish <slug>");let n=await u().publish(t);console.log(`Published ${t} to live \u2192 ${n.productionUrl}`);}var he=l(()=>{f();});var we={};g(we,{run:()=>st});async function st(e){let t=e[0];if(!t){let o=await u().listSites();if(o.length===0){console.log("No sites yet.");return}console.log(`${o.length} site${o.length===1?"":"s"}:`);for(let r of o)console.log(` ${r.slug}`),console.log(` draft: https://${r.slug}--draft.pepita.dev live: https://${r.slug}.pepita.dev`);console.log("\nRun `pepita status <slug>` to see unsaved changes for one site.");return}let n=await u().getTree(t,"develop"),s=n.files.filter(o=>o.dirty).map(o=>o.path);console.log(`Site: ${t}`),console.log(`Draft: https://${t}--draft.pepita.dev`),console.log(`Live: https://${t}.pepita.dev`),console.log(`Unsaved: ${s.length} changed, ${n.deletions.length} deleted`);for(let o of s)console.log(` ~ ${o}`);for(let o of n.deletions)console.log(` - ${o}`);}var ye=l(()=>{f();});f();var xe=`pepita \u2014 command line for pepita sites
|
|
2
|
+
import {tmpdir,hostname,userInfo,homedir}from'os';import {join,dirname,relative,sep}from'path';import {mkdirSync,writeFileSync,readFileSync,readdirSync,statSync}from'fs';import {createServer}from'http';import {spawn}from'child_process';import {unzipSync}from'fflate';import {createInterface}from'readline/promises';var Fe=Object.defineProperty;var c=(e,t)=>()=>(e&&(t=e(e=0)),t);var g=(e,t)=>{for(var o in t)Fe(e,o,{get:t[o],enumerable:true});};function z(){return process.env.PEPITA_CONFIG_DIR??join(homedir(),".pepita")}function M(){return join(z(),"config.json")}function $(){return process.env.PEPITA_API_BASE??w().apiBase??j}function w(){try{let e=readFileSync(M(),"utf-8"),t=JSON.parse(e);return {apiBase:j,...t}}catch{return {apiBase:j}}}function B(e){mkdirSync(z(),{recursive:true}),writeFileSync(M(),JSON.stringify(e,null,2),{mode:384});}function H(){let e=w();B({apiBase:e.apiBase});}var j,O=c(()=>{j="https://app.pepita.dev";});var D=c(()=>{});var W=c(()=>{});var J=c(()=>{});async function ze(e){let t=new TextEncoder().encode(e),o=await crypto.subtle.digest("SHA-256",t);return new Uint8Array(o)}function Me(e){let t="";for(let o of e)t+=String.fromCharCode(o);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function q(e){return Me(await ze(e))}var X=c(()=>{});function G(e){let t=e.fetchImpl??fetch,o=e.apiBase.replace(/\/+$/,""),r=i=>encodeURIComponent(i);async function n(i,a={}){let l=new Headers(a.headers);return e.token&&l.set("authorization",`Bearer ${e.token}`),t(`${o}${i}`,{...a,headers:l})}async function s(i,a){let l=await n(i,a);if(!l.ok)throw new m(l.status,`${a?.method??"GET"} ${i} \u2192 ${l.status} ${await l.text()}`);return await l.json()}return {raw:n,json:s,async listSites(){return (await s("/api/sites")).sites},createSite(i,a){return s("/api/sites",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:i,allowAnalytics:a?.allowAnalytics??true})})},async deleteSite(i){let a=await n(`/api/sites/${r(i)}`,{method:"DELETE"});if(!a.ok)throw new m(a.status,`delete ${i} \u2192 ${a.status} ${await a.text()}`)},getTree(i,a="develop"){return s(`/api/sites/${r(i)}/tree?branch=${a}`)},async writeFile(i,a,l,h){let u=await n(`/api/sites/${r(i)}/draft/write`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({path:a,content:l,encoding:h})});if(!u.ok)throw new m(u.status,`write ${a} \u2192 ${u.status} ${await u.text()}`)},async deleteFile(i,a){let l=await n(`/api/sites/${r(i)}/draft/delete`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({path:a})});if(!l.ok)throw new m(l.status,`delete ${a} \u2192 ${l.status} ${await l.text()}`)},preflight(i,a){return s(`/api/sites/${r(i)}/draft/preflight`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(a)})},async flush(i,a){let l=await n(`/api/sites/${r(i)}/flush`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({branch:"develop",...a})});if(l.status===409)throw new m(409,"save conflict \u2014 pull latest and retry");if(!l.ok)throw new m(l.status,`save \u2192 ${l.status} ${await l.text()}`)},publish(i){return s(`/api/sites/${r(i)}/publish`,{method:"POST"})}}}var m,V=c(()=>{m=class extends Error{status;constructor(t,o){super(o),this.name="PepitaHttpError",this.status=t;}};});function He(e){return e.split("/").pop()??e}function De(e){return e===".well-known"||e.startsWith(".well-known/")}function We(e){return De(e)||He(e)===".gitkeep"}function C(e){return We(e)?false:e.split("/").some(t=>t.startsWith("."))}var F=c(()=>{});function qe(e){let t=e.replace(/\s/g,"");if(t.length===0)return 0;let o=t.endsWith("==")?2:t.endsWith("=")?1:0;return t.length/4*3-o}function K(e,t){return t==="base64"?qe(e):Je.encode(e).length}var Je,Y=c(()=>{F();Je=new TextEncoder;});var Z=c(()=>{});var E=c(()=>{D();W();J();X();V();Y();F();Z();});function d(){return G({apiBase:$(),token:w().token??""})}async function Q(e,t={}){let o=w(),r=new Headers(t.headers);o.token&&r.set("authorization",`Bearer ${o.token}`);let n=await fetch(`${$()}${e}`,{...t,headers:r});if(n.status===401)throw new P("Not logged in \u2014 run `pepita login`.");return n}var P,p,f=c(()=>{O();E();P=class extends Error{},p=class extends Error{};});function ee(e=32){let t=new Uint8Array(e);return globalThis.crypto.getRandomValues(t),[...t].map(o=>o.toString(16).padStart(2,"0")).join("")}function Ze(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",o=process.platform==="win32"?["/c","start",'""',e]:[e];spawn(t,o,{stdio:"ignore",detached:true}).unref();}async function te(){let e=ee(32),t=await q(e),o=ee(16),r=`${hostname()} (${userInfo().username})`,{code:n}=await new Promise((h,u)=>{let y=0,b=createServer((x,v)=>{let U=new URL(x.url??"","http://127.0.0.1");if(U.pathname!=="/callback"){v.writeHead(404).end();return}let I=U.searchParams.get("code"),Ce=U.searchParams.get("state");v.writeHead(200,{"content-type":"text/html"}).end('<html><body style="font-family:sans-serif;text-align:center;padding:3rem"><h2>pepita CLI</h2><p>You can close this tab and return to the terminal.</p></body></html>'),b.close(),clearTimeout(_),!I||Ce!==o?u(new Error("Authorization failed (state mismatch).")):h({code:I});}),_=setTimeout(()=>{b.close(),u(new Error("Login timed out (no response). If you clicked Cancel, run `pepita login` again."));},Ye);b.on("error",x=>{clearTimeout(_),u(x);}),b.listen(0,"127.0.0.1",()=>{let x=b.address();y=typeof x=="object"&&x?x.port:0;let v=`${$()}/auth/cli/authorize?port=${y}&state=${o}&code_challenge=${t}&label=${encodeURIComponent(r)}`;console.log("Opening your browser to authorize\u2026"),console.log(v),Ze(v);});}),s=await fetch(`${$()}/auth/cli/token`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({code:n,code_verifier:e})});if(!s.ok)throw new Error(`Token exchange failed: ${s.status} ${await s.text()}`);let{token:i,user:a}=await s.json(),l=w();B({...l,token:i,email:a.email}),console.log(`Logged in as ${a.email}.`);}async function oe(){if(w().token)try{await Q("/api/cli-tokens/current",{method:"DELETE"});}catch{}H(),console.log("Logged out.");}function ne(){let e=w();console.log(e.token?e.email??"logged in":"Not logged in \u2014 run `pepita login`.");}var Ye,T=c(()=>{E();O();f();Ye=18e4;});var ie={};g(ie,{run:()=>Qe});var Qe,re=c(()=>{T();Qe=te;});var se={};g(se,{run:()=>et});var et,ae=c(()=>{T();et=oe;});var le={};g(le,{run:()=>tt});async function tt(){ne();}var ce=c(()=>{T();});var pe={};g(pe,{run:()=>ot});async function ot(){let e=await d().listSites();if(e.length===0)return console.log("No sites yet.");for(let t of e)console.log(t.slug);}var ue=c(()=>{f();});function he(e){return e.split("/").pop()??e}function ut(e){let t=he(e);return pt.has(t)||ct.has(t.split(".").pop()?.toLowerCase()??"")?"utf-8":"base64"}function L(e){if(!e||e.startsWith("/")||e.startsWith("\\"))return false;let t=e.split(/[/\\]/);for(let o of t)if(o==="..")return false;return true}function dt(e){return he(e)!==".gitkeep"}function ft(e,t){let o=[],r=[];for(let[n,s]of e){let i=t.get(n);(!i||i.content!==s.content||i.encoding!==s.encoding)&&o.push(n);}for(let n of t.keys())e.has(n)||r.push(n);return {writes:o,deletes:r}}async function we(e,t){let o=await d().getTree(e,t);return new Map(o.files.map(r=>[r.path,{content:r.content,encoding:r.encoding}]))}async function gt(e,t){let o=await d().raw(`/api/sites/${encodeURIComponent(e)}/download?branch=${t}`);if(!o.ok)throw new Error(`GET /download?branch=${t} \u2192 ${o.status} ${await o.text()}`);let r=new Uint8Array(await o.arrayBuffer());return new Map(Object.entries(unzipSync(r)))}async function A(e,t,o){let r;if(t==="unsaved"){r=new Map;for(let[s,i]of await we(e,"develop"))r.set(s,Buffer.from(i.content,i.encoding==="base64"?"base64":"utf-8"));}else r=await gt(e,t==="live"?"main":"develop");let n=0;for(let[s,i]of r){if(!L(s)){console.warn(`skipping unsafe remote path: ${s}`);continue}let a=join(o,...s.split("/"));mkdirSync(dirname(a),{recursive:true}),dt(s)&&(writeFileSync(a,i),n++);}return n}function mt(e){let t=new Map,o=r=>{for(let n of readdirSync(r)){if(n===".git")continue;let s=join(r,n),i=relative(e,s).split(sep).join("/");if(statSync(s).isDirectory()){o(s);continue}if(!L(i)){console.warn(`skipping unsafe local path: ${i}`);continue}if(C(i))continue;let a=ut(i),l=a==="base64"?readFileSync(s).toString("base64"):readFileSync(s,"utf-8");t.set(i,{content:l,encoding:a});}if(r!==e){let n=`${relative(e,r).split(sep).join("/")}/.gitkeep`;L(n)&&t.set(n,{content:"",encoding:"utf-8"});}};return o(e),t}function ht(e){let t=["push would exceed pepita size limits:"];for(let o of e.perFileViolations)t.push(` ${o.path}: ${(o.size/k).toFixed(1)} MB (max ${(e.budget.perFileBytes/k).toFixed(0)} MB per file)`);return e.projectedTotal>e.budget.totalBytes&&t.push(` total would be ${(e.projectedTotal/k).toFixed(1)} MB (max ${(e.budget.totalBytes/k).toFixed(0)} MB per site)`),t.push("Shrink or remove the oversized file(s) and try again."),t.join(`
|
|
3
|
+
`)}async function R(e,t,o,r){let n=mt(t),s=await we(e,"develop"),i=ft(n,s);if(i.writes.length===0&&i.deletes.length===0)return {written:0,deleted:0};let a=d(),l=i.writes.map(u=>{let y=n.get(u);return {path:u,size:K(y.content,y.encoding)}}),h=await a.preflight(e,{writes:l,deletes:i.deletes});if(!h.ok)throw new p(ht(h));if(!o&&!await r(i))return {written:0,deleted:0};for(let u of i.writes){let y=n.get(u);await a.writeFile(e,u,y.content,y.encoding);}for(let u of i.deletes)await a.deleteFile(e,u);return {written:i.writes.length,deleted:i.deletes.length}}var ct,pt,k,S=c(()=>{f();E();ct=new Set(["txt","xml","html","htm","js","css","webmanifest","svg"]),pt=new Set(["_headers",".gitkeep"]);k=1024*1024;});var ye={};g(ye,{run:()=>wt});async function wt(e){let t=e.find(a=>!a.startsWith("--"));if(!t)throw new p("usage: pepita create <name> [--no-analytics] [--from <dir>]");let o=!e.includes("--no-analytics"),r=e.includes("--from")?e[e.indexOf("--from")+1]:void 0,{slug:n,liveUrl:s,draftUrl:i}=await d().createSite(t,{allowAnalytics:o});if(console.log(`Created ${n}
|
|
4
|
+
live: ${s}
|
|
5
|
+
draft: ${i}`),r){console.log(`Uploading files from ${r} to ${n}\u2026`);let a;for(let l=0;l<5;l++)try{a=await R(n,r,!0,async()=>!0);break}catch(h){if(l<4&&/404|empty|not found/i.test(h.message)){await new Promise(u=>setTimeout(u,750));continue}throw h}console.log(`Uploaded ${a.written} file(s) (unsaved). Run \`pepita save ${n}\` then \`pepita publish ${n}\`.`);}}var xe=c(()=>{f();S();});var $e={};g($e,{run:()=>xt});async function xt(e){let t=e[0];if(!t)throw new p("usage: pepita pull <slug> [--state live|draft|unsaved] [--dir <path>]");let o=e.includes("--state")?e[e.indexOf("--state")+1]:"live";if(!yt.includes(o))throw new p(`unknown --state '${o}' (expected: live | draft | unsaved)`);let r=o,n=e.includes("--dir")?e[e.indexOf("--dir")+1]:`./${t}`,s=await A(t,r,n);console.log(`Pulled ${s} file(s) from ${t} (${r}) into ${n}`);}var yt,be=c(()=>{S();f();yt=["live","draft","unsaved"];});var ve={};g(ve,{run:()=>bt});async function bt(e){let t=e[0];if(!t)throw new p("usage: pepita apply <slug> [--dir <path>] [--yes]");let o=e.includes("--dir")?e[e.indexOf("--dir")+1]:`./${t}`,r=e.includes("--yes"),s=await R(t,o,r,async i=>{console.log(`Plan for ${t}: +${i.writes.length} write(s), -${i.deletes.length} delete(s)`);let a=createInterface({input:process.stdin,output:process.stdout}),l=(await a.question("Apply as unsaved changes? [y/N] ")).trim().toLowerCase();return a.close(),l==="y"||l==="yes"});console.log(`Applied to ${t}: ${s.written} written, ${s.deleted} deleted (unsaved). Run \`pepita save ${t}\` to save.`);}var Pe=c(()=>{S();f();});var Se={};g(Se,{run:()=>vt});async function vt(e){let t=e[0];if(!t)throw new p("usage: pepita save <slug>");let o=d(),r=await o.getTree(t,"develop"),n=r.files.filter(s=>s.dirty);await o.flush(t,{expectedHeadSha:r.headSha,files:n.map(s=>({path:s.path,content:s.content,encoding:s.encoding})),deletions:r.deletions}),console.log(`Saved ${t} to draft. Run \`pepita publish ${t}\` to go live.`);}var Ee=c(()=>{f();});var Te={};g(Te,{run:()=>Pt});async function Pt(e){let t=e[0];if(!t)throw new p("usage: pepita publish <slug>");let o=await d().publish(t);console.log(`Published ${t} to live \u2192 ${o.productionUrl}`);}var ke=c(()=>{f();});var Re={};g(Re,{confirmMatchesSlug:()=>Ae,run:()=>kt});function Ae(e,t){return e.trim()===t}async function kt(e){let t=e.find(n=>!n.startsWith("--"));if(!t)throw new p("usage: pepita delete <slug> [--download-snapshot] [--yes]");let o=e.includes("--yes");if(e.includes("--download-snapshot")){let n=join(tmpdir(),`pepita-${t}-${Date.now()}`),s=await A(t,"unsaved",n);console.log(`Snapshot: ${s} file(s) \u2192 ${n}`);}if(!o){let n=createInterface({input:process.stdin,output:process.stdout}),s=await n.question(`This permanently deletes ${t} and stops serving it. Type the slug to confirm: `);if(n.close(),!Ae(s,t)){console.log("Cancelled.");return}}await d().deleteSite(t),console.log(`Deleted ${t} \u2014 it no longer serves.`);}var Ue=c(()=>{f();S();});var je={};g(je,{run:()=>At});async function At(e){let t=e[0];if(!t){let n=await d().listSites();if(n.length===0){console.log("No sites yet.");return}console.log(`${n.length} site${n.length===1?"":"s"}:`);for(let s of n)console.log(` ${s.slug}`),console.log(` draft: https://${s.slug}--draft.pepita.dev live: https://${s.slug}.pepita.dev`);console.log("\nRun `pepita status <slug>` to see unsaved changes for one site.");return}let o=await d().getTree(t,"develop"),r=o.files.filter(n=>n.dirty).map(n=>n.path);console.log(`Site: ${t}`),console.log(`Draft: https://${t}--draft.pepita.dev`),console.log(`Live: https://${t}.pepita.dev`),console.log(`Unsaved: ${r.length} changed, ${o.deletions.length} deleted`);for(let n of r)console.log(` ~ ${n}`);for(let n of o.deletions)console.log(` - ${n}`);}var Be=c(()=>{f();});f();var Oe=`pepita \u2014 command line for pepita sites
|
|
3
6
|
|
|
4
7
|
Usage: pepita <command> [args]
|
|
5
8
|
|
|
@@ -7,10 +10,12 @@ Usage: pepita <command> [args]
|
|
|
7
10
|
logout Remove the local token
|
|
8
11
|
whoami Show the logged-in account
|
|
9
12
|
list List your sites
|
|
13
|
+
create <name> [--no-analytics] [--from d] Create a new site (optionally from a local dir)
|
|
10
14
|
pull <slug> [--state live|draft|unsaved] [--dir d] Download a site's files (default: live)
|
|
11
15
|
apply <slug> [--dir d] [--yes] Upload local files as unsaved changes
|
|
12
16
|
save <slug> Save unsaved changes to the draft
|
|
13
17
|
publish <slug> Publish the draft to live
|
|
18
|
+
delete <slug> [--download-snapshot] [--yes] Permanently delete a site (optionally snapshot to /tmp first)
|
|
14
19
|
status <slug> Show unsaved changes + URLs
|
|
15
|
-
`,
|
|
16
|
-
`),console.log(
|
|
20
|
+
`,Rt={login:()=>Promise.resolve().then(()=>(re(),ie)),logout:()=>Promise.resolve().then(()=>(ae(),se)),whoami:()=>Promise.resolve().then(()=>(ce(),le)),list:()=>Promise.resolve().then(()=>(ue(),pe)),create:()=>Promise.resolve().then(()=>(xe(),ye)),pull:()=>Promise.resolve().then(()=>(be(),$e)),apply:()=>Promise.resolve().then(()=>(Pe(),ve)),save:()=>Promise.resolve().then(()=>(Ee(),Se)),publish:()=>Promise.resolve().then(()=>(ke(),Te)),delete:()=>Promise.resolve().then(()=>(Ue(),Re)),status:()=>Promise.resolve().then(()=>(Be(),je))};async function Ut(){let[,,e,...t]=process.argv;if(!e||e==="--help"||e==="-h"||e==="help"){console.log(Oe);return}let o=Rt[e];if(!o){console.error(`Unknown command: ${e}
|
|
21
|
+
`),console.log(Oe),process.exitCode=1;return}await(await o()).run(t);}Ut().catch(e=>{e instanceof p?(console.error(e.message),process.exitCode=1):e instanceof P||e instanceof m&&e.status===401?(console.error("Not logged in \u2014 run `pepita login`."),process.exitCode=2):(console.error(`Error: ${e?.message??e}`),process.exitCode=1);});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pepitahq/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Command-line for pepita sites — pull, apply, save, publish.",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Command-line for pepita sites — create, pull, apply, save, publish, delete.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Zoltan Gobolos <zgobolos@barelynotable.com>",
|
|
7
7
|
"type": "module",
|
|
@@ -26,21 +26,22 @@
|
|
|
26
26
|
"publishConfig": {
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"build": "tsup",
|
|
31
|
+
"prepack": "pnpm build",
|
|
32
|
+
"dev": "tsx src/index.ts",
|
|
33
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
34
|
+
"test": "vitest run"
|
|
35
|
+
},
|
|
29
36
|
"dependencies": {
|
|
30
37
|
"fflate": "^0.8.3"
|
|
31
38
|
},
|
|
32
39
|
"devDependencies": {
|
|
40
|
+
"@pepitahq/shared": "workspace:*",
|
|
33
41
|
"@types/node": "^22.0.0",
|
|
34
42
|
"tsup": "^8.0.0",
|
|
35
43
|
"tsx": "^4.19.0",
|
|
36
44
|
"typescript": "^5.7.0",
|
|
37
|
-
"vitest": "^3.0.0"
|
|
38
|
-
"@pepitahq/shared": "0.0.0"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"build": "tsup",
|
|
42
|
-
"dev": "tsx src/index.ts",
|
|
43
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
44
|
-
"test": "vitest run"
|
|
45
|
+
"vitest": "^3.0.0"
|
|
45
46
|
}
|
|
46
|
-
}
|
|
47
|
+
}
|