@shopify/cli
Version:
A CLI tool to build for the Shopify platform
3 lines (2 loc) • 10.8 kB
JavaScript
import{a as C}from"./chunk-NF2ABOOU.js";import{a as ce}from"./chunk-JQJBBXMX.js";import{b as te,c as oe,d as re,e as se,f as ie,g as ne,i as ae,j as le,l as me}from"./chunk-OY3PNHPZ.js";import{a as Q}from"./chunk-MWGBTOO3.js";import{c as V,e as P,m as X}from"./chunk-K6CTUBFC.js";import{c as Z,e as ee}from"./chunk-GVQIPEZT.js";import{n as R,p as w}from"./chunk-XITQULK4.js";import{a as z,b as B}from"./chunk-6SF3ZETE.js";import{o as K,s as J,t as Y,u as j,w as N}from"./chunk-IX5ICOBV.js";import{k as v,l as x,n as y}from"./chunk-CBXSPL4W.js";import{ta as L,xa as $}from"./chunk-XONFGLJQ.js";import{a as O}from"./chunk-JUVAGMIH.js";import{J as U,s as M,u as I,v as H,w as T,y as q,z as G}from"./chunk-6G6TMKXF.js";import{d as _,e as W}from"./chunk-WSDN25F5.js";import{d as g}from"./chunk-M56NDIMD.js";import{Gb as k,Ib as b,Nb as S,Qb as f,tb as p}from"./chunk-N5PQPIBF.js";import{g as d}from"./chunk-VPRTJUIN.js";d();d();d();d();var de={workPromise:Promise.resolve()};async function he(e,t,r,o,s){if(r.length===0)return de;f("Initiating theme asset reconciliation process");let{filesOnlyPresentLocally:a,filesOnlyPresentOnRemote:i,filesWithConflictingChecksums:l}=be(r,o),n=a.length===0&&i.length===0&&l.length===0;if($(`theme-service:theme-reconciliation:manual:${n}`),n)return f("Local and remote checksums match - no need to reconcile theme assets"),de;let m=await Re({filesOnlyPresentLocally:a,filesOnlyPresentOnRemote:i,filesWithConflictingChecksums:l},s);return{workPromise:Se(e,t,o,m)}}function be(e,t){let r=new Set,o=[],s=[];for(let i of e){r.add(i.key);let l=t.files.get(i.key);l?i.checksum!==l.checksum&&s.push(i):o.push(i)}let a=Array.from(t.files.values()).filter(i=>!r.has(i.key));return{filesOnlyPresentOnRemote:A(o,t),filesOnlyPresentLocally:A(a,t),filesWithConflictingChecksums:A(s,t)}}function A(e,t){return t.applyIgnoreFilters(e).filter(o=>o.key.endsWith(".json"))}async function E(e,t,r){if(e.length===0)return;I({body:{list:{title:t,items:e.map(s=>s.key)}}}),await G({message:"Reconciliation Strategy",choices:[{label:r.remote.label,value:D},{label:r.local.label,value:ue}]})===D?r.remote.callback(e):r.local.callback(e)}async function Se(e,t,r,o){let{localFilesToDelete:s,filesToDownload:a,remoteFilesToDelete:i}=o,l=s.map(c=>r.delete(c.key)),n=C(a,w,async c=>{let h=await v(e.id,c.map(u=>u.key),t);return Promise.all(h.map(u=>{if(u)return r.write(u)}))}),m=x(e.id,i.map(c=>c.key),t);await Promise.all([...l,...n,m])}async function Re(e,t){let{filesOnlyPresentLocally:r,filesOnlyPresentOnRemote:o,filesWithConflictingChecksums:s}=e,a=[],i=[],l=[];return t.noDelete||await E(r,"The files listed below are only present locally. What would you like to do?",{remote:{label:"Delete files from the local directory",callback:n=>{a.push(...n)}},local:{label:"Upload local files to the remote theme",callback:()=>{}}}),await E(o,"The files listed below are only present on the remote theme. What would you like to do?",{remote:{label:"Download remote files to the local directory",callback:n=>{i.push(...n)}},local:{label:"Delete files from the remote theme",callback:n=>{l.push(...n)}}}),await E(s,"The files listed below differ between the local and remote versions. What would you like to do?",{remote:{label:"Keep the remote version",callback:n=>{i.push(...n)}},local:{label:"Keep the local version",callback:()=>{}}}),{localFilesToDelete:a,filesToDownload:i,remoteFilesToDelete:l}}d();var Ae=3e3,F=class extends Error{};function pe(e,t,r,o,s,a){f("Listening for changes in the theme editor");let i=5,l=0,n="",m=r,c=async()=>{await new Promise(h=>setTimeout(h,Ae)),m=await Ee(e,t,m,o,s).then(h=>(l=0,n="",h)).catch(h=>{if(l++,h.message!==n&&(n=h.message,P("Error while polling for changes.",h)),l>=i){let u=new g("Too many polling errors...","Please check the errors above and ensure you have a stable internet connection.");q(u),a(u)}return m})};setTimeout(async()=>{for(;;)await c()})}async function Ee(e,t,r,o,s){let a=new Set(o.unsyncedFileKeys),i=fe(r,o,a),l=await y(e.id,t).then(c=>fe(c,o,a)),n=Fe(i,l),m=De(l,i);return await $e(o,n),await Oe(e,t,o,n),await Le(o,m,s),l}function De(e,t){let r=new Map(e.map(s=>[s.key,s]));return t.filter(s=>r.get(s.key)===void 0)}function Fe(e,t){let r=new Map(e.map(s=>[s.key,s]));return t.filter(s=>{let a=r.get(s.key);if(!a||a.checksum!==s.checksum)return!0})}async function Oe(e,t,r,o){let s=o.filter(i=>r.files.get(i.key)?.checksum!==i.checksum),a=C(s,w,async i=>v(e.id,i.map(l=>l.key),t).then(l=>Promise.all(l.map(async n=>{n&&(await r.write(n),S(b`• ${R.format(new Date)} Synced ${k.raw("\xBB")} ${k.gray(`download ${n.key} from remote theme`)}`))}))));await Promise.all(a)}async function Le(e,t,r){if(!r.noDelete)return Promise.all(t.map(o=>{if(e.files.get(o.key))return e.delete(o.key).then(()=>{S(b`• ${R.format(new Date)} Synced ${k.raw("\xBB")} ${k.gray(`remove ${o.key} from local theme`)}`)})}))}async function $e(e,t){let r=new Map(e.files);await Promise.all(t.map(o=>e.read(o.key)));for(let o of t){let s=r.get(o.key)?.checksum,a=e.files.get(o.key)?.checksum;if(s!==a)throw new F(`Detected changes to the file '${o.key}' on both local and remote sources. Aborting...`)}}function fe(e,t,r){return t.applyIgnoreFilters(e).filter(s=>s.key.endsWith(".json")).filter(s=>!r.has(s.key))}var ue="local",D="remote";async function ye(e,t,r,o,s,a){f("Initiating theme asset reconciliation process"),await o.ready();let{workPromise:i}=await he(e,t,r,o,s);return{updatedRemoteChecksumsPromise:i.then(async()=>{let n=await y(e.id,t);return pe(e,t,n,o,s,a),n}),workPromise:i}}d();function ke(){if(Promise.withResolvers)return Promise.withResolvers();let e,t;return{promise:new Promise((o,s)=>{e=o,t=s}),resolve:e,reject:t}}import{createServer as _e}from"node:http";function ge(e,t){let{promise:r,resolve:o,reject:s}=ke(),a=ie(e,t),i=We(e,t,s),l=Promise.all([a,i.workPromise]).then(()=>t.localThemeFileSystem.startWatcher(e.id.toString(),t.session)),n=Ie(e,t,l);return{workPromise:l,serverStart:n.start,dispatchEvent:n.dispatch,renderDevSetupProgress:i.renderProgress,backgroundJobPromise:r,resolveBackgroundJob:o}}function We(e,t,r){let o=n=>(P("Failed to perform the initial theme synchronization.",n),r(n),new Promise(()=>{})),a=y(e.id,t.session).then(n=>Me(e,t,n,r)),i=a.then(async({updatedRemoteChecksumsPromise:n})=>{let m=await n;return ce(e,t.session,m,t.localThemeFileSystem,{nodelete:t.options.noDelete,deferPartialWork:!0,backgroundWorkCatch:o})});return{workPromise:i.then(n=>n.workPromise).catch(o),renderProgress:async()=>{if(t.options.themeEditorSync){let{workPromise:m}=await a;await ee([{title:"Performing file synchronization. This may take a while...",task:async()=>{await m}}])}let{renderThemeSyncProgress:n}=await i;await n()}}}function Me(e,t,r,o){return t.options.themeEditorSync?ye(e,t.session,r,t.localThemeFileSystem,{noDelete:t.options.noDelete,ignore:t.options.ignore,only:t.options.only},o):Promise.resolve({updatedRemoteChecksumsPromise:Promise.resolve(r),workPromise:Promise.resolve()})}function Ie(e,t,r){let o=j(),s=[`http://${t.options.host}:${t.options.port}`,`https://${t.session.storeFqdn}`];o.use(Y(async()=>(await r,J(i=>{i.node.req.headers.origin&&K(i,{origin:n=>s.includes(n),credentials:!0,methods:["GET","POST","HEAD","OPTIONS"],preflight:{statusCode:204}})})))),t.options.liveReload!=="off"&&o.use(ne(e,t)),o.use(re(e,t)),o.use(te(e,t)),o.use(oe(e,t));let a=_e(N(o));return{dispatch:o.handler.bind(o),start:async()=>new Promise(i=>a.listen({port:t.options.port,host:t.options.host},()=>i({close:async()=>{await Promise.all([new Promise(l=>{a.closeAllConnections(),a.close(l)})])}})))}}import He from"readline";var qe="127.0.0.1",Ge="9292",ve=!1;async function Bt(e){if(!await me(e.directory)&&!await Z(e.force))return;e.password?.startsWith("shpat_")&&T({headline:"Admin API token missing features:",body:["Directly using an Admin API token will result in some missing features.","We recommend generating a password from the Theme Access app.","Alternatively, you can authenticate normally by not passing the --password flag.",`
`,{list:{title:"Known limitations:",items:["Hot module reloading","Password protected storefronts"]}}],link:{label:"Theme Access app",url:"https://shopify.dev/docs/storefronts/themes/tools/theme-access"}}),e.listing&&await ae(e.directory,e.listing);let t=await V(e.adminSession).then(Te=>Te?Q(e.storePassword,e.adminSession.storeFqdn):void 0),r=se(),o=le(e.directory,{filters:e,listing:e.listing,noDelete:e.noDelete,notify:e.notify}),s=e.host??qe;if(e.port&&!await B(Number(e.port)))throw new g(`Port ${e.port} is not available. Try a different port or remove the --port flag to use an available port.`);let a=e.port??String(await z(Number(Ge))),i={local:`http://${s}:${a}`,giftCard:`http://${s}:${a}/gift_cards/[store_id]/preview`,themeEditor:`https://${e.store}/admin/themes/${e.theme.id}/editor?hr=${a}`,preview:`https://${e.store}/?preview_theme_id=${e.theme.id}`},l=await t,m={session:await X(e.theme.id.toString(),e.adminSession,e.password,l),localThemeFileSystem:o,localThemeExtensionFileSystem:r,directory:e.directory,type:"theme",lastRequestedPath:"",options:{themeEditorSync:e["theme-editor-sync"],host:s,port:a,open:e.open,liveReload:e["live-reload"],noDelete:e.noDelete,ignore:e.ignore,only:e.only,errorOverlay:e["error-overlay"]}},{serverStart:c,renderDevSetupProgress:h,backgroundJobPromise:u,resolveBackgroundJob:Pe}=ge(e.theme,m);He.emitKeypressEvents(process.stdin);let Ce=xe(i,m,Pe);process.stdin.on("keypress",Ce),await Promise.all([u,h().then(c).then(()=>{process.stdin.isTTY&&process.stdin.setRawMode(!0),Je(i),e.open&&we(i.local,"development server")})]),await Ue(e.commandConfig,e.adminSession),process.exit(0)}async function Ue(e,t){if(!ve){ve=!0;try{await _(()=>({store_fqdn_hash:O(t.storeFqdn)})),await W(()=>({store_fqdn:t.storeFqdn})),await L({config:e,exitMode:"ok"})}catch{}}}function xe(e,t,r){let o=M(we,100,{leading:!0,trailing:!1});return(s,a)=>{if(a.ctrl&&a.name==="c"){r();return}switch(a.name){case void 0:break;case"t":o(e.local,"localhost");break;case"p":o(e.preview,"theme preview");break;case"e":o(t.lastRequestedPath==="/"?e.themeEditor:`${e.themeEditor}&previewPath=${encodeURIComponent(t.lastRequestedPath)}`,"theme editor");break;case"g":o(e.giftCard,"gift card preview");break;default:break}}}function we(e,t){U(e).catch(Ke(t))}function Ke(e){return t=>{T({headline:`Failed to open ${e}.`,body:t.stack??t.message})}}function Je(e){H({body:[{list:{title:p.bold("Preview your theme ")+p.cyan("(t)"),items:[{link:{url:e.local}}]}}],nextSteps:[[{link:{label:`Share your theme preview ${p.cyan("(p)")}`,url:e.preview}},{subdued:e.preview}],[{link:{label:`Customize your theme at the theme editor ${p.cyan("(e)")}`,url:e.themeEditor}}],[{link:{label:`Preview your gift cards ${p.cyan("(g)")}`,url:e.giftCard}}]]})}export{Bt as a,we as b};