@stacksjs/ts-cloud 0.16.44 → 0.16.45
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/bin/{chunk-gn03w47w.js → chunk-01w4zbex.js} +1 -1
- package/dist/bin/{chunk-nmqjmx30.js → chunk-12x968en.js} +1 -1
- package/dist/bin/chunk-1xxmyx0r.js +1 -0
- package/dist/bin/{chunk-kdsgbvep.js → chunk-23m8kbwh.js} +1 -1
- package/dist/bin/{chunk-bj7ashn6.js → chunk-2gqhzn2r.js} +1 -1
- package/dist/bin/chunk-45qr2bd3.js +1 -0
- package/dist/bin/chunk-4nn00brw.js +1 -0
- package/dist/bin/{chunk-t80pxn04.js → chunk-50r8znqt.js} +6 -6
- package/dist/bin/chunk-5f1n5d80.js +1 -0
- package/dist/bin/{chunk-s64d5nw2.js → chunk-5mm6qn6m.js} +1 -1
- package/dist/bin/chunk-5xr76cms.js +1 -0
- package/dist/bin/{chunk-q40k9jvk.js → chunk-65yvjecx.js} +2 -2
- package/dist/bin/{chunk-5amvqed8.js → chunk-6y6g726g.js} +3 -3
- package/dist/bin/{chunk-f64jvh96.js → chunk-7qbxq0be.js} +2 -2
- package/dist/bin/{chunk-8z4wgqkh.js → chunk-cz2wq0tf.js} +1 -1
- package/dist/bin/chunk-d0tmmzy5.js +1 -0
- package/dist/bin/{chunk-erf79tm2.js → chunk-dawvjb7v.js} +21 -21
- package/dist/bin/{chunk-7p2va3nj.js → chunk-de69nra4.js} +1 -1
- package/dist/bin/{chunk-tf8qxy9k.js → chunk-dj03v81n.js} +20 -20
- package/dist/bin/chunk-fqghdpvr.js +1 -0
- package/dist/bin/{chunk-35x7z78g.js → chunk-frzpqsbj.js} +1 -1
- package/dist/bin/chunk-gkdr09xx.js +1 -0
- package/dist/bin/{chunk-xxe9ga9r.js → chunk-gyvkravq.js} +3 -3
- package/dist/bin/{chunk-jaexpxs8.js → chunk-her9ny96.js} +1 -1
- package/dist/bin/{chunk-3hkppc7h.js → chunk-kqxk1pds.js} +1 -1
- package/dist/bin/{chunk-hfnpjy9y.js → chunk-n2c6y0k1.js} +1 -1
- package/dist/bin/{chunk-3v2pd05g.js → chunk-nhqz2j90.js} +1 -1
- package/dist/bin/chunk-pg65zy8y.js +1 -0
- package/dist/bin/chunk-pr1dg1km.js +1 -0
- package/dist/bin/{chunk-dkf2kcsc.js → chunk-psvqpztv.js} +3 -3
- package/dist/bin/{chunk-ce1qnjs2.js → chunk-pzj1ac7x.js} +1 -1
- package/dist/bin/{chunk-gngsb689.js → chunk-q4dywv80.js} +2 -2
- package/dist/bin/{chunk-pf9dbm3b.js → chunk-q8b77zgw.js} +1 -1
- package/dist/bin/{chunk-qj6tr7bw.js → chunk-qq1f07te.js} +3 -3
- package/dist/bin/chunk-r1kg6yxp.js +1 -0
- package/dist/bin/{chunk-mgwmt2et.js → chunk-rdkr74y2.js} +2 -2
- package/dist/bin/{chunk-jh1vmant.js → chunk-rgcrsd5m.js} +1 -1
- package/dist/bin/chunk-t1mmfpn1.js +1 -0
- package/dist/bin/chunk-thph4z3k.js +1 -0
- package/dist/bin/chunk-txykq6f1.js +1 -0
- package/dist/bin/{chunk-2r9tj1ac.js → chunk-v09tfezh.js} +5 -5
- package/dist/bin/{chunk-dryvqne2.js → chunk-v7t6f8aw.js} +2 -2
- package/dist/bin/{chunk-knzje4ka.js → chunk-vjg2fymw.js} +1 -1
- package/dist/bin/chunk-vt3hjh9q.js +1 -0
- package/dist/bin/{chunk-sg8hcdev.js → chunk-w29z877b.js} +1 -1
- package/dist/bin/{chunk-7593hjcq.js → chunk-xdk0gmxt.js} +1 -1
- package/dist/bin/{chunk-fkzp9sg5.js → chunk-xe527q1k.js} +1 -1
- package/dist/bin/{chunk-9eqpnanr.js → chunk-xx9mrcfs.js} +1 -1
- package/dist/bin/{chunk-vjfwnj9z.js → chunk-ym9h629y.js} +4 -4
- package/dist/bin/{chunk-cqc4e8md.js → chunk-yp3a0j9n.js} +1 -1
- package/dist/bin/{chunk-kzpzkdpd.js → chunk-z8k9mcn5.js} +1 -1
- package/dist/bin/chunk-z8scg2vy.js +1 -0
- package/dist/bin/{chunk-pnj95hwr.js → chunk-znd507q9.js} +1 -1
- package/dist/bin/cli.js +98 -98
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-txwnpxzf.js → chunk-294kdscm.js} +1 -1
- package/dist/{chunk-a102vqez.js → chunk-vv5fmmhr.js} +1 -1
- package/dist/deploy/index.js +1 -1
- package/dist/drivers/factory.d.ts +3 -3
- package/dist/drivers/index.js +1 -1
- package/dist/fly/client.d.ts +153 -0
- package/dist/fly/deploy.d.ts +72 -0
- package/dist/fly/index.d.ts +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +26 -26
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +5 -5
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +1 -1
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +5 -5
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +5 -5
- package/dist/ui/operations/releases.html +6 -6
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +6 -6
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +6 -6
- package/dist/ui/server/diagnostics.html +1 -1
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +6 -6
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +1 -1
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +1 -1
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +2 -2
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +1 -1
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +6 -6
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +5 -5
- package/package.json +3 -3
- package/dist/bin/chunk-26rf5dy2.js +0 -1
- package/dist/bin/chunk-5khcwxhn.js +0 -1
- package/dist/bin/chunk-5nc1g18b.js +0 -1
- package/dist/bin/chunk-71ep1g7k.js +0 -1
- package/dist/bin/chunk-7fh7b8r1.js +0 -1
- package/dist/bin/chunk-7nsjehvx.js +0 -1
- package/dist/bin/chunk-bb08ms5q.js +0 -1
- package/dist/bin/chunk-g3a9a8bx.js +0 -1
- package/dist/bin/chunk-jv9qp13h.js +0 -1
- package/dist/bin/chunk-k9ate69x.js +0 -1
- package/dist/bin/chunk-mh3rgn0e.js +0 -1
- package/dist/bin/chunk-nfb3ew1v.js +0 -1
- package/dist/bin/chunk-qgqgdkg0.js +0 -1
- package/dist/bin/chunk-s77kny9g.js +0 -1
- package/dist/bin/chunk-vn05n5z6.js +0 -1
- package/dist/bin/chunk-yxpzm8ce.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import{dI,lI,Od,qp,_d,Ld,Jr,L,d,$d,jp,Q,Md,g,NA,Mi,Fd,Ud,fe,Qd,kA,r,t,uI,gI,p,pI,mI,fI,hI,yI,Xt,Hd,Fi,BA,SI,II,De,je,Gd,zp,Kp,bI,Wp,Jp,Xp,Eo,Vd,re,Xr,yt,vo,St,he,xA,qd,To,Yp,Zp,em,tm,jd,CI,H,b,OA,_A,rm,a,y,ze,m,nm,Ke,G,It,EI,im,V,zd,Pe,Yt,wo,ne,Kd,ie,LA,Ro,q,j,k,Ui,T,Zt,bt,z,e,Yr,vI,sm,Wd,TI,wI,RI,DI,Jd,PI,NI,kI,BI,xI,OI,_I,LI,$I,MI,FI,UI,$A,MA,FA,UA,QA,HA,GA,er,om,am,Zr,Qi,QI,cm,HI,GI,en,VI,qI,jI,zI,KI,WI,VA,qA,jA,zA,KA,Hi,JI,Do,WA,dm,F,JA,We,Po,Ct,XA,lm,YA,ZA,ey,um,U,XI,YI,ZI,eb,ty,tb,K,rb,nb,ib,Xd,Yd,ry,gm,pm,sb,ob,ab,cb,db,ny,Zd,lb,ub,gb,pb,mb,iy,sy,fb,hb,Ab,yb,Sb,Ib,bb,oy,Cb,mm,el,Eb,vb,Tb,wb,fm,hm,Am,Rb,tl,ay,cy,dy,ly,rl,uy,Db,Pb,Nb,kb,Bb,xb,Ob,gy,py,my,fy,ym,_b,Lb,$b,Mb,Fb,Ub,Qb,Hb,Gb,hy,Ay,yy,Sy,Vb,qb,Sm,jb,Im,bm,Cm,Em,zb,Kb,Wb,Jb,Ne,Gi,Xb,Yb,Zb,eC,tC,rC,nC,iC,Iy,sC,oC,vm,Tm,aC,cC,by,dC,lC,uC,gC,pC,mC,fC,hC,AC,yC,SC,IC,bC,CC,EC,vC,TC,wC,RC,DC,PC,nl,Cy,il,Ey,sl,vy,ol,Ty,al,wy,tr,Ry,cl,Dy,Vi,Py,dl,Ny,ll,ky,wm,NC,Rm,kC,ul,By,rr,xy,Dm,BC,gl,Oy,Pm,xC,Nm,OC,km,_C,pl,_y,Bm,LC,xm,$C,Om,MC,_m,FC,ml,Ly,fl,$y,Lm,UC,$m,QC,Mm,HC,Fm,GC,Um,VC,Qm,qC,hl,My,Hm,jC,Gm,zC,Vm,KC,qm,WC,jm,JC,zm,XC,Km,Wm,Jm,Xm,Ym,YC,Zm,ZC,ef,eE,tf,tE,Je,rf,Fy,No,Al,tn,Uy,qi,nr,yl,Sl,Qy,Hy,Il,nf,bl,sf,rE,nE,ko,Bo,xo,Cl,rn,El,vl,ji,Oo,_o,of,Gy,Vy,qy,iE,af,cf,sE,jy,df,zy,Ky,Wy,oE,lf,nn,Tl,uf,aE,Jy,Lo,$o,wl,gf,cE,Rl,Xy,pf,dE,mf,lE,ff,uE}from"./chunk-c5jyzyqw.js";import{Dl,R,Pl,Mo,Yy,hf,Zy,eS,tS,rS,nS,iS,sS,oS}from"./chunk-x2pxtfk0.js";import{Vo,Af,Ll,lS,Ji,$l,qo,yf,Sf,on,jo,Ml,Ye,Fl,Ul,Ql,Xi,an,If,Ze,Hl,zo,Ko,Wo,Gl,Vl,ql,Yi,Jo,jl,cn,Zi,Xo,Et,bf,zl,Kl,Cf,Wl,Yo,ir,Jl,Xl,Yl,Zl,et,Ef,eu,sr,Zo,ea,ta,es,ts,dn,tu,rs,ra,na,ln,ru,un,vf,Tf,vt,gn,ia,wf,nu,iu,sa,su,ou,au,uS,se,cu,gS,pS,ns,is,mS,Ae,Rf,Tt,ke,Be,wt,du,lu,uu,gu,Df,Pf,oa,Nf,kf,aa,pu,mu,Bf,oe,xf,fu,ye,ca,tt,Rt,Dt,pn,ss,hu,fS,da,Of,_f,Lf,$f,la,ua,Au,mn,ga,yu,os,Su,pa,ma,fa,ha,Aa,ya,Sa,Ia,Iu,or,ba,bu,fn,Cu,Ca,Ea,Eu,ar,va,Ta,Mf,hS,as,AS,yS,SS,wa,Ra,vu,Ff,Da,hn,Tu,cs,wu,Ru,Du,Pa,Uf,Na,Pu,Qf,ka,Hf,An,yn,Nu,ds,Lu,Uu,Qu,Hu,Gu,Vu,us,cr,xa,Sn,In,dr,rt,Jf,_a,Xf,Yf,zu,La,ps,Ku,$a,Nt,Oe,Wu,Ma,Fa,Ju,Ua,Qa,Ha,Ga,Xu,Yu,Cn,Va,qa,ja,za,Zu,ms,En,fs,Ka}from"./chunk-txwnpxzf.js";import{_,Lr,Wc,Xs,u,Sp,Ip}from"./chunk-hm6pwhne.js";import{pt,Kc,bi,Ci,Ei,yp}from"./chunk-1w9v8g26.js";import{Nh,kh,Bh,Zg,ep,tp,xh,rp,np,Oh,_h,ip,Lh,$h,jc,sp,Mh,Fh,op,Uh,Qh,Hh,Gh,Vh,qh,jh,Ii,zc,ap,cp,dp,lp,up,gp,pp,mp,fp,hp,Ap,zh,Kh,Wh,Jh,Xh,Yh,Zh}from"./chunk-vkrgf3sv.js";import{Ge,Jc,me,Vt,Xc,P,qt,mt,Yc,Ys,rA,bp,Zc,s,vi,Zs,$r,ed,td,Mr,nA,rd,sI,oI,eo,aI,cI,nd,id,Ti,to,te,c,ro,Ve,Fr,iA,sA,sd,jt,oA,no,aA,cA,io,od,Ur,so,dA,ad,Cp,zt,Qr,lA,oo,uA,N,gA,cd,Ep,ao,pA,mA,fA,dd,wi,co,ld,Kt,ft,hA,Hr,AA,ud,vp,Tp,lo,gd,pd,ht,wp,Ri,md,uo,Gr,Rp,Di,fd,hd,Pi,Dp,Ad,yd,Sd,Id,go,Pp,Np,yA,kp,bd,Ni,Bp,xp,po,Vr,mo,fo,ho,Cd,Op,Ed,Ao,SA,Wt,IA,vd,qr,Td,bA,wd,_p,ki,jr,yo,Bi,qe,CA,Lp,$p,Jt,Rd,Dd,Pd,xi,Oi,_i,EA,vA,At,So,TA,zr,Mp,Io,wA,Fp,Up,Qp,RA,Hp,Gp,DA,i,PA,Li,bo,Co}from"./chunk-v3w791ze.js";import{n}from"./chunk-cgcthvq9.js";import{be,ot,On}from"./chunk-w78e5n94.js";import{o}from"./chunk-bwtxb2hf.js";import{Se,Cs,Es,rg,Za,ec,vs,tc,nt,W,it,ae,E,Ie,Rn,rc,_e,nc,Dn,Pn,Nn,kt,Bt,xt,kn,ur,ic,gr,pr,st,Bn,oc,Ot,mr,xn,cc,ag,cg,dc,fr}from"./chunk-8jsf214f.js";import{at,le,Me,dg,_t,uc,gc,Lt,M,_n,$t,Mt,Ln,Ds,Ps,hr,Ar,$n,yr,Ns,ks,Bs,xs,X,Os,_s,Ls,$s,ue,Ms,Fs,Us,D,pc,Mn,mc,ge,Sr}from"./chunk-gp9tkznp.js";import{J}from"./chunk-ct72f70x.js";import{lg,fc,Ce,hc,Un,ug,Ac,gg,pg,uh,Hn,Hs,Gn,Vn,qn,Y,Fe,x,vr,zn,Tr,pe,Ic,Kn,bc,Rr,Jn,Gs,Xn,Yn,Zn,ei,Dr,wc,Ue,Z,Qe,He,dt,Te,Pr,we,ni,ii,si,oi,ai,ci,di,Nr,O,js,Fg,xc,ui,gi,pi,mi,Uc,zs,Qc,Gt,fi,Ks,Ws,Hc,hi,Gc}from"./chunk-a102vqez.js";import{Nl,Fo,zi,Ki,Uo,kl,Bl,Wi,Qo,Ho,Ol,_l,Go}from"./chunk-d02jxsxv.js";import{Wa,vn,Tn,hs,As,ys,Ss,Ja,Xa}from"./chunk-j5x0qn7z.js";import{Ya}from"./chunk-96vc5w8w.js";import{lc,Le,S}from"./chunk-3s8dtcz8.js";import{$e}from"./chunk-varjr6np.js";import{I}from"./chunk-97gre81w.js";import{ee,Ai,Js,Vc,yi,Jg}from"./chunk-e4pxs9g6.js";import{Br,Re}from"./chunk-fwcf0n8f.js";import{h}from"./chunk-9e4afej1.js";import{Nd,Kr,kd,Bd,xd,$i,Vp,Wr}from"./chunk-0evxayn1.js";import{aS,Xe}from"./chunk-9mv07nz0.js";import{createHmac as $u,createSign as yg,timingSafeEqual as Cg}from"node:crypto";function bs(l){let f=l instanceof Date?l.getTime():l;if(!Number.isFinite(f))throw TypeError("Media access timestamp must be finite");return Math.floor(f/1000)}function ku(l){return Buffer.from(l).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function Sg(l){return Buffer.from(l).toString("base64url")}function Ou(l,f=!1){if(!l||/[\r\n]/.test(l))throw TypeError("Media resource is invalid");let C=f?l.replaceAll("*","wildcard"):l,A=new URL(C);if(!["http:","https:"].includes(A.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!f&&l.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function xu(l,f){let C=yg("RSA-SHA1");return C.update(l),C.end(),ku(C.sign(f))}function Bu(l){Ou(l.resource,!0);let C={DateLessThan:{"AWS:EpochTime":bs(l.expiresAt)}};if(l.activeAt!==void 0)C.DateGreaterThan={"AWS:EpochTime":bs(l.activeAt)};if(l.ipAddress)C.IpAddress={"AWS:SourceIp":l.ipAddress};return JSON.stringify({Statement:[{Resource:l.resource,Condition:C}]})}function cS(l,f,C){Ou(l);let A=bs(f),w=l.includes("?")?"&":"?",ce=Bu({resource:l,expiresAt:f}),v=xu(ce,C.privateKey);return`${l}${w}Expires=${A}&Signature=${encodeURIComponent(v)}&Key-Pair-Id=${encodeURIComponent(C.keyPairId)}`}function dS(l,f){let C=Bu(l);return{"CloudFront-Key-Pair-Id":f.keyPairId,"CloudFront-Policy":ku(Buffer.from(C)),"CloudFront-Signature":xu(C,f.privateKey)}}function CS(l){if(!l.resource||/[\r\n]/.test(l.resource))throw TypeError("Media resource is invalid");let f=Sg(Buffer.from(JSON.stringify({resource:l.resource,expiresAt:bs(l.expiresAt),...l.keyId?{keyId:l.keyId}:{},...l.audience?{audience:l.audience}:{}}))),C=$u("sha256",l.secret).update(f).digest("base64url");return`${f}.${C}`}function RS(l,f){let[C,A,w]=l.split(".");if(!C||!A||w)return null;let ce=$u("sha256",f.secret).update(C).digest(),v;try{v=Buffer.from(A,"base64url")}catch{return null}if(ce.length!==v.length||!Cg(ce,v))return null;try{let B=JSON.parse(Buffer.from(C,"base64url").toString("utf8")),de=bs(f.now??Date.now());if(!B.resource||!Number.isSafeInteger(B.expiresAt)||B.expiresAt<=de)return null;if(f.resource&&B.resource!==f.resource)return null;if(f.audience&&B.audience!==f.audience)return null;return B}catch{return null}}function bS(l,f=!1){let C=new URL(l,"https://media.invalid").pathname.toLowerCase(),A=/\.(?:m3u8|mpd|vtt|json)$/.test(C),w=/\.(?:key|license)$/.test(C)||C.includes("/keys/")||C.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":f&&(A||w)?"private, no-store":A?"public, max-age=5, s-maxage=30, stale-while-revalidate=30":"public, max-age=31536000, immutable","Cross-Origin-Resource-Policy":"cross-origin","X-Content-Type-Options":"nosniff"}}function TS(l){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(l.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(l.region))throw TypeError("Media bucket region is invalid");let f=l.prefix?`/${l.prefix.replace(/^\/+|\/+$/g,"")}`:"",C=l.protected??!1,A="public, max-age=31536000, immutable",w=C?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${l.bucket}.s3.${l.region}.amazonaws.com`,originPath:f,domain:l.domain,trustedKeyGroupIds:[...new Set(l.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:w,compress:!0,signed:C},{pathPattern:"*.mpd",cacheControl:w,compress:!0,signed:C},{pathPattern:"*.vtt",cacheControl:w,compress:!0,signed:C},{pathPattern:"*",cacheControl:A,compress:!1,signed:C}],responseHeaders:{"Access-Control-Allow-Headers":"Range, If-Range","Access-Control-Allow-Methods":"GET, HEAD, OPTIONS","Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":"Accept-Ranges, Content-Length, Content-Range, ETag","X-Content-Type-Options":"nosniff"}}}class Rg{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(l){this.config=l.config,this.environment=l.environment,this.builder=new Qd(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let f=this.config.environments[this.environment]?.infrastructure;if(!f)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...f,compute:{...this.config.infrastructure?.compute,...f.compute},storage:{...this.config.infrastructure?.storage,...f.storage},functions:{...this.config.infrastructure?.functions,...f.functions},servers:{...this.config.infrastructure?.servers,...f.servers},databases:{...this.config.infrastructure?.databases,...f.databases},cdn:{...this.config.infrastructure?.cdn,...f.cdn},sftp:f.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...f.queues},redirects:{...this.config.infrastructure?.redirects,...f.redirects},realtime:{...this.config.infrastructure?.realtime,...f.realtime},cache:{...this.config.infrastructure?.cache,...f.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...f.fileSystem},email:{...this.config.infrastructure?.email,...f.email},search:{...this.config.infrastructure?.search,...f.search},ai:{...this.config.infrastructure?.ai,...f.ai}}}}shouldDeploy(l){if(l.environments&&!l.environments.includes(this.environment))return!1;if(l.requiresFeatures){let f=this.config.features||{};if(!l.requiresFeatures.every((A)=>f[A]===!0))return!1}if(l.regions){let f=this.config.environments[this.environment]?.region||this.config.project.region;if(!l.regions.includes(f))return!1}if(l.condition&&typeof l.condition==="function")return l.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let l=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,f=Number(l||3008);return Number.isFinite(f)&&f>0?f:3008}defaultComputeCachePathPatterns(){return["/api/*","/auth/*","/publisher/api/*","/publisher/*","/publish","/publish/*","/analytics/*","/packages/*","/npm/*","/zig/*","/php/*","/commits/*","/health","/dashboard/*","/search","/login","/logout","/signup","/account","/account/*"]}shouldRouteStorageBucketToCompute(l,f){return l==="public"||f.routeCompute===!0}storageBucketName(l,f,C){return this.mergedConfig.infrastructure?.storage?.[C]?.bucket??`${l}-${f}-${C}`}fileSystemLogicalId(l,f,C){return t(r({slug:`${l}-${C}`,environment:f,resourceType:"efs"}))}resolveSftpStorage(l,f,C){let A=l.storage;if(A?.type==="efs"&&A.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[A.fileSystem])throw Error(`sftp: storage.fileSystem "${A.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(f,C,A.fileSystem)},posixProfile:A.posixProfile}}if(A?.type==="s3"&&A.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[A.storageBucket])throw Error(`sftp: storage.storageBucket "${A.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(f,C,A.storageBucket)}}return}resolveComputeCachePathPatterns(l){if(l&&l.length>0)return l;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(l,f){return{PathPattern:l,TargetOriginId:f,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",OriginRequestPolicyId:"b689b0a8-53d0-40ab-baf2-68738e2966ac"}}appendComputeAppOrigin(l,f,C,A,w,ce){let v=this.serverEipLogicalIds.get("app"),B=this.serverEipLogicalIds.get("appInstance");if(!v)return;let de=`EC2-${A}-${w}-api`,ct=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",xe=ct==="us-east-1"?".compute-1.amazonaws.com":`.${ct}.compute.amazonaws.com`,Ht={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:v}]}]},xe]]},Ut=this.resolveApiOriginPort();if(l.push({Id:de,DomainName:Ht,CustomOriginConfig:{HTTPPort:Ut,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),C.push(v),B)C.push(B);for(let ut of ce)f.push(this.createComputeCacheBehavior(ut,de))}buildCaddyfile(l){let f=l.filter(([,w])=>typeof w.domain==="string"&&w.domain&&typeof w.port==="number");if(f.length===0)return;let C=new Map;for(let[,w]of f){let ce=C.get(w.domain)??[];ce.push({port:w.port,path:w.path}),C.set(w.domain,ce)}let A=[];for(let[w,ce]of C){let B=[...ce].sort((de,ct)=>{let xe=!de.path||de.path==="/",Ht=!ct.path||ct.path==="/";if(xe&&!Ht)return 1;if(!xe&&Ht)return-1;return(ct.path?.length??0)-(de.path?.length??0)}).map((de)=>{let ct=!de.path||de.path==="/",xe=`reverse_proxy localhost:${de.port}`;return ct?` handle {
|
|
1
|
+
import{dI,lI,Od,qp,_d,Ld,Jr,L,d,$d,jp,Q,Md,g,NA,Mi,Fd,Ud,fe,Qd,kA,r,t,uI,gI,p,pI,mI,fI,hI,yI,Xt,Hd,Fi,BA,SI,II,De,je,Gd,zp,Kp,bI,Wp,Jp,Xp,Eo,Vd,re,Xr,yt,vo,St,he,xA,qd,To,Yp,Zp,em,tm,jd,CI,H,b,OA,_A,rm,a,y,ze,m,nm,Ke,G,It,EI,im,V,zd,Pe,Yt,wo,ne,Kd,ie,LA,Ro,q,j,k,Ui,T,Zt,bt,z,e,Yr,vI,sm,Wd,TI,wI,RI,DI,Jd,PI,NI,kI,BI,xI,OI,_I,LI,$I,MI,FI,UI,$A,MA,FA,UA,QA,HA,GA,er,om,am,Zr,Qi,QI,cm,HI,GI,en,VI,qI,jI,zI,KI,WI,VA,qA,jA,zA,KA,Hi,JI,Do,WA,dm,F,JA,We,Po,Ct,XA,lm,YA,ZA,ey,um,U,XI,YI,ZI,eb,ty,tb,K,rb,nb,ib,Xd,Yd,ry,gm,pm,sb,ob,ab,cb,db,ny,Zd,lb,ub,gb,pb,mb,iy,sy,fb,hb,Ab,yb,Sb,Ib,bb,oy,Cb,mm,el,Eb,vb,Tb,wb,fm,hm,Am,Rb,tl,ay,cy,dy,ly,rl,uy,Db,Pb,Nb,kb,Bb,xb,Ob,gy,py,my,fy,ym,_b,Lb,$b,Mb,Fb,Ub,Qb,Hb,Gb,hy,Ay,yy,Sy,Vb,qb,Sm,jb,Im,bm,Cm,Em,zb,Kb,Wb,Jb,Ne,Gi,Xb,Yb,Zb,eC,tC,rC,nC,iC,Iy,sC,oC,vm,Tm,aC,cC,by,dC,lC,uC,gC,pC,mC,fC,hC,AC,yC,SC,IC,bC,CC,EC,vC,TC,wC,RC,DC,PC,nl,Cy,il,Ey,sl,vy,ol,Ty,al,wy,tr,Ry,cl,Dy,Vi,Py,dl,Ny,ll,ky,wm,NC,Rm,kC,ul,By,rr,xy,Dm,BC,gl,Oy,Pm,xC,Nm,OC,km,_C,pl,_y,Bm,LC,xm,$C,Om,MC,_m,FC,ml,Ly,fl,$y,Lm,UC,$m,QC,Mm,HC,Fm,GC,Um,VC,Qm,qC,hl,My,Hm,jC,Gm,zC,Vm,KC,qm,WC,jm,JC,zm,XC,Km,Wm,Jm,Xm,Ym,YC,Zm,ZC,ef,eE,tf,tE,Je,rf,Fy,No,Al,tn,Uy,qi,nr,yl,Sl,Qy,Hy,Il,nf,bl,sf,rE,nE,ko,Bo,xo,Cl,rn,El,vl,ji,Oo,_o,of,Gy,Vy,qy,iE,af,cf,sE,jy,df,zy,Ky,Wy,oE,lf,nn,Tl,uf,aE,Jy,Lo,$o,wl,gf,cE,Rl,Xy,pf,dE,mf,lE,ff,uE}from"./chunk-c5jyzyqw.js";import{Dl,R,Pl,Mo,Yy,hf,Zy,eS,tS,rS,nS,iS,sS,oS}from"./chunk-x2pxtfk0.js";import{Vo,Af,Ll,lS,Ji,$l,qo,yf,Sf,on,jo,Ml,Ye,Fl,Ul,Ql,Xi,an,If,Ze,Hl,zo,Ko,Wo,Gl,Vl,ql,Yi,Jo,jl,cn,Zi,Xo,Et,bf,zl,Kl,Cf,Wl,Yo,ir,Jl,Xl,Yl,Zl,et,Ef,eu,sr,Zo,ea,ta,es,ts,dn,tu,rs,ra,na,ln,ru,un,vf,Tf,vt,gn,ia,wf,nu,iu,sa,su,ou,au,uS,se,cu,gS,pS,ns,is,mS,Ae,Rf,Tt,ke,Be,wt,du,lu,uu,gu,Df,Pf,oa,Nf,kf,aa,pu,mu,Bf,oe,xf,fu,ye,ca,tt,Rt,Dt,pn,ss,hu,fS,da,Of,_f,Lf,$f,la,ua,Au,mn,ga,yu,os,Su,pa,ma,fa,ha,Aa,ya,Sa,Ia,Iu,or,ba,bu,fn,Cu,Ca,Ea,Eu,ar,va,Ta,Mf,hS,as,AS,yS,SS,wa,Ra,vu,Ff,Da,hn,Tu,cs,wu,Ru,Du,Pa,Uf,Na,Pu,Qf,ka,Hf,An,yn,Nu,ds,Lu,Uu,Qu,Hu,Gu,Vu,us,cr,xa,Sn,In,dr,rt,Jf,_a,Xf,Yf,zu,La,ps,Ku,$a,Nt,Oe,Wu,Ma,Fa,Ju,Ua,Qa,Ha,Ga,Xu,Yu,Cn,Va,qa,ja,za,Zu,ms,En,fs,Ka}from"./chunk-294kdscm.js";import{_,Lr,Wc,Xs,u,Sp,Ip}from"./chunk-hm6pwhne.js";import{pt,Kc,bi,Ci,Ei,yp}from"./chunk-1w9v8g26.js";import{Nh,kh,Bh,Zg,ep,tp,xh,rp,np,Oh,_h,ip,Lh,$h,jc,sp,Mh,Fh,op,Uh,Qh,Hh,Gh,Vh,qh,jh,Ii,zc,ap,cp,dp,lp,up,gp,pp,mp,fp,hp,Ap,zh,Kh,Wh,Jh,Xh,Yh,Zh}from"./chunk-vkrgf3sv.js";import{Ge,Jc,me,Vt,Xc,P,qt,mt,Yc,Ys,rA,bp,Zc,s,vi,Zs,$r,ed,td,Mr,nA,rd,sI,oI,eo,aI,cI,nd,id,Ti,to,te,c,ro,Ve,Fr,iA,sA,sd,jt,oA,no,aA,cA,io,od,Ur,so,dA,ad,Cp,zt,Qr,lA,oo,uA,N,gA,cd,Ep,ao,pA,mA,fA,dd,wi,co,ld,Kt,ft,hA,Hr,AA,ud,vp,Tp,lo,gd,pd,ht,wp,Ri,md,uo,Gr,Rp,Di,fd,hd,Pi,Dp,Ad,yd,Sd,Id,go,Pp,Np,yA,kp,bd,Ni,Bp,xp,po,Vr,mo,fo,ho,Cd,Op,Ed,Ao,SA,Wt,IA,vd,qr,Td,bA,wd,_p,ki,jr,yo,Bi,qe,CA,Lp,$p,Jt,Rd,Dd,Pd,xi,Oi,_i,EA,vA,At,So,TA,zr,Mp,Io,wA,Fp,Up,Qp,RA,Hp,Gp,DA,i,PA,Li,bo,Co}from"./chunk-v3w791ze.js";import{n}from"./chunk-cgcthvq9.js";import{be,ot,On}from"./chunk-w78e5n94.js";import{o}from"./chunk-bwtxb2hf.js";import{Se,Cs,Es,rg,Za,ec,vs,tc,nt,W,it,ae,E,Ie,Rn,rc,_e,nc,Dn,Pn,Nn,kt,Bt,xt,kn,ur,ic,gr,pr,st,Bn,oc,Ot,mr,xn,cc,ag,cg,dc,fr}from"./chunk-8jsf214f.js";import{at,le,Me,dg,_t,uc,gc,Lt,M,_n,$t,Mt,Ln,Ds,Ps,hr,Ar,$n,yr,Ns,ks,Bs,xs,X,Os,_s,Ls,$s,ue,Ms,Fs,Us,D,pc,Mn,mc,ge,Sr}from"./chunk-gp9tkznp.js";import{J}from"./chunk-ct72f70x.js";import{lg,fc,Ce,hc,Un,ug,Ac,gg,pg,uh,Hn,Hs,Gn,Vn,qn,Y,Fe,x,vr,zn,Tr,pe,Ic,Kn,bc,Rr,Jn,Gs,Xn,Yn,Zn,ei,Dr,wc,Ue,Z,Qe,He,dt,Te,Pr,we,ni,ii,si,oi,ai,ci,di,Nr,O,js,Fg,xc,ui,gi,pi,mi,Uc,zs,Qc,Gt,fi,Ks,Ws,Hc,hi,Gc}from"./chunk-vv5fmmhr.js";import{Nl,Fo,zi,Ki,Uo,kl,Bl,Wi,Qo,Ho,Ol,_l,Go}from"./chunk-d02jxsxv.js";import{Wa,vn,Tn,hs,As,ys,Ss,Ja,Xa}from"./chunk-j5x0qn7z.js";import{Ya}from"./chunk-96vc5w8w.js";import{lc,Le,S}from"./chunk-3s8dtcz8.js";import{$e}from"./chunk-varjr6np.js";import{I}from"./chunk-97gre81w.js";import{ee,Ai,Js,Vc,yi,Jg}from"./chunk-e4pxs9g6.js";import{Br,Re}from"./chunk-fwcf0n8f.js";import{h}from"./chunk-9e4afej1.js";import{Nd,Kr,kd,Bd,xd,$i,Vp,Wr}from"./chunk-0evxayn1.js";import{aS,Xe}from"./chunk-9mv07nz0.js";var $S="https://api.machines.dev/v1";class sc extends Error{status;path;constructor(l,f,C){super(l);this.status=f;this.path=C;this.name="FlyApiError"}}function Ou(l){let f=l.ip.includes(":");if(f&&l.ip.startsWith("fdaa:"))return"private_v6";if(l.shared)return"shared_v4";return f?"v6":"v4"}class Dg{token;fetch;constructor(l){if(!l.token)throw Error("Fly.io needs an API token: set FLY_API_TOKEN (`fly tokens create deploy` makes one scoped to an app).");this.token=l.token,this.fetch=l.fetch??fetch}async rest(l,f,C={}){let A=new URL(`https://api.machines.dev/v1${f}`);for(let[ce,de]of Object.entries(C.query??{}))A.searchParams.set(ce,de);let w=await this.fetch(A,{method:l,headers:{Authorization:`Bearer ${this.token}`,...C.body!==void 0?{"Content-Type":"application/json"}:{},...C.headers},body:C.body===void 0?void 0:JSON.stringify(C.body)});if(w.status===404&&C.notFound==="null")return null;let B=await w.text(),v=B?kg(B):void 0;if(!w.ok){let ce=typeof v==="object"&&v&&"error"in v?String(v.error):B||w.statusText;throw new sc(`Fly.io ${l} ${f} failed (${w.status}): ${ce}`,w.status,f)}return v}getApp(l){return this.rest("GET",`/apps/${encodeURIComponent(l)}`,{notFound:"null"})}createApp(l,f){return this.rest("POST","/apps",{body:{app_name:l,org_slug:f}})}async listMachines(l){return await this.rest("GET",`/apps/${encodeURIComponent(l)}/machines`)??[]}createMachine(l,f){return this.rest("POST",`/apps/${encodeURIComponent(l)}/machines`,{body:f})}updateMachine(l,f,C,A){return this.rest("POST",`/apps/${encodeURIComponent(l)}/machines/${encodeURIComponent(f)}`,{body:C,headers:{"fly-machine-lease-nonce":A}})}async acquireLease(l,f,C=120){let w=(await this.rest("POST",`/apps/${encodeURIComponent(l)}/machines/${encodeURIComponent(f)}/lease`,{body:{ttl:C}})).data?.nonce;if(!w)throw new sc(`Fly.io gave no lease nonce for Machine ${f}`,200,`/machines/${f}/lease`);return w}async releaseLease(l,f,C){await this.rest("DELETE",`/apps/${encodeURIComponent(l)}/machines/${encodeURIComponent(f)}/lease`,{headers:{"fly-machine-lease-nonce":C}})}async waitForState(l,f,C,A={}){await this.rest("GET",`/apps/${encodeURIComponent(l)}/machines/${encodeURIComponent(f)}/wait`,{query:{state:C,timeout:String(A.timeoutSeconds??60),...A.instanceId?{instance_id:A.instanceId}:{}}})}async listVolumes(l){return await this.rest("GET",`/apps/${encodeURIComponent(l)}/volumes`)??[]}createVolume(l,f){return this.rest("POST",`/apps/${encodeURIComponent(l)}/volumes`,{body:{...f,encrypted:!0}})}async setSecrets(l,f){return(await this.rest("POST",`/apps/${encodeURIComponent(l)}/secrets`,{body:{values:f}})).version}async listIpAssignments(l){return(await this.rest("GET",`/apps/${encodeURIComponent(l)}/ip_assignments`)).ips??[]}async assignIp(l,f){let C=await this.rest("POST",`/apps/${encodeURIComponent(l)}/ip_assignments`,{body:{type:f}});if(!C.ip)throw new sc(`Fly.io assigned no ${f} address to ${l}`,200,`/apps/${l}/ip_assignments`);return{ip:C.ip,shared:C.shared??f==="shared_v4",region:C.region}}async requestCertificate(l,f){return this.rest("POST",`/apps/${encodeURIComponent(l)}/certificates/acme`,{body:{hostname:f}})}}function kg(l){try{return JSON.parse(l)}catch{return}}var Ec="ts-cloud-role";function DS(l,f){let C=l.fly??{},A=C.app??`${l.project.slug}-${f.environment}`;if(!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/.test(A))throw Error(`"${A}" is not a valid Fly app name: lowercase letters, digits and dashes, 3 to 63 characters.`);let w=C.internalPort??3000,B=C.count??1;if(!Number.isInteger(B)||B<1)throw Error(`fly.count must be a whole number of at least 1, got ${B}.`);return{app:A,org:C.org??"personal",image:f.image,regions:C.regions?.length?C.regions:["iad"],count:B,internalPort:w,healthPath:C.healthPath??"/",vm:{cpuKind:C.vm?.cpuKind??"shared",cpus:C.vm?.cpus??1,memoryMb:C.vm?.memoryMb??512},...C.volume?{volume:{name:C.volume.name??"data",sizeGb:C.volume.sizeGb,path:C.volume.path}}:{},autoStop:C.autoStop??!1,env:{...f.env,PORT:String(w)},secrets:f.secrets??{},hostnames:C.hostnames??[],release:f.release}}function vg(l){return{image:l.image,env:l.env,guest:{cpu_kind:l.vm.cpuKind,cpus:l.vm.cpus,memory_mb:l.vm.memoryMb},services:[{protocol:"tcp",internal_port:l.internalPort,ports:[{port:80,handlers:["http"],force_https:!0},{port:443,handlers:["tls","http"]}],autostop:l.autoStop?"stop":"off",autostart:!0,...l.autoStop?{min_machines_running:0}:{},checks:[{type:"http",method:"GET",path:l.healthPath,interval:"15s",timeout:"5s",grace_period:"10s"}]}],restart:{policy:"on-failure",max_retries:10},metadata:{[Ec]:"app","ts-cloud-release":l.release}}}async function kS(l,f,C=()=>{}){let A=!1;if(!await l.getApp(f.app))C(`Creating Fly app ${f.app} in ${f.org}`),await l.createApp(f.app,f.org),A=!0;let w;if(Object.keys(f.secrets).length>0)w=await l.setSecrets(f.app,f.secrets),C(`Set ${Object.keys(f.secrets).length} secret(s) (version ${w})`);let B=await l.listIpAssignments(f.app),v=new Set(B.map(Ou));if(!v.has("v6"))B.push(await l.assignIp(f.app,"v6")),C("Assigned a dedicated IPv6");if(!v.has("v4")&&!v.has("shared_v4"))B.push(await l.assignIp(f.app,"shared_v4")),C("Assigned a shared IPv4");let ce=vg(f),de=(await l.listMachines(f.app)).filter((lt)=>{let ut=lt.config?.metadata??{};if(ut[Ec])return ut[Ec]==="app";return!ut.fly_process_group||ut.fly_process_group==="app"}),ct=f.volume?await l.listVolumes(f.app):[],xe=[],Ut=[],Qt=new Set;for(let lt of f.regions){let ut=de.filter((Ee)=>Ee.region===lt).sort((Ee,Ft)=>Ee.id.localeCompare(Ft.id));for(let Ee=0;Ee<f.count;Ee++){let Ft=ut[Ee];if(Ft){Qt.add(Ft.id),await Eg(l,f.app,Ft,ce,w),Ut.push(Ft.id),C(`Updated ${Ft.id} (${lt}) to ${f.image}`);continue}let ve=f.volume?[{volume:(await Og(l,f,lt,ct)).id,path:f.volume.path}]:void 0,Pt=await l.createMachine(f.app,{region:lt,name:`${f.app}-${lt}-${Ee+1}`,config:{...ce,...ve?{mounts:ve}:{}},...w!==void 0?{min_secrets_version:w}:{}});await l.waitForState(f.app,Pt.id,"started",{instanceId:Pt.instance_id}),xe.push(Pt.id),C(`Created ${Pt.id} in ${lt}`)}}let gt=[];for(let lt of f.hostnames)gt.push(await l.requestCertificate(f.app,lt));return{app:f.app,url:`https://${f.app}.fly.dev`,createdApp:A,created:xe,updated:Ut,untouched:de.filter((lt)=>!Qt.has(lt.id)).map((lt)=>lt.id),ips:B,certificates:gt}}async function Eg(l,f,C,A,w){let B=await l.acquireLease(f,C.id);try{let v=await l.updateMachine(f,C.id,{config:{...A,...C.config?.mounts?.length?{mounts:C.config.mounts}:{}},...w!==void 0?{min_secrets_version:w}:{}},B);await l.waitForState(f,C.id,"started",{instanceId:v.instance_id})}finally{await l.releaseLease(f,C.id,B)}}async function Og(l,f,C,A){let w=A.find((v)=>v.region===C&&v.name===f.volume.name&&!v.attached_machine_id);if(w)return w.attached_machine_id="pending",w;let B=await l.createVolume(f.app,{name:f.volume.name,region:C,size_gb:f.volume.sizeGb});return A.push({...B,attached_machine_id:"pending"}),B}import{createHmac as xu,createSign as Ng,timingSafeEqual as xg}from"node:crypto";function bs(l){let f=l instanceof Date?l.getTime():l;if(!Number.isFinite(f))throw TypeError("Media access timestamp must be finite");return Math.floor(f/1000)}function Fu(l){return Buffer.from(l).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function Lg(l){return Buffer.from(l).toString("base64url")}function _u(l,f=!1){if(!l||/[\r\n]/.test(l))throw TypeError("Media resource is invalid");let C=f?l.replaceAll("*","wildcard"):l,A=new URL(C);if(!["http:","https:"].includes(A.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!f&&l.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function Mu(l,f){let C=Ng("RSA-SHA1");return C.update(l),C.end(),Fu(C.sign(f))}function Bu(l){_u(l.resource,!0);let C={DateLessThan:{"AWS:EpochTime":bs(l.expiresAt)}};if(l.activeAt!==void 0)C.DateGreaterThan={"AWS:EpochTime":bs(l.activeAt)};if(l.ipAddress)C.IpAddress={"AWS:SourceIp":l.ipAddress};return JSON.stringify({Statement:[{Resource:l.resource,Condition:C}]})}function LS(l,f,C){_u(l);let A=bs(f),w=l.includes("?")?"&":"?",B=Bu({resource:l,expiresAt:f}),v=Mu(B,C.privateKey);return`${l}${w}Expires=${A}&Signature=${encodeURIComponent(v)}&Key-Pair-Id=${encodeURIComponent(C.keyPairId)}`}function FS(l,f){let C=Bu(l);return{"CloudFront-Key-Pair-Id":f.keyPairId,"CloudFront-Policy":Fu(Buffer.from(C)),"CloudFront-Signature":Mu(C,f.privateKey)}}function _S(l){if(!l.resource||/[\r\n]/.test(l.resource))throw TypeError("Media resource is invalid");let f=Lg(Buffer.from(JSON.stringify({resource:l.resource,expiresAt:bs(l.expiresAt),...l.keyId?{keyId:l.keyId}:{},...l.audience?{audience:l.audience}:{}}))),C=xu("sha256",l.secret).update(f).digest("base64url");return`${f}.${C}`}function MS(l,f){let[C,A,w]=l.split(".");if(!C||!A||w)return null;let B=xu("sha256",f.secret).update(C).digest(),v;try{v=Buffer.from(A,"base64url")}catch{return null}if(B.length!==v.length||!xg(B,v))return null;try{let ce=JSON.parse(Buffer.from(C,"base64url").toString("utf8")),de=bs(f.now??Date.now());if(!ce.resource||!Number.isSafeInteger(ce.expiresAt)||ce.expiresAt<=de)return null;if(f.resource&&ce.resource!==f.resource)return null;if(f.audience&&ce.audience!==f.audience)return null;return ce}catch{return null}}function BS(l,f=!1){let C=new URL(l,"https://media.invalid").pathname.toLowerCase(),A=/\.(?:m3u8|mpd|vtt|json)$/.test(C),w=/\.(?:key|license)$/.test(C)||C.includes("/keys/")||C.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":f&&(A||w)?"private, no-store":A?"public, max-age=5, s-maxage=30, stale-while-revalidate=30":"public, max-age=31536000, immutable","Cross-Origin-Resource-Policy":"cross-origin","X-Content-Type-Options":"nosniff"}}function WS(l){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(l.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(l.region))throw TypeError("Media bucket region is invalid");let f=l.prefix?`/${l.prefix.replace(/^\/+|\/+$/g,"")}`:"",C=l.protected??!1,A="public, max-age=31536000, immutable",w=C?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${l.bucket}.s3.${l.region}.amazonaws.com`,originPath:f,domain:l.domain,trustedKeyGroupIds:[...new Set(l.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:w,compress:!0,signed:C},{pathPattern:"*.mpd",cacheControl:w,compress:!0,signed:C},{pathPattern:"*.vtt",cacheControl:w,compress:!0,signed:C},{pathPattern:"*",cacheControl:A,compress:!1,signed:C}],responseHeaders:{"Access-Control-Allow-Headers":"Range, If-Range","Access-Control-Allow-Methods":"GET, HEAD, OPTIONS","Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":"Accept-Ranges, Content-Length, Content-Range, ETag","X-Content-Type-Options":"nosniff"}}}class _g{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(l){this.config=l.config,this.environment=l.environment,this.builder=new Qd(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let f=this.config.environments[this.environment]?.infrastructure;if(!f)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...f,compute:{...this.config.infrastructure?.compute,...f.compute},storage:{...this.config.infrastructure?.storage,...f.storage},functions:{...this.config.infrastructure?.functions,...f.functions},servers:{...this.config.infrastructure?.servers,...f.servers},databases:{...this.config.infrastructure?.databases,...f.databases},cdn:{...this.config.infrastructure?.cdn,...f.cdn},sftp:f.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...f.queues},redirects:{...this.config.infrastructure?.redirects,...f.redirects},realtime:{...this.config.infrastructure?.realtime,...f.realtime},cache:{...this.config.infrastructure?.cache,...f.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...f.fileSystem},email:{...this.config.infrastructure?.email,...f.email},search:{...this.config.infrastructure?.search,...f.search},ai:{...this.config.infrastructure?.ai,...f.ai}}}}shouldDeploy(l){if(l.environments&&!l.environments.includes(this.environment))return!1;if(l.requiresFeatures){let f=this.config.features||{};if(!l.requiresFeatures.every((A)=>f[A]===!0))return!1}if(l.regions){let f=this.config.environments[this.environment]?.region||this.config.project.region;if(!l.regions.includes(f))return!1}if(l.condition&&typeof l.condition==="function")return l.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let l=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,f=Number(l||3008);return Number.isFinite(f)&&f>0?f:3008}defaultComputeCachePathPatterns(){return["/api/*","/auth/*","/publisher/api/*","/publisher/*","/publish","/publish/*","/analytics/*","/packages/*","/npm/*","/zig/*","/php/*","/commits/*","/health","/dashboard/*","/search","/login","/logout","/signup","/account","/account/*"]}shouldRouteStorageBucketToCompute(l,f){return l==="public"||f.routeCompute===!0}storageBucketName(l,f,C){return this.mergedConfig.infrastructure?.storage?.[C]?.bucket??`${l}-${f}-${C}`}fileSystemLogicalId(l,f,C){return t(r({slug:`${l}-${C}`,environment:f,resourceType:"efs"}))}resolveSftpStorage(l,f,C){let A=l.storage;if(A?.type==="efs"&&A.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[A.fileSystem])throw Error(`sftp: storage.fileSystem "${A.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(f,C,A.fileSystem)},posixProfile:A.posixProfile}}if(A?.type==="s3"&&A.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[A.storageBucket])throw Error(`sftp: storage.storageBucket "${A.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(f,C,A.storageBucket)}}return}resolveComputeCachePathPatterns(l){if(l&&l.length>0)return l;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(l,f){return{PathPattern:l,TargetOriginId:f,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",OriginRequestPolicyId:"b689b0a8-53d0-40ab-baf2-68738e2966ac"}}appendComputeAppOrigin(l,f,C,A,w,B){let v=this.serverEipLogicalIds.get("app"),ce=this.serverEipLogicalIds.get("appInstance");if(!v)return;let de=`EC2-${A}-${w}-api`,ct=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",xe=ct==="us-east-1"?".compute-1.amazonaws.com":`.${ct}.compute.amazonaws.com`,Ut={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:v}]}]},xe]]},Qt=this.resolveApiOriginPort();if(l.push({Id:de,DomainName:Ut,CustomOriginConfig:{HTTPPort:Qt,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),C.push(v),ce)C.push(ce);for(let gt of B)f.push(this.createComputeCacheBehavior(gt,de))}buildCaddyfile(l){let f=l.filter(([,w])=>typeof w.domain==="string"&&w.domain&&typeof w.port==="number");if(f.length===0)return;let C=new Map;for(let[,w]of f){let B=C.get(w.domain)??[];B.push({port:w.port,path:w.path}),C.set(w.domain,B)}let A=[];for(let[w,B]of C){let ce=[...B].sort((de,ct)=>{let xe=!de.path||de.path==="/",Ut=!ct.path||ct.path==="/";if(xe&&!Ut)return 1;if(!xe&&Ut)return-1;return(ct.path?.length??0)-(de.path?.length??0)}).map((de)=>{let ct=!de.path||de.path==="/",xe=`reverse_proxy localhost:${de.port}`;return ct?` handle {
|
|
2
2
|
${xe}
|
|
3
3
|
}`:` handle ${de.path} {
|
|
4
4
|
${xe}
|
|
5
5
|
}`});A.push(`${w} {
|
|
6
|
-
${
|
|
6
|
+
${ce.join(`
|
|
7
7
|
`)}
|
|
8
8
|
}`)}return A.join(`
|
|
9
9
|
|
|
10
|
-
`)}normalizeMountPath(l){let f=l?.mountPath||l?.path;if(!f||f==="/")return;let C=`/${f}`.replace(/\/+/g,"/").replace(/\/$/,"");return C==="/"?void 0:C}storageBucketLogicalId(l,f,C){return`${l}-${f}-s3-${C}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((A)=>A.charAt(0).toUpperCase()+A.slice(1)).join("")}pathMountRewriteFunctionCode(l,f="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(l)}; var rewriteStyle = ${JSON.stringify(f)}; var uri = request.uri; if (uri === prefix) { uri = '/'; } else if (uri.indexOf(prefix + '/') === 0) { uri = uri.substring(prefix.length); } if (uri === '' || uri === '/') { request.uri = '/index.html'; return request; } if (uri.endsWith('/')) { request.uri = uri + 'index.html'; return request; } var lastSegment = uri.substring(uri.lastIndexOf('/') + 1); if (lastSegment.indexOf('.') === -1) { request.uri = rewriteStyle === 'flat' ? uri + '.html' : uri + '/index.html'; return request; } request.uri = uri; return request; }`}generate(){let l=this.mergedConfig.project.slug,f=this.environment,C=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),A=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),w=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(l,f),this.generateContainerInfrastructure(l,f);if(C)this.generateServerless(l,f);if(A)this.generateServer(l,f);if(w)this.generateComputeApp(l,f);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(l,f);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(l,f),this.storageFailoverReplicas.length>0)this.builder.addMetadata(qd,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(l){}generateNetworkInfrastructure(l,f){if(this.builder.hasResource("VPC"))return;let A=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:w,logicalId:ce}=y.createVpc({slug:l,environment:f,cidr:A,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",w);let v=`${l}${f}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(v,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${l}-${f}-igw`},{Key:"Environment",Value:f}]}});let B=`${l}${f}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(B,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:v}}});let de=`${l}${f}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(de,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${l}-${f}-public-rt`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${l}${f}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:de},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:v}},DependsOn:B});let ct=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",xe=["a","b"];for(let Ht=0;Ht<2;Ht++){let Ut=`PublicSubnet${Ht+1}`;this.builder.addResource(Ut,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${Ht}.0/24`,AvailabilityZone:`${ct}${xe[Ht]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${l}-${f}-public-${xe[Ht]}`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${Ut}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:Ut},RouteTableId:{Ref:de}}})}}generateContainerInfrastructure(l,f){let C=this.mergedConfig.infrastructure?.containers;if(!C)return;let A=this.mergedConfig.infrastructure?.loadBalancer,w=this.mergedConfig.infrastructure?.ssl,ce=this.mergedConfig.infrastructure?.dns,v;if(w?.enabled&&w.domains?.length)if(w.certificateArn);else{let xe=w.domains[0],Ht=w.domains.slice(1).map((gt)=>{if(gt.includes(".")&>.endsWith(xe))return gt.replace(`.${xe}`,"");return gt}),{certificate:Ut,logicalId:ut}=b.createCertificate({domain:xe,subdomains:Ht,slug:l,environment:f,validationMethod:"DNS",hostedZoneId:ce?.hostedZoneId});v=ut,this.builder.addResource(ut,Ut)}let B="ECSCluster";this.builder.addResource(B,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${l}-${f}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${l}-${f}`},{Key:"Environment",Value:f}]}});let de=`${l}${f}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(de,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${l}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0",Description:"HTTP"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${l}-${f}-alb-sg`},{Key:"Environment",Value:f}]}});let ct=`${l}${f}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[xe,Ht]of Object.entries(C)){let Ut=Ht.port||3000;this.builder.addResource(ct,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${l}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:Ut,ToPort:Ut,SourceSecurityGroupId:{Ref:de},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${l}-${f}-ecs-sg`},{Key:"Environment",Value:f}]}});let ut=`${l}${f}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(ut,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${f}-ecs-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"],Policies:[{PolicyName:"ECRPullPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"}]}}]}});let gt=`${l}${f}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(gt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${f}-ecs-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"}]}}]}});let lt=`${l}${f}${xe}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),Ee=`/ecs/${l}-${f}-${xe}`;this.builder.addResource(lt,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:Ee,RetentionInDays:30}});let Qt=`${l}${f}${xe}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),ve=String(Ht.cpu||512),Pt=String(Ht.memory||1024);this.builder.addResource(Qt,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${f}-${xe}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:ve,Memory:Pt,ExecutionRoleArn:{"Fn::GetAtt":[ut,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[gt,"Arn"]},ContainerDefinitions:[{Name:xe,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${l}:latest`},Essential:!0,PortMappings:[{ContainerPort:Ut,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":Ee,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":xe}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${Ut}${Ht.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${l}-${f}-${xe}`},{Key:"Environment",Value:f}]},DependsOn:[ut,gt,lt]});let Ft=`${l}${f}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(A?.enabled!==!1){this.builder.addResource(Ft,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${l}-${f}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:de}],Tags:[{Key:"Name",Value:`${l}-${f}-alb`},{Key:"Environment",Value:f}]}});let lr=`${l}${f}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),Cr=A?.healthCheck?.path||Ht.healthCheck||"/health";this.builder.addResource(lr,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${l}-${f}-tg`,Port:Ut,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:Cr,HealthCheckIntervalSeconds:A?.healthCheck?.interval||30,HealthyThresholdCount:A?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:A?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${l}-${f}-tg`},{Key:"Environment",Value:f}]}});let br=`${l}${f}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(w?.enabled&&w?.redirectHttp)this.builder.addResource(br,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ft},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(br,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ft},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:lr}}]}});if(w?.enabled){let Ir=w.certificateArn||(v?{Ref:v}:void 0);if(Ir){let Er=`${l}${f}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Er,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ft},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Ir}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:lr}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let wr=`${l}${f}${xe}Service`.replace(/[^a-zA-Z0-9]/g,""),kr=Ht.desiredCount||1;this.builder.addResource(wr,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${f}-${xe}`,Cluster:{Ref:B},TaskDefinition:{Ref:Qt},DesiredCount:kr,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:ct}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:xe,ContainerPort:Ut,TargetGroupArn:{Ref:lr}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${l}-${f}-${xe}`},{Key:"Environment",Value:f}]},DependsOn:[Qt,br,lr]});let xr=Ht.autoScaling;if(xr){let Ir=`${l}${f}${xe}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Ir,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:xr.max||10,MinCapacity:xr.min||1,ResourceId:{"Fn::Sub":`service/\${${B}}/${l}-${f}-${xe}`},ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs",RoleARN:{"Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"}},DependsOn:wr}),xr.targetCpuUtilization)this.builder.addResource(`${l}${f}${xe}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${f}-${xe}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Ir},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:xr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(xr.targetMemoryUtilization)this.builder.addResource(`${l}${f}${xe}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${f}-${xe}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Ir},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:xr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(ce?.domain&&ce?.hostedZoneId)this.builder.addResource(`${l}${f}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:ce.hostedZoneId,Name:`api.${ce.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[Ft,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[Ft,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[B,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${l}-${f}-${xe}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[Ft,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let lr=`${l}${f}${xe}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(lr,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${f}-${xe}`,Cluster:{Ref:B},TaskDefinition:{Ref:Qt},DesiredCount:Ht.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:ct}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${l}-${f}-${xe}`},{Key:"Environment",Value:f}]},DependsOn:[Qt]})}break}}generateServerless(l,f){if(this.mergedConfig.infrastructure?.functions)for(let[C,A]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(A))continue;let{role:w,logicalId:ce}=ne.createRole({slug:l,environment:f,roleName:`${l}-${f}-${C}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(ce,w);let{lambdaFunction:v,logicalId:B}=a.createLambdaFunction({slug:l,environment:f,functionName:`${l}-${f}-${C}`,handler:A.handler||"index.handler",runtime:A.runtime||"nodejs20.x",code:{zipFile:A.code||"export const handler = async () => ({ statusCode: 200 });"},role:ce,timeout:A.timeout,memorySize:A.memorySize});this.builder.addResource(B,v)}if(this.mergedConfig.infrastructure?.api){let{restApi:C,logicalId:A}=Kd.createRestApi({slug:l,environment:f,apiName:`${l}-${f}-api`});this.builder.addResource(A,C)}}generateServer(l,f){if(!this.mergedConfig.infrastructure?.servers)return;let C=this.mergedConfig.infrastructure.servers,A=this.mergedConfig.infrastructure?.compute,w=this.mergedConfig.infrastructure?.ssl;if(Object.values(C).some((v)=>!v.privateNetwork||v.privateNetwork==="create"))this.generateNetworkInfrastructure(l,f);for(let[v,B]of Object.entries(C)){let de=B.instanceType||B.size||A?.size,xe=(de?a.InstanceSize.specs[de]:void 0)?.instanceType||de||"t3.micro",Ht=B.type||"app",Ut=B.userData||B.startupScript;if(!Ut)Ut=a.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:B.bunVersion||"latest",webServer:"none",domain:B.domain,enableSsl:!!w?.enabled,sslEmail:w?.letsEncrypt?.email,installRedis:Ht==="cache",installDatabaseClients:!!B.database});let ut=B.privateNetwork&&B.privateNetwork!=="create"?B.privateNetwork:{Ref:"VPC"},gt=B.subnet||{Ref:"PublicSubnet1"},Ee=!!this.mergedConfig.infrastructure?.email?.server?.enabled,Qt=[22,80,443,this.resolveApiOriginPort()];if(Ee)Qt.push(25,465,587,143,993);let ve=a.createServerModeStack({slug:`${l}-${v}`,environment:f,vpcId:ut,subnetId:gt,instanceType:xe,keyName:B.keyName||`${l}-${f}`,domain:B.domain,userData:Ut,volumeSize:B.diskSize||20,imageId:B.image,allowedPorts:Qt});for(let[Pt,Ft]of Object.entries(ve.resources))this.builder.addResource(Pt,Ft);this.serverEipLogicalIds.set(v,ve.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${v}Instance`,ve.outputs.instanceLogicalId),this.builder.addOutput(`${v}InstanceId`,{Value:{Ref:ve.outputs.instanceLogicalId},Description:`Instance ID for ${v} server`}),this.builder.addOutput(`${v}PublicIp`,{Value:{Ref:ve.outputs.eipLogicalId},Description:`Public IP for ${v} server`})}}generateComputeApp(l,f){let C=this.mergedConfig.infrastructure?.compute;if(!C)return;let A=this.mergedConfig.sites||{},w=Object.entries(A),v=this.mergedConfig.infrastructure?.dns?.domain,B=this.mergedConfig.infrastructure?.database,de=C.size,xe=(de?a.InstanceSize.specs[de]:void 0)?.instanceType||de||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(l,f);let Ht=this.buildCaddyfile(w),Ut=a.UserData.generateBunAppScript({runtime:C.runtime||"bun",runtimeVersion:C.runtimeVersion||"latest",systemPackages:C.systemPackages,database:B,caddyfile:Ht}),ut=Hs(C.appUpdates),gt=ut.length>0?`${Ut}
|
|
11
|
-
${
|
|
10
|
+
`)}normalizeMountPath(l){let f=l?.mountPath||l?.path;if(!f||f==="/")return;let C=`/${f}`.replace(/\/+/g,"/").replace(/\/$/,"");return C==="/"?void 0:C}storageBucketLogicalId(l,f,C){return`${l}-${f}-s3-${C}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((A)=>A.charAt(0).toUpperCase()+A.slice(1)).join("")}pathMountRewriteFunctionCode(l,f="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(l)}; var rewriteStyle = ${JSON.stringify(f)}; var uri = request.uri; if (uri === prefix) { uri = '/'; } else if (uri.indexOf(prefix + '/') === 0) { uri = uri.substring(prefix.length); } if (uri === '' || uri === '/') { request.uri = '/index.html'; return request; } if (uri.endsWith('/')) { request.uri = uri + 'index.html'; return request; } var lastSegment = uri.substring(uri.lastIndexOf('/') + 1); if (lastSegment.indexOf('.') === -1) { request.uri = rewriteStyle === 'flat' ? uri + '.html' : uri + '/index.html'; return request; } request.uri = uri; return request; }`}generate(){let l=this.mergedConfig.project.slug,f=this.environment,C=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),A=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),w=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(l,f),this.generateContainerInfrastructure(l,f);if(C)this.generateServerless(l,f);if(A)this.generateServer(l,f);if(w)this.generateComputeApp(l,f);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(l,f);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(l,f),this.storageFailoverReplicas.length>0)this.builder.addMetadata(qd,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(l){}generateNetworkInfrastructure(l,f){if(this.builder.hasResource("VPC"))return;let A=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:w,logicalId:B}=y.createVpc({slug:l,environment:f,cidr:A,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",w);let v=`${l}${f}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(v,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${l}-${f}-igw`},{Key:"Environment",Value:f}]}});let ce=`${l}${f}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(ce,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:v}}});let de=`${l}${f}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(de,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${l}-${f}-public-rt`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${l}${f}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:de},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:v}},DependsOn:ce});let ct=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",xe=["a","b"];for(let Ut=0;Ut<2;Ut++){let Qt=`PublicSubnet${Ut+1}`;this.builder.addResource(Qt,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${Ut}.0/24`,AvailabilityZone:`${ct}${xe[Ut]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${l}-${f}-public-${xe[Ut]}`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${Qt}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:Qt},RouteTableId:{Ref:de}}})}}generateContainerInfrastructure(l,f){let C=this.mergedConfig.infrastructure?.containers;if(!C)return;let A=this.mergedConfig.infrastructure?.loadBalancer,w=this.mergedConfig.infrastructure?.ssl,B=this.mergedConfig.infrastructure?.dns,v;if(w?.enabled&&w.domains?.length)if(w.certificateArn);else{let xe=w.domains[0],Ut=w.domains.slice(1).map((lt)=>{if(lt.includes(".")&<.endsWith(xe))return lt.replace(`.${xe}`,"");return lt}),{certificate:Qt,logicalId:gt}=b.createCertificate({domain:xe,subdomains:Ut,slug:l,environment:f,validationMethod:"DNS",hostedZoneId:B?.hostedZoneId});v=gt,this.builder.addResource(gt,Qt)}let ce="ECSCluster";this.builder.addResource(ce,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${l}-${f}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${l}-${f}`},{Key:"Environment",Value:f}]}});let de=`${l}${f}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(de,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${l}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0",Description:"HTTP"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${l}-${f}-alb-sg`},{Key:"Environment",Value:f}]}});let ct=`${l}${f}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[xe,Ut]of Object.entries(C)){let Qt=Ut.port||3000;this.builder.addResource(ct,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${l}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:Qt,ToPort:Qt,SourceSecurityGroupId:{Ref:de},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${l}-${f}-ecs-sg`},{Key:"Environment",Value:f}]}});let gt=`${l}${f}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(gt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${f}-ecs-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"],Policies:[{PolicyName:"ECRPullPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"}]}}]}});let lt=`${l}${f}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(lt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${f}-ecs-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"}]}}]}});let ut=`${l}${f}${xe}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),Ee=`/ecs/${l}-${f}-${xe}`;this.builder.addResource(ut,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:Ee,RetentionInDays:30}});let Ft=`${l}${f}${xe}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),ve=String(Ut.cpu||512),Pt=String(Ut.memory||1024);this.builder.addResource(Ft,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${f}-${xe}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:ve,Memory:Pt,ExecutionRoleArn:{"Fn::GetAtt":[gt,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[lt,"Arn"]},ContainerDefinitions:[{Name:xe,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${l}:latest`},Essential:!0,PortMappings:[{ContainerPort:Qt,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":Ee,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":xe}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${Qt}${Ut.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${l}-${f}-${xe}`},{Key:"Environment",Value:f}]},DependsOn:[gt,lt,ut]});let Ht=`${l}${f}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(A?.enabled!==!1){this.builder.addResource(Ht,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${l}-${f}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:de}],Tags:[{Key:"Name",Value:`${l}-${f}-alb`},{Key:"Environment",Value:f}]}});let lr=`${l}${f}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),Cr=A?.healthCheck?.path||Ut.healthCheck||"/health";this.builder.addResource(lr,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${l}-${f}-tg`,Port:Qt,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:Cr,HealthCheckIntervalSeconds:A?.healthCheck?.interval||30,HealthyThresholdCount:A?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:A?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${l}-${f}-tg`},{Key:"Environment",Value:f}]}});let br=`${l}${f}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(w?.enabled&&w?.redirectHttp)this.builder.addResource(br,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ht},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(br,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ht},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:lr}}]}});if(w?.enabled){let Ir=w.certificateArn||(v?{Ref:v}:void 0);if(Ir){let Er=`${l}${f}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Er,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ht},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Ir}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:lr}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let wr=`${l}${f}${xe}Service`.replace(/[^a-zA-Z0-9]/g,""),kr=Ut.desiredCount||1;this.builder.addResource(wr,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${f}-${xe}`,Cluster:{Ref:ce},TaskDefinition:{Ref:Ft},DesiredCount:kr,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:ct}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:xe,ContainerPort:Qt,TargetGroupArn:{Ref:lr}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${l}-${f}-${xe}`},{Key:"Environment",Value:f}]},DependsOn:[Ft,br,lr]});let xr=Ut.autoScaling;if(xr){let Ir=`${l}${f}${xe}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Ir,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:xr.max||10,MinCapacity:xr.min||1,ResourceId:{"Fn::Sub":`service/\${${ce}}/${l}-${f}-${xe}`},ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs",RoleARN:{"Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"}},DependsOn:wr}),xr.targetCpuUtilization)this.builder.addResource(`${l}${f}${xe}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${f}-${xe}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Ir},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:xr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(xr.targetMemoryUtilization)this.builder.addResource(`${l}${f}${xe}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${f}-${xe}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Ir},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:xr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(B?.domain&&B?.hostedZoneId)this.builder.addResource(`${l}${f}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:B.hostedZoneId,Name:`api.${B.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[Ht,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[Ht,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[ce,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${l}-${f}-${xe}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[Ht,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let lr=`${l}${f}${xe}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(lr,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${f}-${xe}`,Cluster:{Ref:ce},TaskDefinition:{Ref:Ft},DesiredCount:Ut.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:ct}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${l}-${f}-${xe}`},{Key:"Environment",Value:f}]},DependsOn:[Ft]})}break}}generateServerless(l,f){if(this.mergedConfig.infrastructure?.functions)for(let[C,A]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(A))continue;let{role:w,logicalId:B}=ne.createRole({slug:l,environment:f,roleName:`${l}-${f}-${C}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(B,w);let{lambdaFunction:v,logicalId:ce}=a.createLambdaFunction({slug:l,environment:f,functionName:`${l}-${f}-${C}`,handler:A.handler||"index.handler",runtime:A.runtime||"nodejs20.x",code:{zipFile:A.code||"export const handler = async () => ({ statusCode: 200 });"},role:B,timeout:A.timeout,memorySize:A.memorySize});this.builder.addResource(ce,v)}if(this.mergedConfig.infrastructure?.api){let{restApi:C,logicalId:A}=Kd.createRestApi({slug:l,environment:f,apiName:`${l}-${f}-api`});this.builder.addResource(A,C)}}generateServer(l,f){if(!this.mergedConfig.infrastructure?.servers)return;let C=this.mergedConfig.infrastructure.servers,A=this.mergedConfig.infrastructure?.compute,w=this.mergedConfig.infrastructure?.ssl;if(Object.values(C).some((v)=>!v.privateNetwork||v.privateNetwork==="create"))this.generateNetworkInfrastructure(l,f);for(let[v,ce]of Object.entries(C)){let de=ce.instanceType||ce.size||A?.size,xe=(de?a.InstanceSize.specs[de]:void 0)?.instanceType||de||"t3.micro",Ut=ce.type||"app",Qt=ce.userData||ce.startupScript;if(!Qt)Qt=a.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:ce.bunVersion||"latest",webServer:"none",domain:ce.domain,enableSsl:!!w?.enabled,sslEmail:w?.letsEncrypt?.email,installRedis:Ut==="cache",installDatabaseClients:!!ce.database});let gt=ce.privateNetwork&&ce.privateNetwork!=="create"?ce.privateNetwork:{Ref:"VPC"},lt=ce.subnet||{Ref:"PublicSubnet1"},Ee=!!this.mergedConfig.infrastructure?.email?.server?.enabled,Ft=[22,80,443,this.resolveApiOriginPort()];if(Ee)Ft.push(25,465,587,143,993);let ve=a.createServerModeStack({slug:`${l}-${v}`,environment:f,vpcId:gt,subnetId:lt,instanceType:xe,keyName:ce.keyName||`${l}-${f}`,domain:ce.domain,userData:Qt,volumeSize:ce.diskSize||20,imageId:ce.image,allowedPorts:Ft});for(let[Pt,Ht]of Object.entries(ve.resources))this.builder.addResource(Pt,Ht);this.serverEipLogicalIds.set(v,ve.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${v}Instance`,ve.outputs.instanceLogicalId),this.builder.addOutput(`${v}InstanceId`,{Value:{Ref:ve.outputs.instanceLogicalId},Description:`Instance ID for ${v} server`}),this.builder.addOutput(`${v}PublicIp`,{Value:{Ref:ve.outputs.eipLogicalId},Description:`Public IP for ${v} server`})}}generateComputeApp(l,f){let C=this.mergedConfig.infrastructure?.compute;if(!C)return;let A=this.mergedConfig.sites||{},w=Object.entries(A),v=this.mergedConfig.infrastructure?.dns?.domain,ce=this.mergedConfig.infrastructure?.database,de=C.size,xe=(de?a.InstanceSize.specs[de]:void 0)?.instanceType||de||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(l,f);let Ut=this.buildCaddyfile(w),Qt=a.UserData.generateBunAppScript({runtime:C.runtime||"bun",runtimeVersion:C.runtimeVersion||"latest",systemPackages:C.systemPackages,database:ce,caddyfile:Ut}),gt=Hs(C.appUpdates),lt=gt.length>0?`${Qt}
|
|
11
|
+
${gt.join(`
|
|
12
12
|
`)}
|
|
13
|
-
`:
|
|
14
|
-
else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`}});let Rs=[{Id:ri,DomainName:{"Fn::Sub":`\${${br}}.s3.${Pc}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Ee}}],Qs=[],$c=[];if(this.shouldRouteStorageBucketToCompute(ve,Pt)){this.appendComputeAppOrigin(Rs,Qs,$c,l,f,this.resolveComputeCachePathPatterns(Pt.computeRoutes));for(let Or of Qt){let Ba=`S3-${l}-${f}-${Or.name}`,kc=`${l}${f}${Or.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(kc,{Type:"AWS::CloudFront::Function",Properties:{Name:`${l}-${f}-${Or.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${l} ${f} ${Or.name} at ${Or.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(Or.mountPath,Or.rewriteStyle)}}),Rs.push({Id:Ba,DomainName:{"Fn::Sub":`\${${Or.logicalId}}.s3.${Pc}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Ee}}),$c.push(Or.logicalId,kc);for(let hg of[Or.mountPath,`${Or.mountPath}/*`])Qs.push({PathPattern:hg,TargetOriginId:Ba,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[kc,"FunctionARN"]}}]})}}let Oa,xl=ri;if(kr){let Or=`${ri}-failover`;Object.assign(Rs[0],kr.primaryConnection),Rs.push({Id:Or,DomainName:Zp(kr.replicaBucket,kr.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Ee}}),Oa=Xr({primaryOriginId:ri,secondaryOriginId:Or,statusCodes:kr.statusCodes}),xl=Oa.Items[0].Id}let Dc={Type:"AWS::CloudFront::Distribution",DependsOn:[br,Ee,...li?[li]:[],...$c],Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${f} ${ve} site`,DefaultRootObject:"index.html",Origins:Rs,...Oa?{OriginGroups:Oa}:{},DefaultCacheBehavior:{TargetOriginId:xl,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...li?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[li,"FunctionARN"]}}]}:{}},...Qs.length>0?{CacheBehaviors:Qs}:{},...Er.length>0?{Aliases:Er}:{},ViewerCertificate:Wn,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:_r}}};if(B)Dc.DependsOn.push(B);if(kr)St(Dc.Properties.DistributionConfig,`infrastructure.storage.${ve}`),this.storageFailoverReplicas.push({name:ve,primaryBucket:lr,primaryRegion:Pc,replicaBucket:kr.replicaBucket,replicaRegion:kr.replicaRegion,replicate:kr.replicate,distributionArnOutput:`${ve}CloudFrontDistributionArn`}),this.builder.addOutput(`${ve}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Ir}}`},Description:`CloudFront distribution ARN for ${ve} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${ve}FailoverBucketName`,{Value:kr.replicaBucket,Description:`Failover replica bucket for ${ve} (${kr.replicaRegion}), outside this stack`});this.builder.addResource(Ir,Dc);let fg=`${br}CloudFrontPolicy`;if(this.builder.addResource(fg,{Type:"AWS::S3::BucketPolicy",DependsOn:[br,Ir],Properties:{Bucket:{Ref:br},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${br}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Ir}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(ve,Pt))for(let Or of Qt){let Ba=`${Or.logicalId}CloudFrontPolicy`;this.builder.addResource(Ba,{Type:"AWS::S3::BucketPolicy",DependsOn:[Or.logicalId,Ir],Properties:{Bucket:{Ref:Or.logicalId},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${Or.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Ir}}`}}}}]}}})}if(Er.length>0)v.push({name:ve,bucketLogicalId:br,distLogicalId:Ir,oacLogicalId:Ee,aliases:Er});this.builder.addOutput(`${ve}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Ir,"DomainName"]},Description:`CloudFront domain for ${ve}`}),this.builder.addOutput(`${ve}CloudFrontDistributionId`,{Value:{Ref:Ir},Description:`CloudFront distribution ID for ${ve}`})}if(this.builder.addOutput(`${ve}BucketName`,{Value:{Ref:br},Description:`S3 bucket name for ${ve}`}),ve==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:br},Description:"Frontend S3 bucket name"});if(ve==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:br},Description:"Documentation S3 bucket name"});if(ve==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:br},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let lt=this.mergedConfig.infrastructure.sftp,Ee=zd.create({...lt,storage:this.resolveSftpStorage(lt,l,f)??lt.storage,slug:l,environment:f});for(let[Qt,ve]of Object.entries(Ee.resources))this.builder.addResource(Qt,ve);this.builder.addOutput("SftpServerId",{Value:{Ref:Ee.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${Ee.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:Ee.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(ce&&v.length>0)for(let{name:lt,distLogicalId:Ee,aliases:Qt}of v)for(let ve of Qt){let Pt=ve.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Pt}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ee],Properties:{HostedZoneId:ce,Name:ve,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[Ee,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${Pt}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ee],Properties:{HostedZoneId:ce,Name:ve,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[Ee,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[lt,Ee]of Object.entries(this.mergedConfig.infrastructure.databases))if(Ee.engine==="dynamodb"){let{table:Qt,logicalId:ve}=Yt.createTable({slug:l,environment:f,tableName:`${l}-${f}-${lt}`,partitionKey:Ee.partitionKey||{name:"id",type:"S"},sortKey:Ee.sortKey});this.builder.addResource(ve,Qt)}else if(Ee.engine==="postgres"){let{dbInstance:Qt,logicalId:ve}=Yt.createPostgres({slug:l,environment:f,dbInstanceIdentifier:`${l}-${f}-${lt}`,masterUsername:Ee.username||"admin",masterUserPassword:Ee.password||"changeme123",allocatedStorage:Ee.storage||20,dbInstanceClass:Ee.instanceClass||"db.t3.micro"});this.builder.addResource(ve,Qt)}else if(Ee.engine==="mysql"){let{dbInstance:Qt,logicalId:ve}=Yt.createMysql({slug:l,environment:f,dbInstanceIdentifier:`${l}-${f}-${lt}`,masterUsername:Ee.username||"admin",masterUserPassword:Ee.password||"changeme123",allocatedStorage:Ee.storage||20,dbInstanceClass:Ee.instanceClass||"db.t3.micro"});this.builder.addResource(ve,Qt)}}if(this.mergedConfig.infrastructure?.cdn)for(let[lt,Ee]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!Ee.origin)continue;let Qt=typeof Ee.customDomain==="string"?Ee.customDomain:Ee.customDomain?.domain||Ee.domain,ve=typeof Ee.customDomain==="object"?Ee.customDomain?.certificateArn:Ee.certificateArn,Pt=ve||de,Ft=`${l}${f}${lt}CDN`.replace(/[^a-zA-Z0-9]/g,""),lr=`S3-${l}-${f}-${lt}-cdn`,Cr=[{Id:lr,DomainName:Ee.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:Ee.originShield?{Enabled:!0,OriginShieldRegion:Ee.originShieldRegion||this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...re(Ee,`infrastructure.cdn.${lt}`)}],br=[],wr=[],kr=["GET","HEAD","OPTIONS"],xr=lr,Ir;if(Ee.failoverOrigin){yt(kr,`the default cache behavior of infrastructure.cdn.${lt}`);let bn=`${lr}-failover`,_r=typeof Ee.failoverOrigin==="string"?{domain:Ee.failoverOrigin}:Ee.failoverOrigin;if(!_r.domain)throw Error(`infrastructure.cdn.${lt}.failoverOrigin.domain is required`);if(_r.domain===Ee.origin)throw Error(`infrastructure.cdn.${lt}: failoverOrigin must differ from origin (both are ${Ee.origin})`);Cr.push({Id:bn,DomainName:_r.domain,OriginPath:_r.originPath||"",...vo(_r.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...re(_r,`infrastructure.cdn.${lt}.failoverOrigin`)}),Ir=Xr({primaryOriginId:lr,secondaryOriginId:bn,statusCodes:Ee.failoverStatusCodes}),xr=Ir.Items[0].Id}else if(Ee.failoverStatusCodes)throw Error(`infrastructure.cdn.${lt}: failoverStatusCodes needs failoverOrigin to fail over to`);if(Ee.routeCompute)this.appendComputeAppOrigin(Cr,br,wr,l,f,this.resolveComputeCachePathPatterns(Ee.computeRoutes));let Er=Pt&&Qt?{AcmCertificateArn:B&&!ve?{Ref:B}:Pt,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},sn=[...wr];if(B&&!ve&&Qt)sn.push(B);let Fn={Type:"AWS::CloudFront::Distribution",...sn.length>0?{DependsOn:sn}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${f} ${lt} CDN`,DefaultRootObject:"index.html",Origins:Cr,...Ir?{OriginGroups:Ir}:{},DefaultCacheBehavior:{TargetOriginId:xr,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:kr,CachedMethods:["GET","HEAD","OPTIONS"],Compress:Ee.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...br.length>0?{CacheBehaviors:br}:{},...Qt&&Pt?{Aliases:[Qt]}:{},ViewerCertificate:Er,PriceClass:"PriceClass_100",HttpVersion:Ee.http3?"http2and3":"http2"}}};if(St(Fn.Properties.DistributionConfig,`infrastructure.cdn.${lt}`),this.builder.addResource(Ft,Fn),ce&&Qt&&Pt){let bn=Qt.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${bn}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ft,...B&&!ve?[B]:[]],Properties:{HostedZoneId:ce,Name:Qt,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[Ft,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[lt,Ee]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(Ee))continue;let{queue:Qt,logicalId:ve}=G.createQueue({slug:l,environment:f,name:`${l}-${f}-${lt}`,fifo:Ee.fifo,visibilityTimeout:Ee.visibilityTimeout,messageRetentionPeriod:Ee.messageRetentionPeriod,delaySeconds:Ee.delaySeconds,maxMessageSize:Ee.maxMessageSize,receiveMessageWaitTime:Ee.receiveMessageWaitTime,contentBasedDeduplication:Ee.contentBasedDeduplication,encrypted:Ee.encrypted,kmsKeyId:Ee.kmsKeyId});this.builder.addResource(ve,Qt);let Pt;if(Ee.deadLetterQueue){let{deadLetterQueue:Ft,updatedSourceQueue:lr,deadLetterLogicalId:Cr}=G.createDeadLetterQueue(ve,{slug:l,environment:f,maxReceiveCount:Ee.maxReceiveCount});Pt=Cr,this.builder.addResource(Cr,Ft);let wr=this.builder.getResources()[ve];if(wr?.Properties)wr.Properties.RedrivePolicy=lr.Properties?.RedrivePolicy}if(Ee.trigger){let Ft=Ee.trigger,lr=`${l}${f}${Ft.functionName}`.replace(/[^a-zA-Z0-9]/g,""),Cr={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[ve,"Arn"]},FunctionName:{Ref:lr},BatchSize:Ft.batchSize||10,MaximumBatchingWindowInSeconds:Ft.batchWindow||0,Enabled:!0,...Ft.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...Ft.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:Ft.maxConcurrency}},...Ft.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(Ft.filterPattern)}]}}},DependsOn:[ve,lr]};this.builder.addResource(`${ve}Trigger`,Cr)}if(Ee.alarms?.enabled){let Ft=Ee.alarms,lr=Ft.notificationTopicArn;if(!lr&&Ft.notificationEmails?.length){let wr=`${ve}AlarmTopic`;this.builder.addResource(wr,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${f}-${lt}-alarms`,DisplayName:`${lt} Queue Alarms`}}),Ft.notificationEmails.forEach((kr,xr)=>{this.builder.addResource(`${wr}Sub${xr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:wr},Protocol:"email",Endpoint:kr}})}),lr={Ref:wr}}let Cr=Ft.queueDepthThreshold||1000;this.builder.addResource(`${ve}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-${lt}-queue-depth`,AlarmDescription:`Queue ${lt} depth exceeds ${Cr} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:Cr,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ve,"QueueName"]}}],...lr&&{AlarmActions:[lr],OKActions:[lr]}}});let br=Ft.messageAgeThreshold||3600;if(this.builder.addResource(`${ve}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-${lt}-message-age`,AlarmDescription:`Queue ${lt} oldest message exceeds ${br} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:br,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ve,"QueueName"]}}],...lr&&{AlarmActions:[lr],OKActions:[lr]}}}),Pt&&Ft.dlqAlarm!==!1)this.builder.addResource(`${Pt}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-${lt}-dlq-messages`,AlarmDescription:`Dead letter queue for ${lt} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[Pt,"QueueName"]}}],...lr&&{AlarmActions:[lr]}}})}if(Ee.subscribe){let Ft=Ee.subscribe,lr=Ft.topicArn;if(!lr&&Ft.topicName)lr={Ref:Ft.topicName};if(lr){this.builder.addResource(`${ve}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:ve}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[ve,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":lr}}}]}}});let Cr={TopicArn:lr,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[ve,"Arn"]},RawMessageDelivery:Ft.rawMessageDelivery||!1};if(Ft.filterPolicy)Cr.FilterPolicy=Ft.filterPolicy,Cr.FilterPolicyScope=Ft.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${ve}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:Cr,DependsOn:`${ve}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(l,f);else this.generateRealtimeResources(l,f);let ct=this.mergedConfig.infrastructure?.redirects;if(ct){let lt=ct.target||this.mergedConfig.infrastructure?.dns?.domain||"",Ee=ct.protocol||"https";if(ct.domains?.length&<)for(let Qt of ct.domains){let{bucket:ve,bucketPolicy:Pt,logicalId:Ft,policyLogicalId:lr}=bt.createDomainRedirectBucket({slug:l,environment:f,sourceDomain:Qt,targetDomain:lt,protocol:Ee});this.builder.addResource(Ft,ve),this.builder.addResource(lr,Pt)}if(ct.paths&&Object.keys(ct.paths).length>0){let Qt=bt.fromMapping(ct.paths,{statusCode:ct.statusCode||301}),{function:ve,logicalId:Pt}=bt.createPathRedirectFunction({slug:l,environment:f,rules:Qt});this.builder.addResource(Pt,ve)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[lt,Ee]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:Qt,logicalId:ve}=Ro.createAlarm({slug:l,environment:f,alarmName:`${l}-${f}-${lt}`,metricName:Ee.metricName||"Errors",namespace:Ee.namespace||"AWS/Lambda",threshold:Ee.threshold||1,comparisonOperator:Ee.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(ve,Qt)}let xe=this.mergedConfig.infrastructure?.cache;if(xe){let lt=xe.type||"redis";if(lt==="redis"){this.generateNetworkInfrastructure(l,f);let Ee=xe.redis||{},{replicationGroup:Qt,subnetGroup:ve,logicalId:Pt,subnetGroupId:Ft}=wo.createRedis({slug:l,environment:f,nodeType:Ee.nodeType||xe.nodeType||"cache.t3.micro",engineVersion:Ee.engineVersion||"7.1",port:Ee.port||6379,numCacheClusters:Ee.numCacheNodes||2,automaticFailover:Ee.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:Ee.snapshotRetentionLimit||7,snapshotWindow:Ee.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Pt,Qt),ve&&Ft)this.builder.addResource(Ft,ve);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Pt,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[Pt,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(lt==="memcached"){this.generateNetworkInfrastructure(l,f);let Ee=xe.elasticache||{},{cluster:Qt,subnetGroup:ve,logicalId:Pt,subnetGroupId:Ft}=wo.createMemcached({slug:l,environment:f,nodeType:Ee.nodeType||xe.nodeType||"cache.t3.micro",engineVersion:Ee.engineVersion||"1.6.22",numCacheNodes:Ee.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Pt,Qt),ve&&Ft)this.builder.addResource(Ft,ve);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Pt,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let Ht=this.mergedConfig.infrastructure?.email;if(Ht){let lt=Ht.domain||this.mergedConfig.infrastructure?.dns?.domain;if(lt){let{emailIdentity:Ee,logicalId:Qt}=m.verifyDomain({domain:lt,slug:l,environment:f,enableDkim:Ht.enableDkim!==!1,dkimKeyLength:Ht.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(Qt,Ee),Ht.configurationSet!==!1){let{configurationSet:Ft,logicalId:lr}=m.createConfigurationSet({slug:l,environment:f});this.builder.addResource(lr,Ft)}let ve=Ht.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(ve){if(Ht.enableDkim!==!1)for(let wr=1;wr<=3;wr++){let kr=`DkimRecord${wr}${lt.replace(/\./g,"")}`;this.builder.addResource(kr,{Type:"AWS::Route53::RecordSet",DependsOn:[Qt],Properties:{HostedZoneId:ve,Name:{"Fn::GetAtt":[Qt,`DkimDNSTokenName${wr}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[Qt,`DkimDNSTokenValue${wr}`]}]}})}let{record:Ft,logicalId:lr}=m.createSpfRecord(lt,ve);this.builder.addResource(lr,Ft);let{record:Cr,logicalId:br}=m.createDmarcRecord(lt,ve,{policy:"none",reportingEmail:Ht.dmarcReportingEmail||`dmarc-reports@${lt}`});this.builder.addResource(br,Cr)}this.builder.addOutput("EmailDomain",{Value:lt,Description:"SES verified email domain"});let Pt=Ht.server;if(Pt?.enabled&&ve){let Ft=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",lr=`${l}-${f}-email`,{role:Cr,policy:br,roleLogicalId:wr,policyLogicalId:kr}=m.createEmailLambdaRole({slug:l,environment:f,s3BucketArn:`arn:aws:s3:::${lr}`,sesIdentityArn:`arn:aws:ses:${Ft}:*:identity/${lt}`});this.builder.addResource(wr,Cr),this.builder.addResource(kr,br);let{function:xr,permission:Ir,logicalId:Er,permissionLogicalId:sn}=m.createInboundEmailLambda({slug:l,environment:f,roleArn:{"Fn::GetAtt":[wr,"Arn"]},s3BucketName:lr,organizedPrefix:"mailboxes/"});this.builder.addResource(Er,xr),this.builder.addResource(sn,Ir);let Fn=m.createInboundEmailSetup({slug:l,environment:f,domain:lt,s3BucketName:lr,s3KeyPrefix:"inbox/",region:Ft,hostedZoneId:ve,lambdaFunctionArn:{"Fn::GetAtt":[Er,"Arn"]}});for(let[_r,Wn]of Object.entries(Fn.resources)){if(Wn.Type==="AWS::SES::ReceiptRule")Wn.DependsOn=[sn,Er];this.builder.addResource(_r,Wn)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:Er},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:lr,Description:"S3 bucket for email storage"});let bn=this.serverEipLogicalIds.get("app");if(bn&&ve){let Wn=`${Pt?.subdomain||"mail"}.${lt}`,ri=Wn.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${ri}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:ve,Name:Wn,Type:"A",TTL:"300",ResourceRecords:[{Ref:bn}]}})}this.builder.addOutput("MailHost",{Value:`mail.${lt}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let Ut=this.mergedConfig.infrastructure?.search;if(Ut){let lt=Ut.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(lt)this.generateNetworkInfrastructure(l,f);let{domain:Ee,logicalId:Qt}=Zt.createDomain({slug:l,environment:f,engineVersion:Ut.engineVersion||"OpenSearch_2.11",instanceType:Ut.instanceType||"t3.small.search",instanceCount:Ut.instanceCount||1,volumeSize:Ut.volumeSize||10,volumeType:Ut.volumeType||"gp3",dedicatedMaster:Ut.dedicatedMaster||!1,dedicatedMasterType:Ut.dedicatedMasterType,dedicatedMasterCount:Ut.dedicatedMasterCount||3,multiAz:Ut.multiAz||!1,encryption:Ut.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:Ut.advancedSecurity,autoTune:Ut.autoTune!==!1,vpc:lt});this.builder.addResource(Qt,Ee),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[Qt,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[Qt,"Arn"]},Description:"OpenSearch domain ARN"})}let ut=this.mergedConfig.infrastructure?.fileSystem;if(ut&&Object.keys(ut).length>0){this.generateNetworkInfrastructure(l,f);for(let[lt,Ee]of Object.entries(ut)){let{fileSystem:Qt,logicalId:ve}=ze.createFileSystem({slug:`${l}-${lt}`,environment:f,encrypted:Ee.encrypted!==!1,performanceMode:Ee.performanceMode||"generalPurpose",throughputMode:Ee.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(ve,Qt);let{securityGroup:Pt,logicalId:Ft}=ze.createEfsSecurityGroup({slug:`${l}-${lt}`,environment:f,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(Ft,Pt);let{mountTargets:lr,logicalIds:Cr}=ze.createMultiAzMountTargets(ve,{slug:`${l}-${lt}`,environment:f,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:Ft}});for(let br=0;br<lr.length;br++)this.builder.addResource(Cr[br],lr[br]);this.builder.addOutput(`${lt}FileSystemId`,{Value:{Ref:ve},Description:`EFS file system ID for ${lt}`})}}let gt=this.mergedConfig.infrastructure?.ai;if(gt){let lt=gt.service||"ecs",Ee=gt.models||["*"],Qt=gt.allowStreaming!==!1,ve;if(lt==="ecs")ve=Pe.enableBedrockForEcs({slug:l,environment:f,models:Ee,allowStreaming:Qt});else if(lt==="ec2")ve=Pe.enableBedrockForEc2({slug:l,environment:f,models:Ee,allowStreaming:Qt});else if(lt==="lambda")ve=Pe.enableBedrockForLambda({slug:l,environment:f,models:Ee,allowStreaming:Qt});else ve=Pe.createBedrockRole(lt,{slug:l,environment:f,models:Ee,allowStreaming:Qt});if(this.builder.addResource(ve.logicalId,ve.role),gt.allowAsync){let{policy:Pt,logicalId:Ft}=Pe.createBedrockPolicy({slug:l,environment:f,models:Ee,allowStreaming:Qt,allowAsync:!0});this.builder.addResource(Ft,Pt)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[ve.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(l,f){let C=this.mergedConfig.infrastructure?.realtime;if(!C)return;let A=C.name||`${l}-${f}-realtime`,w=C.scaling||{},ce=C.storage||{type:"dynamodb"},v=w.handlerMemory||256,B=w.handlerTimeout||30,de=`${l}${f}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),ct=`${l}${f}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(ce.type==="dynamodb"){let Cr=ce.dynamodb||{},br=Cr.billingMode||"PAY_PER_REQUEST";this.builder.addResource(de,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${f}-realtime-connections`,BillingMode:br,AttributeDefinitions:[{AttributeName:"connectionId",AttributeType:"S"},{AttributeName:"userId",AttributeType:"S"}],KeySchema:[{AttributeName:"connectionId",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"userId-index",KeySchema:[{AttributeName:"userId",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"},...br==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Cr.readCapacity||5,WriteCapacityUnits:Cr.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...br==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Cr.readCapacity||5,WriteCapacityUnits:Cr.writeCapacity||5}},...Cr.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${l}-${f}-realtime-connections`},{Key:"Environment",Value:f}]}}),this.builder.addResource(ct,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${f}-realtime-channels`,BillingMode:br,AttributeDefinitions:[{AttributeName:"channel",AttributeType:"S"},{AttributeName:"connectionId",AttributeType:"S"}],KeySchema:[{AttributeName:"channel",KeyType:"HASH"},{AttributeName:"connectionId",KeyType:"RANGE"}],GlobalSecondaryIndexes:[{IndexName:"connectionId-index",KeySchema:[{AttributeName:"connectionId",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"},...br==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Cr.readCapacity||5,WriteCapacityUnits:Cr.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...br==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Cr.readCapacity||5,WriteCapacityUnits:Cr.writeCapacity||5}},Tags:[{Key:"Name",Value:`${l}-${f}-realtime-channels`},{Key:"Environment",Value:f}]}})}let xe=`${l}${f}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(xe,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${f}-realtime-handler-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"RealtimeHandlerPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:UpdateItem"],Resource:[{"Fn::GetAtt":[de,"Arn"]},{"Fn::Sub":`\${${de}.Arn}/index/*`},{"Fn::GetAtt":[ct,"Arn"]},{"Fn::Sub":`\${${ct}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let Ht=`${l}${f}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),Ut=`${l}${f}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),ut=`${l}${f}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ht,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${f}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[xe,"Arn"]},MemorySize:v,Timeout:B,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:de},CHANNELS_TABLE:{Ref:ct},ENVIRONMENT:f}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[xe,de]}),this.builder.addResource(Ut,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${f}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[xe,"Arn"]},MemorySize:v,Timeout:B,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:de},CHANNELS_TABLE:{Ref:ct},ENVIRONMENT:f}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[xe,de,ct]}),this.builder.addResource(ut,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${f}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[xe,"Arn"]},MemorySize:v,Timeout:B,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:de},CHANNELS_TABLE:{Ref:ct},ENVIRONMENT:f}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[xe,de,ct]});let gt=`${l}${f}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(gt,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:A,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:A,Environment:f}}});let lt=`${Ht}Permission`,Ee=`${Ut}Permission`,Qt=`${ut}Permission`;this.builder.addResource(lt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Ht},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${gt}}/*/$connect`}}}),this.builder.addResource(Ee,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Ut},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${gt}}/*/$disconnect`}}}),this.builder.addResource(Qt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:ut},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${gt}}/*/$default`}}});let ve=`${gt}ConnectInteg`,Pt=`${gt}DisconnectInteg`,Ft=`${gt}MessageInteg`;this.builder.addResource(ve,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:gt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Ht}.Arn}/invocations`}}}),this.builder.addResource(Pt,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:gt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Ut}.Arn}/invocations`}}}),this.builder.addResource(Ft,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:gt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${ut}.Arn}/invocations`}}}),this.builder.addResource(`${gt}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:gt},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${ve}}`}}}),this.builder.addResource(`${gt}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:gt},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${Pt}}`}}}),this.builder.addResource(`${gt}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:gt},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${Ft}}`}}});let lr=`${gt}Stage`;if(this.builder.addResource(lr,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:gt},StageName:f,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:w.messagesPerSecond||1000,ThrottlingRateLimit:w.messagesPerSecond||1000}}}),C.monitoring?.enabled){let Cr=C.monitoring,br=Cr.notificationTopicArn;if(!br&&Cr.notificationEmails?.length){let wr=`${gt}AlarmTopic`;this.builder.addResource(wr,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${f}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),Cr.notificationEmails.forEach((kr,xr)=>{this.builder.addResource(`${wr}Sub${xr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:wr},Protocol:"email",Endpoint:kr}})}),br={Ref:wr}}if(Cr.connectionThreshold)this.builder.addResource(`${gt}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${Cr.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:Cr.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:gt}}],...br&&{AlarmActions:[br]}}});if(Cr.errorThreshold)this.builder.addResource(`${gt}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${Cr.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:Cr.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:gt}}],...br&&{AlarmActions:[br]}}})}this.builder.addOutput(`${gt}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${gt}}.execute-api.\${AWS::Region}.amazonaws.com/${f}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${gt}Id`,{Description:"WebSocket API ID",Value:{Ref:gt},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
|
|
13
|
+
`:Qt,ut=w.map(([,Cr])=>Cr.port).filter((Cr)=>typeof Cr==="number"&&![80,443].includes(Cr)),Ee=this.resolveApiOriginPort(),Ft=`${l}${f}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),ve=`${l}-${f}-deploy`;this.builder.addResource(Ft,{Type:"AWS::S3::Bucket",Properties:{BucketName:ve,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"expire-old-releases",Status:"Enabled",ExpirationInDays:7,Prefix:"releases/"}]},Tags:[{Key:"Project",Value:l},{Key:"Environment",Value:f},{Key:"ManagedBy",Value:"ts-cloud"}]}});let Pt=a.createServerModeStack({slug:`${l}-app`,environment:f,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:xe,keyName:C.allowSsh?`${l}-${f}`:void 0,domain:v,userData:lt,volumeSize:C.disk?.size||20,imageId:C.image,allowedPorts:[...C.allowSsh?[22]:[],80,443,Ee,...ut]}),Ht=Pt.resources[Pt.outputs.instanceLogicalId];if(Ht?.Properties){let Cr=Ht.Properties.Tags||[];Ht.Properties.Tags=[...Cr,{Key:"Project",Value:l},{Key:"Environment",Value:f},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let lr=Pt.resources[Pt.outputs.roleLogicalId];if(lr?.Properties)lr.Properties.Policies=lr.Properties.Policies||[],lr.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${ve}`,`arn:aws:s3:::${ve}/*`]}]}});for(let[Cr,br]of Object.entries(Pt.resources))this.builder.addResource(Cr,br);this.builder.addOutput("deployBucketName",{Value:{Ref:Ft},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:Pt.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:Pt.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",Pt.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",Pt.outputs.instanceLogicalId)}jumpBoxFileSystemId(l,f,C){let A=Object.keys(this.mergedConfig.infrastructure?.fileSystem??{});if(typeof C==="string")return A.includes(C)?{Ref:this.fileSystemLogicalId(l,f,C)}:C;if(A.length===1)return{Ref:this.fileSystemLogicalId(l,f,A[0])};throw Error(A.length===0?"infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares no file system. Declare one, or set mountEfs to an EFS id.":`infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares ${A.length} (${A.join(", ")}). Set mountEfs to the name of the one to mount.`)}generateJumpBox(l,f){let C=this.mergedConfig.infrastructure?.jumpBox;if(!C)return;let A=C===!0?{}:C;if(A.enabled===!1)return;this.generateNetworkInfrastructure(l,f);let w=A.size||"micro",v=a.InstanceSize.specs[w]?.instanceType||w||"t3.micro",ce=a.createJumpBox({slug:l,environment:f,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:A.keyName,instanceType:v,allowedCidrs:A.allowedCidrs,mountEfs:A.mountEfs?{fileSystemId:this.jumpBoxFileSystemId(l,f,A.mountEfs),mountPath:A.mountPath||"/mnt/efs"}:void 0,databaseTools:A.databaseTools});for(let[de,ct]of Object.entries(ce.resources))this.builder.addResource(de,ct);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:ce.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(l,f){let C=this.mergedConfig.infrastructure?.ssl,A=this.mergedConfig.infrastructure?.dns,w=A?.domain,B=A?.hostedZoneId,v=[],ce,de;if(C?.certificateArn)de=C.certificateArn;else if(C?.enabled&&w&&B){let ut=C.domains||[w],Ee=ut[0],Ft=ut.slice(1).map((Ht)=>{if(Ht.includes(".")&&Ht.endsWith(Ee))return Ht.replace(`.${Ee}`,"");return Ht}),{certificate:ve,logicalId:Pt}=b.createCertificate({domain:Ee,subdomains:Ft,slug:l,environment:f,validationMethod:"DNS",hostedZoneId:B});ce=Pt,this.builder.addResource(Pt,ve)}if(this.mergedConfig.infrastructure?.storage){let ut=Object.entries(this.mergedConfig.infrastructure.storage).some(([,ve])=>ve.website),Ee;if(ut&&(ce||de))Ee=`${l}${f}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(Ee,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${l}-${f}-s3-oac`,Description:`OAC for ${l} ${f} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let Ft=Object.entries(this.mergedConfig.infrastructure.storage).map(([ve,Pt])=>({name:ve,config:Pt,mountPath:this.normalizeMountPath(Pt),rewriteStyle:Pt.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(l,f,ve)})).filter((ve)=>ve.name!=="public"&&ve.config.website&&ve.mountPath);for(let[ve,Pt]of Object.entries(this.mergedConfig.infrastructure.storage)){let Ht=!!(Pt.website&&Ee),lr=this.storageBucketName(l,f,ve),{bucket:Cr,logicalId:br}=De.createBucket({slug:l,name:ve,environment:f,bucketName:lr,versioning:Pt.versioning,encryption:Pt.encryption,public:Ht?!1:Pt.public}),wr=this.normalizeMountPath(Pt),kr;if(Pt.failover){let Ir=`infrastructure.storage.${ve}`;if(!Ht||!w||wr&&ve!=="public")throw Error(`${Ir}.failover needs this bucket to be served by its own CloudFront distribution: a website bucket (website: true), not mounted under the path of another site, with infrastructure.dns.domain set and SSL configured (infrastructure.ssl.certificateArn, or ssl.enabled with dns.hostedZoneId).`);if(kr=Yp({failover:Pt.failover,primaryBucket:lr,primaryRegion:this.mergedConfig.project.region||"us-east-1",where:Ir}),kr.replicate&&Cr.Properties){let Er=`${br}FailoverReplicationRole`;this.builder.addResource(Er,em({primaryBucket:lr,replicaBucket:kr.replicaBucket}));let sn=Cr.Properties;sn.VersioningConfiguration={Status:"Enabled"},sn.ReplicationConfiguration=tm({replicaBucket:kr.replicaBucket,roleArn:{"Fn::GetAtt":[Er,"Arn"]}})}}if(Ht&&Cr.Properties)Cr.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(br,Cr),Pt.website){let Ir=typeof Pt.website==="object"?Pt.website:{},Er=De.enableWebsiteHosting(Cr,Ir.indexDocument||"index.html",Ir.errorDocument);this.builder.addResource(br,Er)}let xr=this.normalizeMountPath(Pt);if(Ht&&Ee&&w&&!(xr&&ve!=="public")){let Ir=`${l}${f}${ve}CDN`.replace(/[^a-zA-Z0-9]/g,""),Er=[];if(Pt.aliases&&Pt.aliases.length>0)Er.push(...Pt.aliases);else if(ve==="public"){if(Er.push(w),C?.domains?.includes(`www.${w}`))Er.push(`www.${w}`)}else if(ve==="docs")Er.push(`docs.${w}`);else if(ve==="blog")Er.push(`blog.${w}`);let sn=typeof Pt.website==="object"?Pt.website:{},Fn=Pt.spa===!0,bn=sn.errorDocument||(Fn?"index.html":"404.html"),_r=[];if(Fn)_r.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else _r.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${bn}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${bn}`,ErrorCachingMinTTL:300});let Wn=de&&Er.length>0?{AcmCertificateArn:de,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:ce&&Er.length>0?{AcmCertificateArn:{Ref:ce},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},ri=`S3-${l}-${f}-${ve}`,$c=this.mergedConfig.project.region||"us-east-1",li;if(!Fn)li=`${l}${f}${ve}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(li,{Type:"AWS::CloudFront::Function",Properties:{Name:`${l}-${f}-${ve}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${l} ${f} ${ve} - appends .html to extensionless paths`,Runtime:"cloudfront-js-2.0"},FunctionCode:`function handler(event) { var request = event.request; var uri = request.uri; if (uri.endsWith('/')) { request.uri += 'index.html'; }
|
|
14
|
+
else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`}});let Rs=[{Id:ri,DomainName:{"Fn::Sub":`\${${br}}.s3.${$c}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Ee}}],Qs=[],Dc=[];if(this.shouldRouteStorageBucketToCompute(ve,Pt)){this.appendComputeAppOrigin(Rs,Qs,Dc,l,f,this.resolveComputeCachePathPatterns(Pt.computeRoutes));for(let Or of Ft){let Ba=`S3-${l}-${f}-${Or.name}`,vc=`${l}${f}${Or.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(vc,{Type:"AWS::CloudFront::Function",Properties:{Name:`${l}-${f}-${Or.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${l} ${f} ${Or.name} at ${Or.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(Or.mountPath,Or.rewriteStyle)}}),Rs.push({Id:Ba,DomainName:{"Fn::Sub":`\${${Or.logicalId}}.s3.${$c}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Ee}}),Dc.push(Or.logicalId,vc);for(let Ig of[Or.mountPath,`${Or.mountPath}/*`])Qs.push({PathPattern:Ig,TargetOriginId:Ba,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[vc,"FunctionARN"]}}]})}}let Oa,ku=ri;if(kr){let Or=`${ri}-failover`;Object.assign(Rs[0],kr.primaryConnection),Rs.push({Id:Or,DomainName:Zp(kr.replicaBucket,kr.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Ee}}),Oa=Xr({primaryOriginId:ri,secondaryOriginId:Or,statusCodes:kr.statusCodes}),ku=Oa.Items[0].Id}let kc={Type:"AWS::CloudFront::Distribution",DependsOn:[br,Ee,...li?[li]:[],...Dc],Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${f} ${ve} site`,DefaultRootObject:"index.html",Origins:Rs,...Oa?{OriginGroups:Oa}:{},DefaultCacheBehavior:{TargetOriginId:ku,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...li?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[li,"FunctionARN"]}}]}:{}},...Qs.length>0?{CacheBehaviors:Qs}:{},...Er.length>0?{Aliases:Er}:{},ViewerCertificate:Wn,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:_r}}};if(ce)kc.DependsOn.push(ce);if(kr)St(kc.Properties.DistributionConfig,`infrastructure.storage.${ve}`),this.storageFailoverReplicas.push({name:ve,primaryBucket:lr,primaryRegion:$c,replicaBucket:kr.replicaBucket,replicaRegion:kr.replicaRegion,replicate:kr.replicate,distributionArnOutput:`${ve}CloudFrontDistributionArn`}),this.builder.addOutput(`${ve}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Ir}}`},Description:`CloudFront distribution ARN for ${ve} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${ve}FailoverBucketName`,{Value:kr.replicaBucket,Description:`Failover replica bucket for ${ve} (${kr.replicaRegion}), outside this stack`});this.builder.addResource(Ir,kc);let wg=`${br}CloudFrontPolicy`;if(this.builder.addResource(wg,{Type:"AWS::S3::BucketPolicy",DependsOn:[br,Ir],Properties:{Bucket:{Ref:br},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${br}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Ir}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(ve,Pt))for(let Or of Ft){let Ba=`${Or.logicalId}CloudFrontPolicy`;this.builder.addResource(Ba,{Type:"AWS::S3::BucketPolicy",DependsOn:[Or.logicalId,Ir],Properties:{Bucket:{Ref:Or.logicalId},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${Or.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Ir}}`}}}}]}}})}if(Er.length>0)v.push({name:ve,bucketLogicalId:br,distLogicalId:Ir,oacLogicalId:Ee,aliases:Er});this.builder.addOutput(`${ve}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Ir,"DomainName"]},Description:`CloudFront domain for ${ve}`}),this.builder.addOutput(`${ve}CloudFrontDistributionId`,{Value:{Ref:Ir},Description:`CloudFront distribution ID for ${ve}`})}if(this.builder.addOutput(`${ve}BucketName`,{Value:{Ref:br},Description:`S3 bucket name for ${ve}`}),ve==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:br},Description:"Frontend S3 bucket name"});if(ve==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:br},Description:"Documentation S3 bucket name"});if(ve==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:br},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let ut=this.mergedConfig.infrastructure.sftp,Ee=zd.create({...ut,storage:this.resolveSftpStorage(ut,l,f)??ut.storage,slug:l,environment:f});for(let[Ft,ve]of Object.entries(Ee.resources))this.builder.addResource(Ft,ve);this.builder.addOutput("SftpServerId",{Value:{Ref:Ee.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${Ee.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:Ee.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(B&&v.length>0)for(let{name:ut,distLogicalId:Ee,aliases:Ft}of v)for(let ve of Ft){let Pt=ve.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Pt}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ee],Properties:{HostedZoneId:B,Name:ve,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[Ee,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${Pt}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ee],Properties:{HostedZoneId:B,Name:ve,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[Ee,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[ut,Ee]of Object.entries(this.mergedConfig.infrastructure.databases))if(Ee.engine==="dynamodb"){let{table:Ft,logicalId:ve}=Yt.createTable({slug:l,environment:f,tableName:`${l}-${f}-${ut}`,partitionKey:Ee.partitionKey||{name:"id",type:"S"},sortKey:Ee.sortKey});this.builder.addResource(ve,Ft)}else if(Ee.engine==="postgres"){let{dbInstance:Ft,logicalId:ve}=Yt.createPostgres({slug:l,environment:f,dbInstanceIdentifier:`${l}-${f}-${ut}`,masterUsername:Ee.username||"admin",masterUserPassword:Ee.password||"changeme123",allocatedStorage:Ee.storage||20,dbInstanceClass:Ee.instanceClass||"db.t3.micro"});this.builder.addResource(ve,Ft)}else if(Ee.engine==="mysql"){let{dbInstance:Ft,logicalId:ve}=Yt.createMysql({slug:l,environment:f,dbInstanceIdentifier:`${l}-${f}-${ut}`,masterUsername:Ee.username||"admin",masterUserPassword:Ee.password||"changeme123",allocatedStorage:Ee.storage||20,dbInstanceClass:Ee.instanceClass||"db.t3.micro"});this.builder.addResource(ve,Ft)}}if(this.mergedConfig.infrastructure?.cdn)for(let[ut,Ee]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!Ee.origin)continue;let Ft=typeof Ee.customDomain==="string"?Ee.customDomain:Ee.customDomain?.domain||Ee.domain,ve=typeof Ee.customDomain==="object"?Ee.customDomain?.certificateArn:Ee.certificateArn,Pt=ve||de,Ht=`${l}${f}${ut}CDN`.replace(/[^a-zA-Z0-9]/g,""),lr=`S3-${l}-${f}-${ut}-cdn`,Cr=[{Id:lr,DomainName:Ee.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:Ee.originShield?{Enabled:!0,OriginShieldRegion:Ee.originShieldRegion||this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...re(Ee,`infrastructure.cdn.${ut}`)}],br=[],wr=[],kr=["GET","HEAD","OPTIONS"],xr=lr,Ir;if(Ee.failoverOrigin){yt(kr,`the default cache behavior of infrastructure.cdn.${ut}`);let bn=`${lr}-failover`,_r=typeof Ee.failoverOrigin==="string"?{domain:Ee.failoverOrigin}:Ee.failoverOrigin;if(!_r.domain)throw Error(`infrastructure.cdn.${ut}.failoverOrigin.domain is required`);if(_r.domain===Ee.origin)throw Error(`infrastructure.cdn.${ut}: failoverOrigin must differ from origin (both are ${Ee.origin})`);Cr.push({Id:bn,DomainName:_r.domain,OriginPath:_r.originPath||"",...vo(_r.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...re(_r,`infrastructure.cdn.${ut}.failoverOrigin`)}),Ir=Xr({primaryOriginId:lr,secondaryOriginId:bn,statusCodes:Ee.failoverStatusCodes}),xr=Ir.Items[0].Id}else if(Ee.failoverStatusCodes)throw Error(`infrastructure.cdn.${ut}: failoverStatusCodes needs failoverOrigin to fail over to`);if(Ee.routeCompute)this.appendComputeAppOrigin(Cr,br,wr,l,f,this.resolveComputeCachePathPatterns(Ee.computeRoutes));let Er=Pt&&Ft?{AcmCertificateArn:ce&&!ve?{Ref:ce}:Pt,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},sn=[...wr];if(ce&&!ve&&Ft)sn.push(ce);let Fn={Type:"AWS::CloudFront::Distribution",...sn.length>0?{DependsOn:sn}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${f} ${ut} CDN`,DefaultRootObject:"index.html",Origins:Cr,...Ir?{OriginGroups:Ir}:{},DefaultCacheBehavior:{TargetOriginId:xr,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:kr,CachedMethods:["GET","HEAD","OPTIONS"],Compress:Ee.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...br.length>0?{CacheBehaviors:br}:{},...Ft&&Pt?{Aliases:[Ft]}:{},ViewerCertificate:Er,PriceClass:"PriceClass_100",HttpVersion:Ee.http3?"http2and3":"http2"}}};if(St(Fn.Properties.DistributionConfig,`infrastructure.cdn.${ut}`),this.builder.addResource(Ht,Fn),B&&Ft&&Pt){let bn=Ft.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${bn}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ht,...ce&&!ve?[ce]:[]],Properties:{HostedZoneId:B,Name:Ft,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[Ht,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[ut,Ee]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(Ee))continue;let{queue:Ft,logicalId:ve}=G.createQueue({slug:l,environment:f,name:`${l}-${f}-${ut}`,fifo:Ee.fifo,visibilityTimeout:Ee.visibilityTimeout,messageRetentionPeriod:Ee.messageRetentionPeriod,delaySeconds:Ee.delaySeconds,maxMessageSize:Ee.maxMessageSize,receiveMessageWaitTime:Ee.receiveMessageWaitTime,contentBasedDeduplication:Ee.contentBasedDeduplication,encrypted:Ee.encrypted,kmsKeyId:Ee.kmsKeyId});this.builder.addResource(ve,Ft);let Pt;if(Ee.deadLetterQueue){let{deadLetterQueue:Ht,updatedSourceQueue:lr,deadLetterLogicalId:Cr}=G.createDeadLetterQueue(ve,{slug:l,environment:f,maxReceiveCount:Ee.maxReceiveCount});Pt=Cr,this.builder.addResource(Cr,Ht);let wr=this.builder.getResources()[ve];if(wr?.Properties)wr.Properties.RedrivePolicy=lr.Properties?.RedrivePolicy}if(Ee.trigger){let Ht=Ee.trigger,lr=`${l}${f}${Ht.functionName}`.replace(/[^a-zA-Z0-9]/g,""),Cr={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[ve,"Arn"]},FunctionName:{Ref:lr},BatchSize:Ht.batchSize||10,MaximumBatchingWindowInSeconds:Ht.batchWindow||0,Enabled:!0,...Ht.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...Ht.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:Ht.maxConcurrency}},...Ht.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(Ht.filterPattern)}]}}},DependsOn:[ve,lr]};this.builder.addResource(`${ve}Trigger`,Cr)}if(Ee.alarms?.enabled){let Ht=Ee.alarms,lr=Ht.notificationTopicArn;if(!lr&&Ht.notificationEmails?.length){let wr=`${ve}AlarmTopic`;this.builder.addResource(wr,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${f}-${ut}-alarms`,DisplayName:`${ut} Queue Alarms`}}),Ht.notificationEmails.forEach((kr,xr)=>{this.builder.addResource(`${wr}Sub${xr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:wr},Protocol:"email",Endpoint:kr}})}),lr={Ref:wr}}let Cr=Ht.queueDepthThreshold||1000;this.builder.addResource(`${ve}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-${ut}-queue-depth`,AlarmDescription:`Queue ${ut} depth exceeds ${Cr} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:Cr,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ve,"QueueName"]}}],...lr&&{AlarmActions:[lr],OKActions:[lr]}}});let br=Ht.messageAgeThreshold||3600;if(this.builder.addResource(`${ve}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-${ut}-message-age`,AlarmDescription:`Queue ${ut} oldest message exceeds ${br} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:br,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ve,"QueueName"]}}],...lr&&{AlarmActions:[lr],OKActions:[lr]}}}),Pt&&Ht.dlqAlarm!==!1)this.builder.addResource(`${Pt}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-${ut}-dlq-messages`,AlarmDescription:`Dead letter queue for ${ut} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[Pt,"QueueName"]}}],...lr&&{AlarmActions:[lr]}}})}if(Ee.subscribe){let Ht=Ee.subscribe,lr=Ht.topicArn;if(!lr&&Ht.topicName)lr={Ref:Ht.topicName};if(lr){this.builder.addResource(`${ve}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:ve}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[ve,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":lr}}}]}}});let Cr={TopicArn:lr,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[ve,"Arn"]},RawMessageDelivery:Ht.rawMessageDelivery||!1};if(Ht.filterPolicy)Cr.FilterPolicy=Ht.filterPolicy,Cr.FilterPolicyScope=Ht.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${ve}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:Cr,DependsOn:`${ve}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(l,f);else this.generateRealtimeResources(l,f);let ct=this.mergedConfig.infrastructure?.redirects;if(ct){let ut=ct.target||this.mergedConfig.infrastructure?.dns?.domain||"",Ee=ct.protocol||"https";if(ct.domains?.length&&ut)for(let Ft of ct.domains){let{bucket:ve,bucketPolicy:Pt,logicalId:Ht,policyLogicalId:lr}=bt.createDomainRedirectBucket({slug:l,environment:f,sourceDomain:Ft,targetDomain:ut,protocol:Ee});this.builder.addResource(Ht,ve),this.builder.addResource(lr,Pt)}if(ct.paths&&Object.keys(ct.paths).length>0){let Ft=bt.fromMapping(ct.paths,{statusCode:ct.statusCode||301}),{function:ve,logicalId:Pt}=bt.createPathRedirectFunction({slug:l,environment:f,rules:Ft});this.builder.addResource(Pt,ve)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[ut,Ee]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:Ft,logicalId:ve}=Ro.createAlarm({slug:l,environment:f,alarmName:`${l}-${f}-${ut}`,metricName:Ee.metricName||"Errors",namespace:Ee.namespace||"AWS/Lambda",threshold:Ee.threshold||1,comparisonOperator:Ee.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(ve,Ft)}let xe=this.mergedConfig.infrastructure?.cache;if(xe){let ut=xe.type||"redis";if(ut==="redis"){this.generateNetworkInfrastructure(l,f);let Ee=xe.redis||{},{replicationGroup:Ft,subnetGroup:ve,logicalId:Pt,subnetGroupId:Ht}=wo.createRedis({slug:l,environment:f,nodeType:Ee.nodeType||xe.nodeType||"cache.t3.micro",engineVersion:Ee.engineVersion||"7.1",port:Ee.port||6379,numCacheClusters:Ee.numCacheNodes||2,automaticFailover:Ee.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:Ee.snapshotRetentionLimit||7,snapshotWindow:Ee.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Pt,Ft),ve&&Ht)this.builder.addResource(Ht,ve);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Pt,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[Pt,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(ut==="memcached"){this.generateNetworkInfrastructure(l,f);let Ee=xe.elasticache||{},{cluster:Ft,subnetGroup:ve,logicalId:Pt,subnetGroupId:Ht}=wo.createMemcached({slug:l,environment:f,nodeType:Ee.nodeType||xe.nodeType||"cache.t3.micro",engineVersion:Ee.engineVersion||"1.6.22",numCacheNodes:Ee.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Pt,Ft),ve&&Ht)this.builder.addResource(Ht,ve);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Pt,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let Ut=this.mergedConfig.infrastructure?.email;if(Ut){let ut=Ut.domain||this.mergedConfig.infrastructure?.dns?.domain;if(ut){let{emailIdentity:Ee,logicalId:Ft}=m.verifyDomain({domain:ut,slug:l,environment:f,enableDkim:Ut.enableDkim!==!1,dkimKeyLength:Ut.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(Ft,Ee),Ut.configurationSet!==!1){let{configurationSet:Ht,logicalId:lr}=m.createConfigurationSet({slug:l,environment:f});this.builder.addResource(lr,Ht)}let ve=Ut.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(ve){if(Ut.enableDkim!==!1)for(let wr=1;wr<=3;wr++){let kr=`DkimRecord${wr}${ut.replace(/\./g,"")}`;this.builder.addResource(kr,{Type:"AWS::Route53::RecordSet",DependsOn:[Ft],Properties:{HostedZoneId:ve,Name:{"Fn::GetAtt":[Ft,`DkimDNSTokenName${wr}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[Ft,`DkimDNSTokenValue${wr}`]}]}})}let{record:Ht,logicalId:lr}=m.createSpfRecord(ut,ve);this.builder.addResource(lr,Ht);let{record:Cr,logicalId:br}=m.createDmarcRecord(ut,ve,{policy:"none",reportingEmail:Ut.dmarcReportingEmail||`dmarc-reports@${ut}`});this.builder.addResource(br,Cr)}this.builder.addOutput("EmailDomain",{Value:ut,Description:"SES verified email domain"});let Pt=Ut.server;if(Pt?.enabled&&ve){let Ht=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",lr=`${l}-${f}-email`,{role:Cr,policy:br,roleLogicalId:wr,policyLogicalId:kr}=m.createEmailLambdaRole({slug:l,environment:f,s3BucketArn:`arn:aws:s3:::${lr}`,sesIdentityArn:`arn:aws:ses:${Ht}:*:identity/${ut}`});this.builder.addResource(wr,Cr),this.builder.addResource(kr,br);let{function:xr,permission:Ir,logicalId:Er,permissionLogicalId:sn}=m.createInboundEmailLambda({slug:l,environment:f,roleArn:{"Fn::GetAtt":[wr,"Arn"]},s3BucketName:lr,organizedPrefix:"mailboxes/"});this.builder.addResource(Er,xr),this.builder.addResource(sn,Ir);let Fn=m.createInboundEmailSetup({slug:l,environment:f,domain:ut,s3BucketName:lr,s3KeyPrefix:"inbox/",region:Ht,hostedZoneId:ve,lambdaFunctionArn:{"Fn::GetAtt":[Er,"Arn"]}});for(let[_r,Wn]of Object.entries(Fn.resources)){if(Wn.Type==="AWS::SES::ReceiptRule")Wn.DependsOn=[sn,Er];this.builder.addResource(_r,Wn)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:Er},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:lr,Description:"S3 bucket for email storage"});let bn=this.serverEipLogicalIds.get("app");if(bn&&ve){let Wn=`${Pt?.subdomain||"mail"}.${ut}`,ri=Wn.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${ri}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:ve,Name:Wn,Type:"A",TTL:"300",ResourceRecords:[{Ref:bn}]}})}this.builder.addOutput("MailHost",{Value:`mail.${ut}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let Qt=this.mergedConfig.infrastructure?.search;if(Qt){let ut=Qt.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(ut)this.generateNetworkInfrastructure(l,f);let{domain:Ee,logicalId:Ft}=Zt.createDomain({slug:l,environment:f,engineVersion:Qt.engineVersion||"OpenSearch_2.11",instanceType:Qt.instanceType||"t3.small.search",instanceCount:Qt.instanceCount||1,volumeSize:Qt.volumeSize||10,volumeType:Qt.volumeType||"gp3",dedicatedMaster:Qt.dedicatedMaster||!1,dedicatedMasterType:Qt.dedicatedMasterType,dedicatedMasterCount:Qt.dedicatedMasterCount||3,multiAz:Qt.multiAz||!1,encryption:Qt.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:Qt.advancedSecurity,autoTune:Qt.autoTune!==!1,vpc:ut});this.builder.addResource(Ft,Ee),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[Ft,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[Ft,"Arn"]},Description:"OpenSearch domain ARN"})}let gt=this.mergedConfig.infrastructure?.fileSystem;if(gt&&Object.keys(gt).length>0){this.generateNetworkInfrastructure(l,f);for(let[ut,Ee]of Object.entries(gt)){let{fileSystem:Ft,logicalId:ve}=ze.createFileSystem({slug:`${l}-${ut}`,environment:f,encrypted:Ee.encrypted!==!1,performanceMode:Ee.performanceMode||"generalPurpose",throughputMode:Ee.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(ve,Ft);let{securityGroup:Pt,logicalId:Ht}=ze.createEfsSecurityGroup({slug:`${l}-${ut}`,environment:f,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(Ht,Pt);let{mountTargets:lr,logicalIds:Cr}=ze.createMultiAzMountTargets(ve,{slug:`${l}-${ut}`,environment:f,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:Ht}});for(let br=0;br<lr.length;br++)this.builder.addResource(Cr[br],lr[br]);this.builder.addOutput(`${ut}FileSystemId`,{Value:{Ref:ve},Description:`EFS file system ID for ${ut}`})}}let lt=this.mergedConfig.infrastructure?.ai;if(lt){let ut=lt.service||"ecs",Ee=lt.models||["*"],Ft=lt.allowStreaming!==!1,ve;if(ut==="ecs")ve=Pe.enableBedrockForEcs({slug:l,environment:f,models:Ee,allowStreaming:Ft});else if(ut==="ec2")ve=Pe.enableBedrockForEc2({slug:l,environment:f,models:Ee,allowStreaming:Ft});else if(ut==="lambda")ve=Pe.enableBedrockForLambda({slug:l,environment:f,models:Ee,allowStreaming:Ft});else ve=Pe.createBedrockRole(ut,{slug:l,environment:f,models:Ee,allowStreaming:Ft});if(this.builder.addResource(ve.logicalId,ve.role),lt.allowAsync){let{policy:Pt,logicalId:Ht}=Pe.createBedrockPolicy({slug:l,environment:f,models:Ee,allowStreaming:Ft,allowAsync:!0});this.builder.addResource(Ht,Pt)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[ve.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(l,f){let C=this.mergedConfig.infrastructure?.realtime;if(!C)return;let A=C.name||`${l}-${f}-realtime`,w=C.scaling||{},B=C.storage||{type:"dynamodb"},v=w.handlerMemory||256,ce=w.handlerTimeout||30,de=`${l}${f}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),ct=`${l}${f}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(B.type==="dynamodb"){let Cr=B.dynamodb||{},br=Cr.billingMode||"PAY_PER_REQUEST";this.builder.addResource(de,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${f}-realtime-connections`,BillingMode:br,AttributeDefinitions:[{AttributeName:"connectionId",AttributeType:"S"},{AttributeName:"userId",AttributeType:"S"}],KeySchema:[{AttributeName:"connectionId",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"userId-index",KeySchema:[{AttributeName:"userId",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"},...br==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Cr.readCapacity||5,WriteCapacityUnits:Cr.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...br==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Cr.readCapacity||5,WriteCapacityUnits:Cr.writeCapacity||5}},...Cr.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${l}-${f}-realtime-connections`},{Key:"Environment",Value:f}]}}),this.builder.addResource(ct,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${f}-realtime-channels`,BillingMode:br,AttributeDefinitions:[{AttributeName:"channel",AttributeType:"S"},{AttributeName:"connectionId",AttributeType:"S"}],KeySchema:[{AttributeName:"channel",KeyType:"HASH"},{AttributeName:"connectionId",KeyType:"RANGE"}],GlobalSecondaryIndexes:[{IndexName:"connectionId-index",KeySchema:[{AttributeName:"connectionId",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"},...br==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Cr.readCapacity||5,WriteCapacityUnits:Cr.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...br==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Cr.readCapacity||5,WriteCapacityUnits:Cr.writeCapacity||5}},Tags:[{Key:"Name",Value:`${l}-${f}-realtime-channels`},{Key:"Environment",Value:f}]}})}let xe=`${l}${f}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(xe,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${f}-realtime-handler-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"RealtimeHandlerPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:UpdateItem"],Resource:[{"Fn::GetAtt":[de,"Arn"]},{"Fn::Sub":`\${${de}.Arn}/index/*`},{"Fn::GetAtt":[ct,"Arn"]},{"Fn::Sub":`\${${ct}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let Ut=`${l}${f}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),Qt=`${l}${f}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),gt=`${l}${f}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ut,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${f}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[xe,"Arn"]},MemorySize:v,Timeout:ce,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:de},CHANNELS_TABLE:{Ref:ct},ENVIRONMENT:f}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[xe,de]}),this.builder.addResource(Qt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${f}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[xe,"Arn"]},MemorySize:v,Timeout:ce,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:de},CHANNELS_TABLE:{Ref:ct},ENVIRONMENT:f}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[xe,de,ct]}),this.builder.addResource(gt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${f}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[xe,"Arn"]},MemorySize:v,Timeout:ce,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:de},CHANNELS_TABLE:{Ref:ct},ENVIRONMENT:f}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[xe,de,ct]});let lt=`${l}${f}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(lt,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:A,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:A,Environment:f}}});let ut=`${Ut}Permission`,Ee=`${Qt}Permission`,Ft=`${gt}Permission`;this.builder.addResource(ut,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Ut},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${lt}}/*/$connect`}}}),this.builder.addResource(Ee,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Qt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${lt}}/*/$disconnect`}}}),this.builder.addResource(Ft,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:gt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${lt}}/*/$default`}}});let ve=`${lt}ConnectInteg`,Pt=`${lt}DisconnectInteg`,Ht=`${lt}MessageInteg`;this.builder.addResource(ve,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:lt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Ut}.Arn}/invocations`}}}),this.builder.addResource(Pt,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:lt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Qt}.Arn}/invocations`}}}),this.builder.addResource(Ht,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:lt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${gt}.Arn}/invocations`}}}),this.builder.addResource(`${lt}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:lt},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${ve}}`}}}),this.builder.addResource(`${lt}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:lt},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${Pt}}`}}}),this.builder.addResource(`${lt}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:lt},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${Ht}}`}}});let lr=`${lt}Stage`;if(this.builder.addResource(lr,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:lt},StageName:f,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:w.messagesPerSecond||1000,ThrottlingRateLimit:w.messagesPerSecond||1000}}}),C.monitoring?.enabled){let Cr=C.monitoring,br=Cr.notificationTopicArn;if(!br&&Cr.notificationEmails?.length){let wr=`${lt}AlarmTopic`;this.builder.addResource(wr,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${f}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),Cr.notificationEmails.forEach((kr,xr)=>{this.builder.addResource(`${wr}Sub${xr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:wr},Protocol:"email",Endpoint:kr}})}),br={Ref:wr}}if(Cr.connectionThreshold)this.builder.addResource(`${lt}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${Cr.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:Cr.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:lt}}],...br&&{AlarmActions:[br]}}});if(Cr.errorThreshold)this.builder.addResource(`${lt}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${Cr.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:Cr.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:lt}}],...br&&{AlarmActions:[br]}}})}this.builder.addOutput(`${lt}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${lt}}.execute-api.\${AWS::Region}.amazonaws.com/${f}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${lt}Id`,{Description:"WebSocket API ID",Value:{Ref:lt},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
|
|
15
15
|
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
|
|
16
16
|
const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb');
|
|
17
17
|
|
|
@@ -170,7 +170,7 @@ catch (error) {
|
|
|
170
170
|
return { statusCode: 500, body: JSON.stringify({ error: 'Internal error' }) };
|
|
171
171
|
}
|
|
172
172
|
};
|
|
173
|
-
`.trim()}generateRealtimeServerResources(l,f){let C=this.mergedConfig.infrastructure?.realtime;if(!C)return;let A=C.server||{},w=A.port||6001,
|
|
173
|
+
`.trim()}generateRealtimeServerResources(l,f){let C=this.mergedConfig.infrastructure?.realtime;if(!C)return;let A=C.server||{},w=A.port||6001,B=A.instances||1,v=`${l}${f}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(v,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${l} realtime WebSocket server`,GroupName:`${l}-${f}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:w,ToPort:w,CidrIp:"0.0.0.0/0",Description:"WebSocket connections"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS/WSS connections"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${l}-${f}-realtime-sg`},{Key:"Environment",Value:f}]}});let ce=`${l}${f}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),de=`${l}${f}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),ct=`${l}${f}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(ct,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${f}-realtime-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}}),this.builder.addResource(de,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${f}-realtime-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RealtimeTaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},...A.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let xe=[{Name:"BROADCAST_HOST",Value:A.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(w)},{Name:"NODE_ENV",Value:f==="production"?"production":"development"}];if(A.redis?.enabled){if(A.redis.useElastiCache)xe.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),xe.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else xe.push({Name:"REDIS_HOST",Value:A.redis.host||"localhost"}),xe.push({Name:"REDIS_PORT",Value:String(A.redis.port||6379)});if(A.redis.keyPrefix)xe.push({Name:"REDIS_KEY_PREFIX",Value:A.redis.keyPrefix})}this.builder.addResource(ce,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${f}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[ct,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[de,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${l}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:w,Protocol:"tcp"}],Environment:xe,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${l}-${f}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${w}${A.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${l}-${f}-realtime`},{Key:"Environment",Value:f}]},DependsOn:[ct,de]});let Ut=`${l}${f}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ut,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${l}-${f}-realtime`,RetentionInDays:30}});let Qt=`${l}${f}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Qt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${f}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:ce},DesiredCount:B,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:v}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${l}-${f}-realtime`},{Key:"Environment",Value:f}]},DependsOn:[ce,v,Ut]}),A.autoScaling){let gt=A.autoScaling,lt=`${l}${f}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(lt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:gt.max||10,MinCapacity:gt.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${l}-${f}-realtime`},RoleARN:{"Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"},ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},DependsOn:Qt}),gt.targetCPU)this.builder.addResource(`${l}${f}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${f}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:lt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:gt.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(C.monitoring?.enabled){let gt=C.monitoring,lt=gt.notificationTopicArn;if(!lt&>.notificationEmails?.length){let ut=`${l}${f}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(ut,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${f}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),gt.notificationEmails.forEach((Ee,Ft)=>{this.builder.addResource(`${ut}Sub${Ft}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:ut},Protocol:"email",Endpoint:Ee}})}),lt={Ref:ut}}this.builder.addResource(`${l}${f}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-realtime-high-cpu`,AlarmDescription:"Realtime server CPU utilization is high",MetricName:"CPUUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${l}-${f}-realtime`}],...lt&&{AlarmActions:[lt]}},DependsOn:Qt}),this.builder.addResource(`${l}${f}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${f}-realtime-high-memory`,AlarmDescription:"Realtime server memory utilization is high",MetricName:"MemoryUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${l}-${f}-realtime`}],...lt&&{AlarmActions:[lt]}},DependsOn:Qt})}this.builder.addOutput(`${l}${f}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${l}-${f}-realtime.\${AWS::Region}.elb.amazonaws.com:${w}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let l=this.mergedConfig.infrastructure?.realtime;if(!l||l.mode!=="server")return"";let f=l.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
|
|
174
174
|
|
|
175
175
|
export default {
|
|
176
176
|
verbose: ${this.environment!=="production"},
|
|
@@ -219,7 +219,7 @@ ${f.loadManagement?.enabled?`
|
|
|
219
219
|
},
|
|
220
220
|
`:""}
|
|
221
221
|
} satisfies BroadcastConfig
|
|
222
|
-
`}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function
|
|
222
|
+
`}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function Mg(l){let f=[],C=[];if(!l.AWSTemplateFormatVersion)f.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(l.AWSTemplateFormatVersion!=="2010-09-09")C.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!l.Resources||Object.keys(l.Resources).length===0)f.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[A,w]of Object.entries(l.Resources))Bg(A,w,f,C);if(l.Resources){let A=zg(l.Resources);if(A.length>0)f.push({path:"Resources",message:`Circular dependencies detected: ${A.join(" -> ")}`,severity:"error"})}if(l.Parameters)for(let[A,w]of Object.entries(l.Parameters))Wg(A,w,f,C);if(l.Outputs)for(let[A,w]of Object.entries(l.Outputs))Vg(A,w,f,C);return{valid:f.length===0,errors:f,warnings:C}}function Bg(l,f,C,A){if(!f.Type)C.push({path:`Resources.${l}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(l))A.push({path:`Resources.${l}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(f.Type&&!f.Type.startsWith("AWS::")&&!f.Type.startsWith("Custom::"))C.push({path:`Resources.${l}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(f.Properties){for(let[w,B]of Object.entries(f.Properties))if(B===void 0||B===null)A.push({path:`Resources.${l}.Properties.${w}`,message:"Property has undefined or null value",severity:"warning"})}if(f.DependsOn){if(typeof f.DependsOn==="string"){if(f.DependsOn===l)C.push({path:`Resources.${l}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(f.DependsOn)){if(f.DependsOn.includes(l))C.push({path:`Resources.${l}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function Wg(l,f,C,A){if(!f.Type)C.push({path:`Parameters.${l}.Type`,message:"Parameter Type is required",severity:"error"});let w=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(f.Type&&!w.includes(f.Type)&&!f.Type.startsWith("AWS::"))A.push({path:`Parameters.${l}.Type`,message:`Uncommon parameter type: ${f.Type}`,severity:"warning"});if(f.NoEcho&&f.Default)A.push({path:`Parameters.${l}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function Vg(l,f,C,A){if(!f.Value)C.push({path:`Outputs.${l}.Value`,message:"Output Value is required",severity:"error"})}function zg(l){let f={};for(let[v,ce]of Object.entries(l)){if(f[v]=[],ce.DependsOn){if(typeof ce.DependsOn==="string")f[v].push(ce.DependsOn);else if(Array.isArray(ce.DependsOn))f[v].push(...ce.DependsOn)}let de=Oc(ce);f[v].push(...de)}let C=new Set,A=new Set,w=[];function B(v,ce){C.add(v),A.add(v),ce.push(v);let de=f[v]||[];for(let ct of de)if(!C.has(ct)){if(B(ct,ce))return!0}else if(A.has(ct)){let xe=ce.indexOf(ct);return w.push(...ce.slice(xe),ct),!0}return ce.pop(),A.delete(v),!1}for(let v of Object.keys(f))if(!C.has(v)){if(B(v,[]))return w}return[]}function Oc(l,f=[]){if(typeof l!=="object"||l===null)return f;if(Array.isArray(l)){for(let C of l)Oc(C,f);return f}if(l.Ref&&typeof l.Ref==="string"&&!l.Ref.startsWith("AWS::"))f.push(l.Ref);if(l["Fn::GetAtt"]){let C=l["Fn::GetAtt"];if(Array.isArray(C)&&C.length>0)f.push(C[0])}for(let C of Object.values(l))Oc(C,f);return f}function Hg(l){let f=[],C=[],A=new TextEncoder().encode(l).length,w=51200,B=460800;if(A>51200)if(A>460800)f.push({path:"template",message:`Template size (${A} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else C.push({path:"template",message:`Template size (${A} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:f.length===0,errors:f,warnings:C}}function Ug(l){let f=[],C=[],A=l.Resources?Object.keys(l.Resources).length:0,w=l.Parameters?Object.keys(l.Parameters).length:0,B=l.Outputs?Object.keys(l.Outputs).length:0;if(A>500)f.push({path:"Resources",message:`Template has ${A} resources, exceeding the limit of 500`,severity:"error"});else if(A>200)C.push({path:"Resources",message:`Template has ${A} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(w>200)f.push({path:"Parameters",message:`Template has ${w} parameters, exceeding the limit of 200`,severity:"error"});if(B>200)f.push({path:"Outputs",message:`Template has ${B} outputs, exceeding the limit of 200`,severity:"error"});return{valid:f.length===0,errors:f,warnings:C}}function eR(l){let{domains:f,email:C,staging:A=!1,challengeType:w="http-01",certPath:B="/etc/letsencrypt/live",autoRenew:v=!0}=l,ce=f[0],de=f.map((xe)=>`-d ${xe}`).join(" "),ct=A?"--staging":"";if(w==="http-01")return Gg({domains:f,email:C,staging:A,certPath:B,autoRenew:v,domainFlags:de,stagingFlag:ct,primaryDomain:ce});else{let xe=l.dnsProvider?.provider||(l.hostedZoneId?"route53":void 0);return jg({domains:f,email:C,staging:A,certPath:B,autoRenew:v,domainFlags:de,stagingFlag:ct,primaryDomain:ce,hostedZoneId:l.hostedZoneId,dnsProvider:l.dnsProvider,dnsProviderType:xe})}}function Gg(l){let{email:f,certPath:C,autoRenew:A,domainFlags:w,stagingFlag:B,primaryDomain:v}=l;return`
|
|
223
223
|
# ==========================================
|
|
224
224
|
# Let's Encrypt Certificate Setup (HTTP-01)
|
|
225
225
|
# ==========================================
|
|
@@ -236,7 +236,7 @@ certbot certonly \\
|
|
|
236
236
|
--non-interactive \\
|
|
237
237
|
--agree-tos \\
|
|
238
238
|
--email ${f} \\
|
|
239
|
-
${
|
|
239
|
+
${B} \\
|
|
240
240
|
${w}
|
|
241
241
|
|
|
242
242
|
# Check if certificate was obtained
|
|
@@ -253,11 +253,11 @@ else
|
|
|
253
253
|
echo "Failed to obtain certificate!"
|
|
254
254
|
fi
|
|
255
255
|
|
|
256
|
-
${A?
|
|
256
|
+
${A?Nc(v):"# Auto-renewal disabled"}
|
|
257
257
|
|
|
258
258
|
# Restart the application
|
|
259
259
|
systemctl start stacks
|
|
260
|
-
`}function
|
|
260
|
+
`}function jg(l){let{email:f,certPath:C,autoRenew:A,domainFlags:w,stagingFlag:B,primaryDomain:v,hostedZoneId:ce,dnsProvider:de,dnsProviderType:ct}=l;if(ct==="route53"||ce){if(!ce)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
|
|
261
261
|
# ==========================================
|
|
262
262
|
# Let's Encrypt Certificate Setup (DNS-01 via Route53)
|
|
263
263
|
# ==========================================
|
|
@@ -271,7 +271,7 @@ certbot certonly \\
|
|
|
271
271
|
--non-interactive \\
|
|
272
272
|
--agree-tos \\
|
|
273
273
|
--email ${f} \\
|
|
274
|
-
${
|
|
274
|
+
${B} \\
|
|
275
275
|
${w}
|
|
276
276
|
|
|
277
277
|
# Check if certificate was obtained
|
|
@@ -288,8 +288,8 @@ else
|
|
|
288
288
|
echo "Failed to obtain certificate!"
|
|
289
289
|
fi
|
|
290
290
|
|
|
291
|
-
${A?
|
|
292
|
-
`}if(!de)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let xe=de.provider.toUpperCase(),
|
|
291
|
+
${A?Nc(v):"# Auto-renewal disabled"}
|
|
292
|
+
`}if(!de)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let xe=de.provider.toUpperCase(),Ut=Kg(de);return`
|
|
293
293
|
# ==========================================
|
|
294
294
|
# Let's Encrypt Certificate Setup (DNS-01 via ${xe})
|
|
295
295
|
# ==========================================
|
|
@@ -297,7 +297,7 @@ ${A?Ec(v):"# Auto-renewal disabled"}
|
|
|
297
297
|
# Install certbot
|
|
298
298
|
dnf install -y certbot jq curl
|
|
299
299
|
|
|
300
|
-
${
|
|
300
|
+
${Ut}
|
|
301
301
|
|
|
302
302
|
# Create DNS challenge hook scripts directory
|
|
303
303
|
mkdir -p /etc/letsencrypt/hooks
|
|
@@ -312,7 +312,7 @@ DOMAIN="$CERTBOT_DOMAIN"
|
|
|
312
312
|
VALIDATION="$CERTBOT_VALIDATION"
|
|
313
313
|
RECORD_NAME="_acme-challenge.$DOMAIN"
|
|
314
314
|
|
|
315
|
-
${
|
|
315
|
+
${qg(de)}
|
|
316
316
|
|
|
317
317
|
# Wait for DNS propagation
|
|
318
318
|
echo "Waiting 60 seconds for DNS propagation..."
|
|
@@ -331,7 +331,7 @@ DOMAIN="$CERTBOT_DOMAIN"
|
|
|
331
331
|
VALIDATION="$CERTBOT_VALIDATION"
|
|
332
332
|
RECORD_NAME="_acme-challenge.$DOMAIN"
|
|
333
333
|
|
|
334
|
-
${
|
|
334
|
+
${Yg(de)}
|
|
335
335
|
CLEANUPHOOK
|
|
336
336
|
|
|
337
337
|
chmod +x /etc/letsencrypt/hooks/cleanup-hook.sh
|
|
@@ -345,7 +345,7 @@ certbot certonly \\
|
|
|
345
345
|
--non-interactive \\
|
|
346
346
|
--agree-tos \\
|
|
347
347
|
--email ${f} \\
|
|
348
|
-
${
|
|
348
|
+
${B} \\
|
|
349
349
|
${w}
|
|
350
350
|
|
|
351
351
|
# Check if certificate was obtained
|
|
@@ -362,8 +362,8 @@ else
|
|
|
362
362
|
echo "Failed to obtain certificate!"
|
|
363
363
|
fi
|
|
364
364
|
|
|
365
|
-
${A?
|
|
366
|
-
`}function
|
|
365
|
+
${A?Nc(v):"# Auto-renewal disabled"}
|
|
366
|
+
`}function Kg(l){switch(l.provider){case"porkbun":return`
|
|
367
367
|
# Porkbun API credentials
|
|
368
368
|
export PORKBUN_API_KEY="${l.apiKey}"
|
|
369
369
|
export PORKBUN_SECRET_KEY="${l.secretKey}"
|
|
@@ -374,7 +374,7 @@ export GODADDY_API_SECRET="${l.apiSecret}"
|
|
|
374
374
|
export GODADDY_ENV="${l.environment||"production"}"
|
|
375
375
|
`;case"route53":return`
|
|
376
376
|
# Route53 uses IAM role credentials
|
|
377
|
-
`;default:return""}}function
|
|
377
|
+
`;default:return""}}function qg(l){switch(l.provider){case"porkbun":return`
|
|
378
378
|
# Extract root domain (last two parts)
|
|
379
379
|
ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
|
|
380
380
|
SUBDOMAIN="_acme-challenge"
|
|
@@ -418,7 +418,7 @@ curl -s -X PATCH "$API_URL/v1/domains/$ROOT_DOMAIN/records" \\
|
|
|
418
418
|
"data": "'"$VALIDATION"'",
|
|
419
419
|
"ttl": 600
|
|
420
420
|
}]'
|
|
421
|
-
`;default:return'echo "Unsupported DNS provider"'}}function
|
|
421
|
+
`;default:return'echo "Unsupported DNS provider"'}}function Yg(l){switch(l.provider){case"porkbun":return`
|
|
422
422
|
# Extract root domain, and the challenge's subdomain the way the auth hook did
|
|
423
423
|
ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
|
|
424
424
|
SUBDOMAIN="_acme-challenge"
|
|
@@ -470,7 +470,7 @@ fi
|
|
|
470
470
|
|
|
471
471
|
curl -s -X DELETE "$API_URL/v1/domains/$ROOT_DOMAIN/records/TXT/$RECORD_NAME" \\
|
|
472
472
|
-H "Authorization: sso-key $GODADDY_API_KEY:$GODADDY_API_SECRET"
|
|
473
|
-
`;default:return'echo "Unsupported DNS provider"'}}function
|
|
473
|
+
`;default:return'echo "Unsupported DNS provider"'}}function Nc(l){return`
|
|
474
474
|
# ==========================================
|
|
475
475
|
# Certificate Auto-Renewal Setup
|
|
476
476
|
# ==========================================
|
|
@@ -515,7 +515,7 @@ systemctl enable certbot-renewal.timer
|
|
|
515
515
|
systemctl start certbot-renewal.timer
|
|
516
516
|
|
|
517
517
|
echo "Certificate auto-renewal configured"
|
|
518
|
-
`}function
|
|
518
|
+
`}function tR(l){let{httpPort:f=80,httpsPort:C=443,certPath:A="/etc/ssl/stacks",redirectHttp:w=!0}=l;return`
|
|
519
519
|
// HTTPS Server with Let's Encrypt certificates
|
|
520
520
|
import { existsSync } from 'node:fs'
|
|
521
521
|
|
|
@@ -601,5 +601,5 @@ async function handleRequest(request: Request): Promise<Response> {
|
|
|
601
601
|
// Implement your request handling here
|
|
602
602
|
return new Response('Hello from Stacks!')
|
|
603
603
|
}
|
|
604
|
-
`}async function
|
|
605
|
-
`).filter((ce)=>!ce.startsWith("-----")).join(""),f=Buffer.from(l,"base64"),C=f.length-65,A=f.subarray(C+1,C+33),w=f.subarray(C+33,C+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(A),y:this.base64UrlEncode(w)}}getJwkThumbprint(){let l=this.getJwk(),f=JSON.stringify({crv:l.crv,kty:l.kty,x:l.x,y:l.y}),C=Fu("sha256").update(f).digest();return this.base64UrlEncode(C)}base64UrlEncode(l){return(typeof l==="string"?Buffer.from(l):l).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(l,f){let C=await this.getNonce(),A=this.getJwk(),w={alg:"ES256",nonce:C,url:l};if(this.accountUrl)w.kid=this.accountUrl;else w.jwk=A;let ce=this.base64UrlEncode(JSON.stringify(w)),v=f===""?"":this.base64UrlEncode(JSON.stringify(f)),B=`${ce}.${v}`,de=Bg("SHA256");de.update(B);let ct=de.sign(this.accountKey),xe=ct.subarray(4,4+ct[3]),Ht=4+ct[3]+2,Ut=ct.subarray(Ht,Ht+ct[Ht-1]),ut=Buffer.alloc(32),gt=Buffer.alloc(32);xe.copy(ut,32-xe.length),Ut.copy(gt,32-Ut.length);let lt=Buffer.concat([ut,gt]);return JSON.stringify({protected:ce,payload:v,signature:this.base64UrlEncode(lt)})}async acmeRequest(l,f){let C=await this.signPayload(l,f),A=await fetch(l,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:C}),w=A.headers.get("replay-nonce");if(w)this.nonce=w;let ce,v=A.headers.get("content-type");if(v?.includes("application/json")||v?.includes("application/problem+json"))ce=await A.json();else ce=await A.text();if(!A.ok)throw Error(`ACME request failed: ${JSON.stringify(ce)}`);return{body:ce,headers:A.headers}}async registerAccount(){let l=await this.getDirectory(),{body:f,headers:C}=await this.acmeRequest(l.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),A=C.get("location");if(!A)throw Error("No account URL returned");return this.accountUrl=A,A}async createOrder(l){if(!this.accountUrl)await this.registerAccount();let f=await this.getDirectory(),{body:C,headers:A}=await this.acmeRequest(f.newOrder,{identifiers:l.map((ce)=>({type:"dns",value:ce}))}),w=A.get("location");if(!w)throw Error("No order URL returned");return{orderUrl:w,authorizations:C.authorizations,finalize:C.finalize}}async getAuthorization(l){let{body:f}=await this.acmeRequest(l,""),C=f.identifier.value,A=this.getJwkThumbprint(),w=f.challenges.filter((ce)=>ce.type==="http-01"||ce.type==="dns-01").map((ce)=>{let v=`${ce.token}.${A}`;if(ce.type==="http-01")return{type:"http-01",token:ce.token,keyAuthorization:v,identifier:`/.well-known/acme-challenge/${ce.token}`};else{let B=this.base64UrlEncode(Fu("sha256").update(v).digest());return{type:"dns-01",token:ce.token,keyAuthorization:v,identifier:`_acme-challenge.${C}`,dnsValue:B}}});return{domain:C,challenges:w}}async respondToChallenge(l){await this.acmeRequest(l,{})}async waitForAuthorization(l,f=30){for(let C=0;C<f;C++){let{body:A}=await this.acmeRequest(l,"");if(A.status==="valid")return;if(A.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(A)}`);await new Promise((w)=>setTimeout(w,2000))}throw Error("Authorization timed out")}generateCsr(l){let{privateKey:f}=Mu("rsa",{modulusLength:2048}),C=f.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(l,f),privateKey:C}}createSimpleCsr(l,f){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(l,f){let{csr:C,privateKey:A}=this.generateCsr(f),{body:w}=await this.acmeRequest(l,{csr:this.base64UrlEncode(Buffer.from(C,"base64"))}),ce=w.certificate;if(!ce)throw Error("Certificate not immediately available - polling not implemented");let B=await(await fetch(ce)).text(),de=B.split(/(?=-----BEGIN CERTIFICATE-----)/g),ct=de[0],xe=de.slice(1).join("");return{certificate:ct,privateKey:A,chain:xe,fullchain:B,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var wn=(l)=>l===void 0?void 0:l?"on":"off";function Oc(l){let f={ssl:l.ssl,always_use_https:wn(l.alwaysUseHttps),automatic_https_rewrites:wn(l.automaticHttpsRewrites),min_tls_version:l.minTlsVersion,tls_1_3:wn(l.tls13),brotli:wn(l.brotli),http3:wn(l.http3),"0rtt":wn(l.zeroRtt),early_hints:wn(l.earlyHints),browser_cache_ttl:l.browserCacheTtl,always_online:wn(l.alwaysOnline),websockets:wn(l.websockets),email_obfuscation:wn(l.emailObfuscation)};if(l.hsts)f.security_header={strict_transport_security:{enabled:l.hsts.enabled,max_age:l.hsts.maxAge??31536000,include_subdomains:l.hsts.includeSubdomains??!1,preload:l.hsts.preload??!1,nosniff:l.hsts.noSniff??!0}};for(let C of Object.keys(f))if(f[C]===void 0)delete f[C];return{...f,...l.raw??{}}}var Ts={ssl:"strict",alwaysUseHttps:!0,automaticHttpsRewrites:!0,minTlsVersion:"1.2",tls13:!0,brotli:!0,http3:!0,earlyHints:!0,alwaysOnline:!0,emailObfuscation:!1,browserCacheTtl:0};import{connect as Mg}from"node:tls";async function Nc(l){let{address:f,serverName:C,port:A=443,timeoutMs:w=5000}=l;return new Promise((ce)=>{let v=!1,B=(ct)=>{if(v)return;v=!0;try{de.destroy()}catch{}ce(ct)},de=Mg({host:f,port:A,servername:C,rejectUnauthorized:!1,timeout:w});de.once("secureConnect",()=>{if(de.authorized){B({reachable:!0,trusted:!0});return}B({reachable:!0,trusted:!1,reason:de.authorizationError?String(de.authorizationError):"origin certificate is not trusted for this hostname"})}),de.once("timeout",()=>{B({reachable:!1,trusted:!1,reason:`no TLS handshake within ${w}ms`})}),de.once("error",(ct)=>{B({reachable:!1,trusted:!1,reason:ct.message})})})}function Wg(l,f){let C=f.replace(/\.$/,"").toLowerCase();return l.some((A)=>{let w=A.replace(/\.$/,"").toLowerCase();if(w===C)return!0;if(!w.startsWith("*."))return!1;let ce=w.slice(2);if(!C.endsWith(`.${ce}`))return!1;return!C.slice(0,C.length-ce.length-1).includes(".")})}async function Vg(l){let{provider:f,zone:C,hosts:A,ipv4:w,ipv6:ce,proxied:v=!0,settings:B=Ts,cache:de,originGuard:ct,purge:xe=!0,ttl:Ht=300,skipOriginProbe:Ut=!1,skipEdgeCertificateCheck:ut=!1}=l,gt={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(A.length===0)return gt;let lt=[],Ee=v&&!ut?await f.listEdgeCertificateHosts(C):null;for(let ve of A){let Pt=v;if(Pt&&Ee&&!Wg(Ee,ve)){Pt=!1;let lr=Ee.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${Ee.join(", ")})`;gt.deferredProxy.push({host:ve,reason:lr}),gt.warnings.push(`${ve}: publishing DNS-only — ${lr}. Proxying it would make Cloudflare terminate TLS with no certificate for the name, which fails the handshake outright rather than degrading. Universal SSL covers the apex and ONE level of subdomain, so a deeper name needs its own certificate; otherwise re-run the deploy once the certificate is active.`)}if(Pt&&!Ut){let lr=await Nc({address:w,serverName:ve});if(!lr.trusted){Pt=!1;let Cr=lr.reason||"origin is not serving a trusted certificate";gt.deferredProxy.push({host:ve,reason:Cr}),gt.warnings.push(`${ve}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${Cr}). The origin issues certificates over HTTP-01, which needs the name to reach it directly; re-run the deploy once it has one and the record will be proxied.`)}}if(Pt)lt.push(ve);let Ft=[{type:"A",content:w}];if(ce&&Un(ve))Ft.push({type:"AAAA",content:ce});for(let{type:lr,content:Cr}of Ft){let br=await f.upsertRecord(C,{name:ve,type:lr,content:Cr,ttl:Ht,proxied:Pt});if(br.success)gt.records.push({host:ve,type:lr,content:Cr,proxied:Pt});else gt.warnings.push(`${ve} ${lr} → ${Cr} failed: ${br.message||"unknown provider error"}`)}}if(lt.length===0){if(v)gt.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return gt}try{let ve=Oc(B),Pt=await f.applyZoneSettings(C,ve);gt.settingsChanged=Pt.changed;for(let Ft of Pt.failed)gt.warnings.push(`zone setting '${Ft.id}' could not be applied: ${Ft.error}`)}catch(ve){gt.warnings.push(`zone settings could not be read: ${ve instanceof Error?ve.message:String(ve)}`)}let Qt=uc(lt,de);if(Qt.length>0){let ve=await f.putManagedPhaseRules(C,"http_request_cache_settings",Qt);if(ve.success)gt.cacheRules=Qt.length;else gt.warnings.push(`cache rules could not be written: ${ve.message}`)}if(ct){let ve=gc(lt,ct.header,ct.value);if(ve.length>0){let Pt=await f.putManagedPhaseRules(C,"http_request_late_transform",ve);if(Pt.success)gt.originGuard=!0;else gt.warnings.push(`origin guard header could not be written: ${Pt.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(xe){if(gt.purged=await f.purgeCache(C,{hosts:lt}),!gt.purged)gt.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return gt}var zg=(l)=>process.env[l];function qu(l,f){let C=l.replace(/\.$/,"").toLowerCase();if(f){let A=f.replace(/\.$/,"").toLowerCase();if(C===A||C.endsWith(`.${A}`))return A}return C.split(".").slice(-2).join(".")}function Hg(l,f={}){let C=f.env??zg,A=l.infrastructure?.compute?.proxy?.cdn,w=[];if(!A||A.provider!=="cloudflare")return{plan:null,errors:w};if(A.originDomain)w.push(`compute.proxy.cdn.originDomain (${A.originDomain}) is ignored for Cloudflare: the proxy forwards to the address in the record it fronts, `+"so no separate origin hostname is needed — and publishing one gives clients a documented way around the edge.");let ce=C("CLOUDFLARE_API_TOKEN");if(!ce)return w.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:w};let v=l.sites??{},B=A.frontedHosts?.length?[...new Set(A.frontedHosts.map((Ut)=>Ut.toLowerCase()))]:qn(v,{autoWww:l.infrastructure?.compute?.proxy?.autoWww!==!1});if(B.length===0)return w.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:w};let de=l.infrastructure?.dns?.domain,ct=new Set(B.map((Ut)=>qu(Ut,de)));if(ct.size>1)return w.push(`Fronted hosts span more than one zone (${[...ct].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:w};let xe=A.cloudflare??{},Ht=A.secret?{header:A.secretHeader??"X-Origin-Verify",value:A.secret}:void 0;return{plan:{zone:[...ct][0],hosts:B,apiToken:ce,zoneId:xe.zoneId??C("CLOUDFLARE_ZONE_ID"),accountId:xe.accountId??C("CLOUDFLARE_ACCOUNT_ID"),proxied:xe.proxied!==!1,settings:xe.settings??Ts,cache:xe.cache,originGuard:Ht,purge:xe.purgeOnDeploy!==!1,skipOriginProbe:xe.skipOriginProbe===!0},errors:w}}var Ug=26214400;var jg=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class Wf{name="cloudflare-pages";apiToken;accountId;constructor(l){if(!l.apiToken)throw Error("Cloudflare Pages needs an API token");if(!l.accountId)throw Error("Cloudflare Pages needs an account id");this.apiToken=l.apiToken,this.accountId=l.accountId}async request(l,f,C){return sc(l,`/accounts/${this.accountId}${f}`,`Bearer ${this.apiToken}`,C)}async getProject(l){try{return await this.request("GET",`/pages/projects/${l}`)}catch(f){if(f instanceof Error&&/\b8000007\b|not found/i.test(f.message))return null;throw f}}async ensureProject(l,f="main"){let C=await this.getProject(l);if(C)return C;return this.request("POST","/pages/projects",{name:l,production_branch:f})}async uploadToken(l){return(await this.request("GET",`/pages/projects/${l}/upload-token`)).jwt}async missingHashes(l,f){let C=await sc("POST","/pages/assets/check-missing",`Bearer ${l}`,{hashes:f});return new Set(C)}async upsertHashes(l,f){await sc("POST","/pages/assets/upsert-hashes",`Bearer ${l}`,{hashes:f})}async uploadBatch(l,f){let C=f.map((A)=>({key:A.hash,value:A.base64,metadata:{contentType:Kg(A.extension)},base64:!0}));await sc("POST","/pages/assets/upload",`Bearer ${l}`,C)}async createDeployment(l,f,C){let A={};for(let ce of f)A[ce.path]=ce.hash;let w=new FormData;if(w.append("manifest",JSON.stringify(A)),C)w.append("branch",C);return this.request("POST",`/pages/projects/${l}/deployments`,w)}async deployDirectory(l){let f=await zf(l.directory);if(f.length===0)throw Error(`No files to deploy in ${l.directory}`);let C=await this.uploadToken(l.project),A=await this.missingHashes(C,f.map((de)=>de.hash)),w=f.filter((de)=>A.has(de.hash)),ce=[];for(let de=0;de<w.length;de+=100)ce.push(w.slice(de,de+100));let v=0;for(let de=0;de<ce.length;de+=4){let ct=ce.slice(de,de+4);await Promise.all(ct.map((xe)=>this.uploadBatch(C,xe))),v+=ct.reduce((xe,Ht)=>xe+Ht.length,0),l.onProgress?.(v,w.length)}return await this.upsertHashes(C,f.map((de)=>de.hash)),{deployment:await this.createDeployment(l.project,f,l.branch),total:f.length,uploaded:w.length,uploadedBytes:w.reduce((de,ct)=>de+ct.size,0)}}async listCustomDomains(l){return(await this.request("GET",`/pages/projects/${l}/domains`)).map((C)=>C.name)}async attachCustomDomain(l,f){if((await this.listCustomDomains(l)).includes(f))return!1;return await this.request("POST",`/pages/projects/${l}/domains`,{name:f}),!0}}function Gg(l,f){return{type:"CNAME",name:l,value:f.endsWith(".pages.dev")?f:`${f}.pages.dev`,ttl:1,proxied:!0}}async function Vf(l,f){let{blake3:C}=await import("./chunk-7eaech9q.js").then((m)=>aS(m.default,1));return(await C(l+f)).slice(0,32)}async function zf(l){let{readdir:f}=await import("node:fs/promises"),{join:C,relative:A,sep:w}=await import("node:path"),ce=[];async function v(B){let de=await f(B,{withFileTypes:!0});for(let ct of de){let xe=C(B,ct.name);if(ct.isDirectory()){await v(xe);continue}if(!ct.isFile())continue;let Ht=`/${A(l,xe).split(w).join("/")}`;if(jg.has(Ht))continue;let Ut=await Bun.file(xe).bytes();if(Ut.byteLength>26214400)throw Error(`${Ht} is ${Ut.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let ut=Buffer.from(Ut).toString("base64"),gt=ct.name.lastIndexOf("."),lt=gt>0?ct.name.slice(gt+1):"";ce.push({path:Ht,hash:await Vf(ut,lt),base64:ut,extension:lt,size:Ut.byteLength})}}return await v(l),ce.sort((B,de)=>B.path.localeCompare(de.path)),ce}function Kg(l){return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",mjs:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",map:"application/json; charset=utf-8",xml:"application/xml; charset=utf-8",txt:"text/plain; charset=utf-8",svg:"image/svg+xml",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",avif:"image/avif",ico:"image/x-icon",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",pdf:"application/pdf",webmanifest:"application/manifest+json"}[l.toLowerCase()]||"application/octet-stream"}async function sc(l,f,C,A){let w={Authorization:C},ce;if(A instanceof FormData)ce=A;else if(A!==void 0)w["Content-Type"]="application/json",ce=JSON.stringify(A);let v=await fetch(`https://api.cloudflare.com/client/v4${f}`,{method:l,headers:w,body:ce}),B=await v.text(),de;try{de=JSON.parse(B)}catch{throw Error(`Cloudflare Pages API returned ${v.status} with a non-JSON body: ${B.slice(0,200)}`)}if(!de.success){let ct=(de.errors??[]).map((xe)=>`${xe.code}: ${xe.message}`).join(", ");throw Error(`Cloudflare Pages API error (${v.status}): ${ct||B.slice(0,200)}`)}return de.result}import{createHash as qg}from"node:crypto";var Gf="https://api.cloudflare.com/client/v4",Kf=10042,Yg=10006,Xg=10059;class ti extends Error{status;errors;constructor(l,f,C=[]){super(l);this.name="R2ApiError",this.status=f,this.errors=C}hasCode(l){return this.errors.some((f)=>f.code===l)}}class jn extends ti{accountId;constructor(l,f,C=[]){super(`R2 is not enabled on Cloudflare account ${l}. Enable it once in the Cloudflare dashboard (R2 Object Storage, then follow the prompt to activate it), then re-run the deploy.`,f,C);this.name="R2NotEnabledError",this.accountId=l}}class Si{name="cloudflare-r2";apiToken;accountId;fetchImpl;constructor(l){if(!l.apiToken)throw Error("Cloudflare R2 needs an API token");if(!l.accountId)throw Error("Cloudflare R2 needs an account id");this.apiToken=l.apiToken,this.accountId=l.accountId,this.fetchImpl=l.fetch??((f,C)=>fetch(f,C))}async requestEnvelope(l,f,C,A={}){let w={Authorization:`Bearer ${this.apiToken}`};if(C!==void 0)w["Content-Type"]="application/json";if(A.jurisdiction&&A.jurisdiction!=="default")w["cf-r2-jurisdiction"]=A.jurisdiction;let ce=await this.fetchImpl(`${Gf}/accounts/${this.accountId}/r2${f}`,{method:l,headers:w,body:C===void 0?void 0:JSON.stringify(C)}),v=await ce.text(),B;try{B=JSON.parse(v)}catch{throw new ti(`Cloudflare R2 API returned ${ce.status} with a non-JSON body: ${v.slice(0,200)}`,ce.status)}if(!B.success){let de=B.errors??[];if(de.some((xe)=>xe.code===Kf))throw new jn(this.accountId,ce.status,de);let ct=de.map((xe)=>`${xe.code}: ${xe.message}`).join(", ");throw new ti(`Cloudflare R2 API error (${ce.status}) on ${l} ${f}: ${ct||v.slice(0,200)}`,ce.status,de)}return B}async request(l,f,C,A){return(await this.requestEnvelope(l,f,C,A)).result}bucketPath(l){return`/buckets/${encodeURIComponent(l)}`}async listBuckets(l={}){let f=[],C;do{let A=new URLSearchParams({per_page:"1000"});if(C)A.set("cursor",C);let w=await this.requestEnvelope("GET",`/buckets?${A}`,void 0,l),ce=w.result?.buckets??[];f.push(...ce),C=ce.length>0?w.result_info?.cursor||void 0:void 0}while(C);return f}async getBucket(l,f={}){try{return await this.request("GET",this.bucketPath(l),void 0,f)}catch(C){if(C instanceof jn)throw C;if(C instanceof ti&&(C.hasCode(Yg)||C.status===404))return null;throw C}}async ensureBucket(l,f={}){let C={jurisdiction:f.jurisdiction},A=await this.getBucket(l,C);if(A)return{bucket:A,created:!1};let w={name:l};if(f.locationHint)w.locationHint=f.locationHint;let ce=await this.request("POST","/buckets",w,C);return{bucket:{...ce,name:ce?.name||l},created:!0}}async getCors(l,f={}){try{return(await this.request("GET",`${this.bucketPath(l)}/cors`,void 0,f))?.rules??[]}catch(C){if(C instanceof ti&&!(C instanceof jn)&&(C.hasCode(Xg)||C.status===404))return[];throw C}}async putCors(l,f,C={}){if(f.length===0){await this.request("DELETE",`${this.bucketPath(l)}/cors`,void 0,C);return}await this.request("PUT",`${this.bucketPath(l)}/cors`,{rules:f},C)}async ensureCors(l,f,C={}){let A=await this.getCors(l,C);if(ac(A,f))return!1;return await this.putCors(l,f,C),!0}async getLifecycle(l,f={}){return(await this.request("GET",`${this.bucketPath(l)}/lifecycle`,void 0,f))?.rules??[]}async putLifecycle(l,f,C={}){await this.request("PUT",`${this.bucketPath(l)}/lifecycle`,{rules:f},C)}async ensureLifecycle(l,f,C={}){let A=await this.getLifecycle(l,C);if(yc(A,f))return!1;return await this.putLifecycle(l,f,C),!0}async listCustomDomains(l,f={}){return(await this.request("GET",`${this.bucketPath(l)}/domains/custom`,void 0,f))?.domains??[]}async attachCustomDomain(l,f,C={}){return this.request("POST",`${this.bucketPath(l)}/domains/custom`,{domain:f.domain,zoneId:f.zoneId,enabled:f.enabled??!0,minTLS:f.minTLS??"1.2"},C)}async updateCustomDomain(l,f,C,A={}){return this.request("PUT",`${this.bucketPath(l)}/domains/custom/${encodeURIComponent(f)}`,C,A)}async ensureCustomDomain(l,f,C={},A){let w=f.minTLS??"1.2",v=(A??await this.listCustomDomains(l,C)).find((ct)=>ct.domain.toLowerCase()===f.domain.toLowerCase());if(!v){let ct=await this.attachCustomDomain(l,{...f,minTLS:w,enabled:!0},C);return{action:"attached",domain:{...ct,domain:ct?.domain||f.domain}}}let B=v.minTLS??"1.0";if(v.enabled&&B===w)return{action:"unchanged",domain:v};let de=await this.updateCustomDomain(l,v.domain,{enabled:!0,minTLS:w},C);return{action:"updated",domain:{...v,...de}}}async getManagedDomain(l,f={}){return this.request("GET",`${this.bucketPath(l)}/domains/managed`,void 0,f)}async setManagedDomain(l,f,C={}){let A=await this.getManagedDomain(l,C);if(A?.enabled===f)return{changed:!1,domain:A};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(l)}/domains/managed`,{enabled:f},C)}}}function qf(l){return`https://${l}.r2.cloudflarestorage.com`}async function Qg(l){let{apiToken:f,accountId:C}=l;if(!f)throw Error("r2S3Credentials needs an API token");if(!C)throw Error("r2S3Credentials needs an account id");let A=l.fetch??((v,B)=>fetch(v,B)),w=[],ce;for(let v of[`/accounts/${C}/tokens/verify`,"/user/tokens/verify"]){let B=await A(`${Gf}${v}`,{method:"GET",headers:{Authorization:`Bearer ${f}`}}),de=await B.json().catch(()=>null);if(B.ok&&de?.success&&de.result?.id){ce=de.result.id;break}let ct=de?.errors?.map((xe)=>`${xe.code}: ${xe.message}`).join(", ");w.push(`${v} -> ${B.status}${ct?` (${ct})`:""}`)}if(!ce)throw Error(`Could not verify the Cloudflare API token to derive R2 credentials: ${w.join("; ")}`);return{accessKeyId:ce,secretAccessKey:qg("sha256").update(f).digest("hex"),endpoint:qf(C),region:"auto"}}function ws(l){if(Array.isArray(l))return`[${l.map(ws).join(",")}]`;if(l&&typeof l==="object")return`{${Object.entries(l).filter(([,C])=>C!==void 0).sort(([C],[A])=>C.localeCompare(A)).map(([C,A])=>`${JSON.stringify(C)}:${ws(A)}`).join(",")}}`;return JSON.stringify(l)}function jf(l,f){let C=(A)=>A&&A.length>0?[...A].map(String).sort():void 0;return{id:f?l.id:void 0,allowed:{origins:C(l.allowed?.origins),methods:C(l.allowed?.methods?.map((A)=>A.toUpperCase())),headers:C(l.allowed?.headers?.map((A)=>A.toLowerCase()))},exposeHeaders:C(l.exposeHeaders?.map((A)=>A.toLowerCase())),maxAgeSeconds:l.maxAgeSeconds}}function ac(l,f){if(l.length!==f.length)return!1;return f.every((C,A)=>{let w=C.id!==void 0;return ws(jf(l[A],w))===ws(jf(C,w))})}function yc(l,f){if(l.length!==f.length)return!1;let C=(A)=>ws([...A].map((w)=>({...w,storageClassTransitions:w.storageClassTransitions?.length?w.storageClassTransitions:void 0})).sort((w,ce)=>w.id.localeCompare(ce.id)));return C(l)===C(f)}var eh="r2 cache",th=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function rh(l,f={}){let C=f.log??(()=>{}),A={buckets:[],warnings:[]},w=l.infrastructure?.r2??l.r2,ce=Object.entries(w?.buckets??{});if(ce.length===0)return C("R2: no buckets declared, skipping."),A;if(!f.apiToken||!f.accountId){let xe=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),Ht=`R2: ${ce.length} bucket(s) declared but ${xe} is not set, skipping.`;return C(Ht),A.warnings.push(Ht),A}let v=f.dryRun===!0,B=new Si({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),de=new M(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),ct=new Map;for(let[xe,Ht]of ce){let Ut=Ht?.name;if(!Ut||!th.test(Ut)){A.warnings.push(`R2: bucket '${xe}' has an invalid name '${Ut??""}' (3-63 chars: lowercase letters, digits, hyphens), skipping.`);continue}C(`R2: ${v?"checking":"reconciling"} bucket ${Ut}...`);let ut={name:Ut,changes:[],domains:[]};if(A.buckets.push(ut),await nh(Ht,{r2:B,cloudflare:de,dryRun:v,summary:ut,warnings:A.warnings,claimed:ct,log:C}),ut.changes.length===0)C(`R2: ${Ut} is in sync.`);else for(let gt of ut.changes)C(`R2: ${Ut}: ${gt}`)}return A}async function nh(l,f){let{r2:C,dryRun:A,summary:w,warnings:ce}=f,v=l.name,B={jurisdiction:l.jurisdiction},de=(ut,gt)=>{let lt=A?gt&&`would ${gt}`:ut;if(lt)w.changes.push(lt)},ct;if(A)ct=await C.getBucket(v,B)!==null;else{let{created:ut}=await C.ensureBucket(v,{locationHint:l.locationHint,jurisdiction:l.jurisdiction});if(ct=!0,ut)de("created","")}if(!ct)de("","create bucket");let xe=oh(l.customDomains);await Is(f,`cors on ${v}`,async()=>{if(!l.cors)return;if(!ct){de("cors updated","set cors");return}let ut=await C.getCors(v,B);if(ac(ut,l.cors))return;if(!A)await C.putCors(v,l.cors,B);de(l.cors.length===0?"cors removed":"cors updated",l.cors.length===0?"remove cors":"update cors")}),await Is(f,`lifecycle on ${v}`,async()=>{if(!l.lifecycle)return;let ut=l.lifecycle.map(tg);if(ct){let gt=await C.getLifecycle(v,B);if(yc(gt,ut))return}if(!A)await C.putLifecycle(v,ut,B);de("lifecycle updated","update lifecycle")}),await Is(f,`r2.dev URL on ${v}`,async()=>{let ut=l.publicDevUrl===!0;if(!ct){if(ut)de("r2.dev URL enabled","enable r2.dev URL");return}if((await C.getManagedDomain(v,B))?.enabled===ut)return;if(!A)await C.setManagedDomain(v,ut,B);de(ut?"r2.dev URL enabled":"r2.dev URL disabled",ut?"enable r2.dev URL":"disable r2.dev URL")});let Ht=[];if(xe.length>0&&ct)try{Ht=await C.listCustomDomains(v,B)}catch(ut){if(ut instanceof jn)throw ut;ce.push(`R2: could not list custom domains on ${v}: ${_c(ut)}`)}let Ut=new Map;for(let{domain:ut,minTLS:gt}of xe){let lt=f.claimed.get(ut);if(lt&<!==v){ce.push(`R2: ${ut} is declared on both ${lt} and ${v}; leaving it on ${lt}.`);continue}f.claimed.set(ut,v);let Ee=Ht.find((ve)=>ve.domain.toLowerCase()===ut),Qt=gt??"1.2";if(Ee&&Ee.enabled&&(Ee.minTLS??"1.0")===Qt){if(w.domains.push({domain:ut,status:Bc(Ee)}),Ee.zoneId)Ut.set(ut,Ee.zoneId);continue}await Is(f,`custom domain ${ut} on ${v}`,async()=>{if(Ee){if(!A)await C.updateCustomDomain(v,Ee.domain,{enabled:!0,minTLS:Qt},B);if(de(`custom domain ${ut} updated`,`update custom domain ${ut}`),w.domains.push({domain:ut,status:Bc({...Ee,enabled:!0})}),Ee.zoneId)Ut.set(ut,Ee.zoneId);return}let ve=await f.cloudflare.zoneIdFor(ut);if(Ut.set(ut,ve),!A)await C.ensureCustomDomain(v,{domain:ut,zoneId:ve,minTLS:Qt},B,Ht);de(`custom domain ${ut} attached`,`attach custom domain ${ut}`),w.domains.push({domain:ut,status:A?"not attached":"pending"})},()=>w.domains.push({domain:ut,status:"error"}))}if(l.cache&&xe.length>0)await ih(l,xe.map((ut)=>ut.domain).filter((ut)=>f.claimed.get(ut)===v),Ut,f,de)}async function ih(l,f,C,A,w){let ce=Zf(l.cache);if(!ce||f.length===0)return;let v=new Map;for(let B of f){let de=C.get(B);if(!de)try{de=await A.cloudflare.zoneIdFor(B)}catch(ct){A.warnings.push(`R2: could not resolve the zone for ${B}, cache rule skipped: ${_c(ct)}`);continue}v.set(de,[...v.get(de)??[],B])}for(let B of v.values()){let de={action:"set_cache_settings",description:`${Lt} ${eh}`,expression:`(${_t(B)})`,enabled:!0,action_parameters:ce};await Is(A,`cache rule for ${B.join(", ")}`,async()=>{let ct=await A.cloudflare.getPhaseRules(B[0],"http_request_cache_settings");if(eg(ct,de))return;if(!A.dryRun){let xe=await A.cloudflare.putManagedPhaseRules(B[0],"http_request_cache_settings",[de]);if(!xe.success)throw Error(xe.message||"cache rule write failed")}w(`cache rule updated for ${B.join(", ")}`,`update cache rule for ${B.join(", ")}`)})}}function Zf(l){if(l.edgeTtl===void 0&&l.browserTtl===void 0)return null;let f={cache:!0};if(l.edgeTtl!==void 0)f.edge_ttl={mode:"override_origin",default:l.edgeTtl};if(l.browserTtl!==void 0)f.browser_ttl={mode:"override_origin",default:l.browserTtl};return f}function eg(l,f){let C=$t(f.expression),A=_n(f.expression),w=(B)=>(B.description||"").startsWith(Lt),ce=(B)=>B.action===f.action&&B.description===f.description&&(B.enabled??!0)===(f.enabled??!0)&&_n(B.expression)===A&&Cc(B.action_parameters)===Cc(f.action_parameters),v=!1;for(let B of l){if(!w(B))continue;let de=$t(B.expression);if(!C.some((xe)=>de.includes(xe)))continue;if(ce(B)&&C.every((xe)=>de.includes(xe))&&!v){v=!0;continue}return!1}return v}function tg(l){let f={id:l.id,enabled:l.enabled??!0,conditions:{prefix:l.prefix??""}};if(l.expireAfterDays!==void 0)f.deleteObjectsTransition={condition:{type:"Age",maxAge:Lc(l.expireAfterDays)}};else if(l.expireOn!==void 0)f.deleteObjectsTransition={condition:{type:"Date",date:l.expireOn}};if(l.abortMultipartUploadsAfterDays!==void 0)f.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:Lc(l.abortMultipartUploadsAfterDays)}};if(l.infrequentAccessAfterDays!==void 0)f.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:Lc(l.infrequentAccessAfterDays)}}];return f}function Lc(l){return Math.round(l*86400)}function oh(l){let f=new Set,C=[];for(let A of l??[]){let w=typeof A==="string"?{domain:A}:A,ce=w.domain?.trim().replace(/\.$/,"").toLowerCase();if(!ce||f.has(ce))continue;f.add(ce),C.push({domain:ce,minTLS:w.minTLS})}return C}function Bc(l){if(!l.enabled)return"disabled";let f=l.status?.ownership,C=l.status?.ssl;if(f==="active"&&C==="active")return"active";for(let A of[f,C])if(A==="error"||A==="blocked"||A==="deactivated")return A;return"pending"}async function Is(l,f,C,A){try{await C()}catch(w){if(w instanceof jn)throw w;l.warnings.push(`R2: ${f} failed: ${_c(w)}`),A?.()}}function _c(l){return l instanceof Error?l.message:String(l)}function Cc(l){if(Array.isArray(l))return`[${l.map(Cc).join(",")}]`;if(l&&typeof l==="object")return`{${Object.entries(l).filter(([,C])=>C!==void 0).sort(([C],[A])=>C.localeCompare(A)).map(([C,A])=>`${JSON.stringify(C)}:${Cc(A)}`).join(",")}}`;return JSON.stringify(l)}import{basename as mh,extname as fh}from"node:path";import{createHash as sh}from"node:crypto";var ah="https://api.cloudflare.com/client/v4",Qn="TS_CLOUD_CONTENT_HASH",Vs="2025-09-01",Mc="application/javascript+module",ch=10007,lh=[1e4,9109];class ls extends Error{status;errors;constructor(l,f,C=[]){super(l);this.name="WorkersApiError",this.status=f,this.errors=C}hasCode(l){return this.errors.some((f)=>f.code===l)}}class Sc extends ls{permission;constructor(l,f,C,A=[]){super(`The Cloudflare API token is missing the "${l}" permission (${f}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,C,A);this.name="WorkersPermissionError",this.permission=l}}class Rc{name="cloudflare-workers";apiToken;accountId;fetchImpl;constructor(l){if(!l.apiToken)throw Error("Cloudflare Workers needs an API token");if(!l.accountId)throw Error("Cloudflare Workers needs an account id");this.apiToken=l.apiToken,this.accountId=l.accountId,this.fetchImpl=l.fetch??((f,C)=>fetch(f,C))}async request(l,f,C){let A={Authorization:`Bearer ${this.apiToken}`},w;if(C instanceof FormData)w=C;else if(C!==void 0)A["Content-Type"]="application/json",w=JSON.stringify(C);let ce=await this.fetchImpl(`${ah}/accounts/${this.accountId}/workers${f}`,{method:l,headers:A,body:w}),v=await ce.text(),B;try{B=JSON.parse(v)}catch{throw new ls(`Cloudflare Workers API returned ${ce.status} with a non-JSON body: ${v.slice(0,200)}`,ce.status)}if(!B.success){let de=B.errors??[],ct=de.map((xe)=>`${xe.code}: ${xe.message}`).join(", ");if(dh(ce.status,de))throw new Sc(ph(f),`${l} ${f} -> ${ce.status}${ct?`, ${ct}`:""}`,ce.status,de);throw new ls(`Cloudflare Workers API error (${ce.status}) on ${l} ${f}: ${ct||v.slice(0,200)}`,ce.status,de)}return B.result}scriptPath(l){return`/scripts/${encodeURIComponent(l)}`}async getSettings(l){try{return await this.request("GET",`${this.scriptPath(l)}/settings`)}catch(f){if(f instanceof Sc)throw f;if(f instanceof ls&&(f.hasCode(ch)||f.status===404))return null;throw f}}async getScript(l){return this.getSettings(l)}async uploadModuleScript(l,f){return this.request("PUT",this.scriptPath(l),ig(f))}async ensureModuleScript(l,f){let C=qs(f),A=await this.getSettings(l);if(A&&Tc(A,f,C))return{action:"unchanged",hash:C};return await this.uploadModuleScript(l,og(f,C)),{action:A?"updated":"created",hash:C}}async listCustomDomains(l={}){let f=new URLSearchParams;if(l.service)f.set("service",l.service);if(l.hostname)f.set("hostname",l.hostname);if(l.zoneId)f.set("zone_id",l.zoneId);let C=f.toString(),A=C?`?${C}`:"";return await this.request("GET",`/domains${A}`)??[]}async attachCustomDomain(l,f){let C={hostname:l,service:f.service,environment:f.environment??"production"};if(f.zoneId)C.zone_id=f.zoneId;return this.request("PUT","/domains",C)}async detachCustomDomain(l){await this.request("DELETE",`/domains/${encodeURIComponent(l)}`)}async ensureCustomDomain(l,f,C){let w=(C??await this.listCustomDomains({hostname:l})).find((v)=>v.hostname.toLowerCase()===l.toLowerCase());if(w&&w.service===f.service)return{action:"unchanged",domain:w};if(w)throw Error(`${l} is attached to the Worker '${w.service}'. Detach it there first (Workers & Pages, ${w.service}, Settings, Domains & Routes); ts-cloud does not move it.`);let ce=await this.attachCustomDomain(l,f);return{action:"attached",domain:{...ce,hostname:ce?.hostname||l}}}}function dh(l,f){if(f.some((C)=>lh.includes(C.code)))return!0;return(l===401||l===403)&&f.length===0}function ph(l){if(l.startsWith("/domains"))return"Workers Routes: Edit (zone, for Workers custom domains) and Workers Scripts: Edit (account)";return"Workers Scripts: Edit (account)"}function ig(l){if(!l.modules.some((A)=>A.name===l.mainModule))throw Error(`Worker main module '${l.mainModule}' is not one of the uploaded modules`);let f={main_module:l.mainModule,bindings:l.bindings??[],compatibility_date:l.compatibilityDate??Vs,compatibility_flags:l.compatibilityFlags??[],keep_bindings:["secret_text"]},C=new FormData;C.append("metadata",JSON.stringify(f));for(let A of l.modules)C.append(A.name,new Blob([A.content],{type:A.type}),A.name);return C}function qs(l){let f={mainModule:l.mainModule,modules:[...l.modules].sort((C,A)=>C.name.localeCompare(A.name)).map((C)=>({name:C.name,type:C.type,sha256:ng(C.content)})),bindings:[...l.bindings??[]].filter((C)=>C.name!==Qn).sort((C,A)=>C.name.localeCompare(A.name)),compatibilityDate:l.compatibilityDate??Vs,compatibilityFlags:[...l.compatibilityFlags??[]].sort()};return ng(Fc(f))}function og(l,f=qs(l)){return{...l,bindings:[...(l.bindings??[]).filter((C)=>C.name!==Qn),{type:"plain_text",name:Qn,text:f}]}}function Tc(l,f,C){let A=l.bindings??[],w=A.find((ce)=>ce.name===Qn&&ce.type==="plain_text");if(!w||w.text!==C)return!1;return(f.bindings??[]).every((ce)=>{let v=A.find((de)=>de.name===ce.name);if(!v||v.type!==ce.type)return!1;let B=ce.type==="r2_bucket"?"bucket_name":ce.type==="plain_text"?"text":void 0;return!B||v[B]===ce[B]})}function ng(l){return sh("sha256").update(l).digest("hex")}function Fc(l){if(Array.isArray(l))return`[${l.map(Fc).join(",")}]`;if(l&&typeof l==="object")return`{${Object.entries(l).filter(([,C])=>C!==void 0).sort(([C],[A])=>C.localeCompare(A)).map(([C,A])=>`${JSON.stringify(C)}:${Fc(A)}`).join(",")}}`;return JSON.stringify(l)}async function qc(l){if(!await Bun.file(l).exists())throw Error(`Worker entry not found: ${l}`);let f;try{f=await Bun.build({entrypoints:[l],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(w){throw Error(`Bundling Worker ${l} failed: ${gh(w)}`)}if(!f.success)throw Error(`Bundling Worker ${l} failed: ${f.logs.map((w)=>String(w.message??w)).join("; ")}`);if(f.outputs.length!==1)throw Error(`Bundling Worker ${l} produced ${f.outputs.length} files (${f.outputs.map((w)=>w.path).join(", ")}); a Worker is uploaded as a single module, so remove the dynamic imports or asset imports that split it.`);let C=f.outputs[0];if(C.kind!=="entry-point")throw Error(`Bundling Worker ${l} produced a ${C.kind} instead of an entry module`);let A=await C.text();return{name:`${mh(l,fh(l))}.js`,content:A,type:Mc,size:new TextEncoder().encode(A).byteLength}}function gh(l){if(l instanceof AggregateError&&l.errors.length>0)return l.errors.map((f)=>f instanceof Error?f.message:String(f?.message??f)).join("; ");return l instanceof Error?l.message:String(l)}import{isAbsolute as hh,resolve as yh}from"node:path";var Ch="https://api.cloudflare.com/client/v4",Sh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function Rh(l,f={}){let C=f.log??(()=>{}),A={workers:[],warnings:[]},w=Object.entries(l.infrastructure?.workers??l.workers??{});if(w.length===0)return C("Workers: none declared, skipping."),A;if(!f.apiToken||!f.accountId){let B=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),de=`Workers: ${w.length} Worker(s) declared but ${B} is not set, skipping.`;return C(de),A.warnings.push(de),A}let ce=l.infrastructure?.r2??l.r2,v={workers:new Rc({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),r2:new Si({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),cloudflare:new M(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),apiToken:f.apiToken,fetch:f.fetch??((B,de)=>fetch(B,de)),projectRoot:f.projectRoot??process.cwd(),dryRun:f.dryRun===!0,warnings:A.warnings,log:C,r2ConfigDomains:Dh(ce),r2Buckets:ce,claimed:new Map};for(let[B,de]of w){let ct=de?.name;if(!ct||!Sh.test(ct)){A.warnings.push(`Workers: '${B}' has an invalid name '${ct??""}' (1-63 chars: lowercase letters, digits, '-' and '_'), skipping.`);continue}if(!de.entry){A.warnings.push(`Workers: ${ct} has no entry, skipping.`);continue}C(`Workers: ${v.dryRun?"checking":"reconciling"} ${ct}...`);let xe={name:ct,changes:[],domains:[]};A.workers.push(xe),await bh(de,xe,v);for(let Ht of xe.changes)C(`Workers: ${ct}: ${Ht}`)}return A}async function bh(l,f,C){let A=l.name,w=hh(l.entry)?l.entry:yh(C.projectRoot,l.entry),ce;try{ce=await qc(w)}catch(B){throw Error(`Worker ${A}: ${gs(B)}`)}f.changes.push(`bundled ${vh(ce.size)}`);let v={mainModule:ce.name,modules:[{name:ce.name,content:ce.content,type:ce.type}],bindings:sg(l,C),compatibilityDate:l.compatibilityDate??Vs,compatibilityFlags:l.compatibilityFlags??[]};if(C.dryRun){let B=await C.workers.getSettings(A);f.changes.push(B&&Tc(B,v,qs(v))?"unchanged":"would upload")}else{let{action:B}=await C.workers.ensureModuleScript(A,v);f.changes.push(B==="unchanged"?"unchanged":"uploaded")}for(let B of Ih(l.customDomains))await Ah(A,B,f,C)}async function Ah(l,f,C,A){let w=(ut)=>{C.domains.push({domain:f,status:ut})},ce=(ut)=>{A.warnings.push(`Workers: ${ut}`),w("conflict")},v=A.claimed.get(f);if(v&&v!==l){ce(`${f} is declared on both ${v} and ${l}; leaving it on ${v}.`);return}A.claimed.set(f,l);let B=A.r2ConfigDomains.get(f);if(B){ce(`${f} is also declared as a custom domain of the R2 bucket '${B}' (r2.buckets). A hostname serves either a bucket or a Worker. Remove it from the bucket's customDomains and detach it in the dashboard (R2, ${B}, Settings, Custom Domains) first; to serve the bucket through the Worker, bind it with bindings.r2Buckets instead.`);return}let de=await Th(A);if(de===null){w("error");return}let ct=de.find((ut)=>ut.hostname.toLowerCase()===f);if(ct?.service===l){w("active");return}if(ct){ce(`${f} is attached to the Worker '${ct.service}'. Detach it there first (Workers & Pages, ${ct.service}, Settings, Domains & Routes); it is not moved automatically.`);return}let xe=(await Ph(A))?.get(f);if(xe){ce(`${f} is attached to the R2 bucket '${xe}' as a custom domain. Detach it first (R2, ${xe}, Settings, Custom Domains, then re-run the deploy); it is not detached automatically. To serve the bucket through the Worker, bind it with bindings.r2Buckets.`);return}let Ht;try{Ht=await A.cloudflare.zoneIdFor(f)}catch(ut){A.warnings.push(`Workers: could not resolve the zone for ${f}, not attached: ${gs(ut)}`),w("error");return}let Ut=await wh(A,Ht,f);if(Ut.length>0){let ut=Ut.map((gt)=>`${gt.type} ${gt.content}`).join(", ");ce(`${f} already has a DNS record (${ut}). A Worker custom domain creates its own record, so Cloudflare will not attach over it. Delete the record first (DNS, Records), then re-run the deploy; it is not deleted automatically.`);return}if(A.dryRun){C.changes.push(`would attach custom domain ${f}`),w("not attached");return}try{await A.workers.ensureCustomDomain(f,{service:l,zoneId:Ht},de),C.changes.push(`custom domain ${f} attached`),de.push({id:"",hostname:f,service:l,zone_id:Ht}),w("pending")}catch(ut){A.warnings.push(`Workers: custom domain ${f} on ${l} failed: ${gs(ut)}`),w("error")}}async function Th(l){if(l.attached!==void 0)return l.attached;try{l.attached=await l.workers.listCustomDomains()}catch(f){l.warnings.push(`Workers: could not list Worker custom domains, none attached: ${gs(f)}`),l.attached=null}return l.attached}async function Ph(l){if(l.r2AccountDomains!==void 0)return l.r2AccountDomains;let f=new Map;try{let C=(await l.r2.listBuckets()).map((A)=>({name:A.name}));for(let A of Object.values(l.r2Buckets?.buckets??{}))if(A.jurisdiction&&A.jurisdiction!=="default")C.push({name:A.name,jurisdiction:A.jurisdiction});for(let A of C){let w=await l.r2.listCustomDomains(A.name,{jurisdiction:A.jurisdiction}).catch(()=>[]);for(let ce of w)f.set(ce.domain.toLowerCase(),A.name)}l.r2AccountDomains=f}catch(C){l.log(`Workers: could not check R2 custom domains (${gs(C)}); relying on the DNS check.`),l.r2AccountDomains=null}return l.r2AccountDomains}async function wh(l,f,C){try{let A=await l.fetch(`${Ch}/zones/${f}/dns_records?name=${encodeURIComponent(C)}&per_page=100`,{method:"GET",headers:{Authorization:`Bearer ${l.apiToken}`}}),w=await A.json();if(!w?.success)throw Error(`HTTP ${A.status}`);return(w.result??[]).filter((ce)=>ce.name?.toLowerCase()===C).map((ce)=>({type:ce.type??"?",content:ce.content??""}))}catch(A){return l.log(`Workers: could not read DNS records for ${C} (${gs(A)}); attaching anyway.`),[]}}function sg(l,f){let C=[],A=new Set,w=(v)=>{if(v===Qn)return f.warnings.push(`Workers: ${l.name}: binding name ${Qn} is reserved for ts-cloud, ignored.`),!1;if(A.has(v))return f.warnings.push(`Workers: ${l.name}: binding ${v} is declared twice; the first one wins.`),!1;return A.add(v),!0},ce=new Map;for(let v of Object.values(f.r2Buckets?.buckets??{}))if(v.jurisdiction&&v.jurisdiction!=="default")ce.set(v.name,v.jurisdiction);for(let[v,B]of Object.entries(l.bindings?.r2Buckets??{})){if(!w(v))continue;let de=ce.get(B);C.push(de?{type:"r2_bucket",name:v,bucket_name:B,jurisdiction:de}:{type:"r2_bucket",name:v,bucket_name:B})}for(let[v,B]of Object.entries(l.bindings?.vars??{}))if(w(v))C.push({type:"plain_text",name:v,text:String(B)});return C}function Dh(l){let f=new Map;for(let C of Object.values(l?.buckets??{}))for(let A of C?.customDomains??[]){let w=mg(typeof A==="string"?A:A.domain);if(w)f.set(w,C.name)}return f}function Ih(l){return[...new Set((l??[]).map(mg).filter(Boolean))]}function mg(l){return(l??"").trim().replace(/\.$/,"").toLowerCase()}function vh(l){if(l<1024)return`${l} B`;if(l<1048576)return`${(l/1024).toFixed(1)} KB`;return`${(l/1024/1024).toFixed(1)} MB`}function gs(l){return l instanceof Error?l.message:String(l)}export{dl as ABTestManager,ge as ACMClient,Sr as ACMDnsValidator,ju as ACME_DIRECTORIES,Pe as AI,ql as API_IDEMPOTENCY_TTL_MS,Gl as API_TOKEN_DEFAULT_TTL_MS,Vl as API_TOKEN_MAX_TTL_MS,rs as API_VERSION,me as AUTHORIZATION_CAPABILITIES,Fl as AUTH_ACTION_TOKEN_TTL_MS,Ul as AUTH_MFA_CHALLENGE_TTL_MS,Ql as AUTH_OIDC_TRANSACTION_TTL_MS,Ye as AUTH_SESSION_ABSOLUTE_TTL_MS,Ml as AUTH_SESSION_IDLE_TTL_MS,YA as AWSAPIError,n as AWSClient,h as AWSCloudFormationClient,S as AWSCloudFrontClient,sl as AWSConfigManager,vI as AWS_PSEUDO_PARAMETERS,Ne as AWS_REGIONS,_g as AcmeClient,jr as AlertEvaluator,ki as AlertStore,po as AnomalyConfigStore,Kd as ApiGateway,i as ApiServiceError,oc as ApplicationAutoScalingClient,Yr as Arn,k as AssetHasher,q as Auth,Xi as AuthenticationStore,Li as AutomationApiService,Yi as AutomationIdentityStore,ma as AwsAuroraDataAdapter,Sa as AwsAuroraTransport,$a as AwsDatabaseBackupSource,vr as AwsDriver,fa as AwsElastiCacheDataAdapter,Ia as AwsElastiCacheTransport,wf as AwsIamCapabilityScanner,Ha as AwsInfrastructureBackupSource,pa as AwsRdsDataAdapter,ya as AwsRdsTransport,Ff as AwsRegionalDriver,Va as AwsSecretsManagerConfigurationBackend,Hp as AwsSpendTransport,qa as AwsSsmConfigurationBackend,ps as BackupCoordinator,nl as BackupManager,_a as BackupStore,ef as BatchProcessingManager,Nn as BedrockClient,Pn as BedrockRuntimeClient,Yl as BitbucketSourceAdapter,cl as BlueGreenManager,Vm as BounceComplaintHandler,_m as BuildOptimizationManager,Iu as BunDockerRuntime,Ju as BunDockerVolumeRuntime,Wu as BunFilesystemArchiveRuntime,he as CDN,Bo as CHAIN_HEADER,Lt as CLOUDFLARE_MANAGED_RULE_PREFIX,Gd as CLOUDFRONT_FAILOVER_STATUS_CODES,lC as COMMON_CROSS_ACCOUNT_ROLES,Qn as CONTENT_HASH_BINDING,Ge as CONTROL_PLANE_SCHEMA_VERSION,wo as Cache,Vi as CanaryManager,Bm as CertificateManager,dA as CloudBlockVolumeDriver,js as CloudDriverFactory,We as CloudError,sm as CloudFormationBuilder,h as CloudFormationClient,S as CloudFrontClient,ol as CloudTrailManager,Ie as CloudWatchLogsClient,Wf as CloudflarePagesProvider,M as CloudflareProvider,Sy as CommandHistory,z as Communication,Qr as ComposeApplicationService,zt as ComposeApplicationStore,kt as ComprehendClient,a as Compute,Gp as ComputeSpendTransport,Po as ConfigurationError,za as ConfigurationService,Ga as ConfigurationStore,Rn as ConnectClient,Aa as ContainerDataAdapter,ml as ContainerRegistryManager,Qa as ControlPlaneBackupSource,ka as ControlPlaneCleanupDriver,vi as ControlPlaneStore,lo as CounterTracker,Ct as CredentialError,Im as CrossRegionReferenceManager,MA as DASHBOARD_ENTRY,FA as DASHBOARD_PORT_BASE,UA as DASHBOARD_PORT_SPAN,$A as DASHBOARD_STATE_DIR,Qo as DEFAULT_ATTACK_MODE_HOURS,Vs as DEFAULT_COMPATIBILITY_DATE,Nd as DEFAULT_DDOS_THRESHOLDS,zp as DEFAULT_FAILOVER_STATUS_CODES,ud as DEFAULT_METER_MAPPINGS,dd as DEFAULT_PRICE_BOOK,rn as DEFAULT_RECURSION_LIMITS,Gn as DEFAULT_RPX_CERTS_DIR,K as DEFAULT_SERVICE_LIMITS,Od as DEFAULT_STATE_DIR,dg as DEFAULT_STATIC_ASSET_EXTENSIONS,xA as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,CA as DEFAULT_TELEMETRY_POLICY,wp as DEFAULT_THRESHOLDS,iA as DEPLOYMENT_QUEUE_KINDS,ko as DEPTH_HEADER,Vr as DETECTABLE_SIGNALS,fu as DIAGNOSTIC_PRESETS,Zm as DLQMonitoringManager,H as DNS,Hm as DNSSECManager,os as DataServiceLifecycle,ga as DataServiceStore,Yt as Database,Nm as DatabaseUserManager,U as DebugLogger,BA as DependencyGraph,j as Deployment,XA as DeploymentError,il as DisasterRecoveryManager,Mn as DnsProviderFactory,or as DockerDataTransport,oa as DockerDiscoveryAdapter,Ur as DockerNamedVolumeDriver,Ua as DockerVolumeBackupSource,c as DurableOperationQueue,ro as DurableQueueWorker,_e as DynamoDBClient,Br as EC2Client,$e as ECRClient,nt as ECSClient,fr as EFSClient,rc as ELBv2Client,uA as ENFORCEMENT_ACTIONS,Pi as ENFORCEMENT_DESCRIPTIONS,N as ENFORCEMENT_SEVERITY,ep as ENVIRONMENT_LABEL,pu as EcsRuntimeAdapter,Uo as EdgeRateLimiter,st as ElastiCacheClient,m as Email,Km as EmailAdvanced,qm as EmailAnalyticsManager,On as EmailClient,Wm as EmailHandlers,zm as EmailTemplateManager,ba as EncryptedDataSecretStore,ZA as ErrorCodes,pr as EventBridgeClient,Lf as EventBridgeJobAdapter,ja as ExternalConfigurationBackend,To as FAILOVER_REPLICA_POLICY_SID,Ym as FIFOQueueManager,Op as FOCUS_VERSION,Xd as FileCache,ze as FileSystem,Ma as FilesystemBackupSource,Ea as FleetService,Ca as FleetStore,e as Fn,Zl as GiteaSourceAdapter,Jl as GithubSourceAdapter,Xl as GitlabSourceAdapter,bm as GlobalResourceManager,Me as GoDaddyProvider,al as GuardDutyManager,pt as HOST_SITES_DIR,ny as HashCache,pf as HealthCheckManager,qe as HealthCheckRunner,Dr as HetznerClient,Te as HetznerDriver,be as IAMClient,hc as IPV6_EXCLUDED_HOST_LABELS,Om as ImageScanningManager,Rg as InfrastructureGenerator,Yc as InvalidOperationTransitionError,It as JobLoader,$f as JobProviderReconciler,ua as JobService,da as JobStore,gr as KendraClient,uf as LARAVEL_SERVERLESS_BUILD_STEPS,E as LambdaClient,Mm as LambdaConcurrencyManager,Qm as LambdaDLQManager,Fm as LambdaDestinationsManager,Lm as LambdaLayersManager,mu as LambdaRuntimeAdapter,Um as LambdaVPCManager,$m as LambdaVersionsManager,Cn as LocalEncryptedConfigurationBackend,Fa as LogicalDatabaseBackupSource,ul as LogsManager,Uy as MANAGED_NODE_VERSIONS,Uc as MANAGEMENT_DASHBOARD_SITE,om as MANAGEMENT_DASHBOARD_SITE_PREFIX,Wi as MAX_CONTROL_HOURS,Zc as MAX_CONTROL_PLANE_ERROR_BYTES,bp as MAX_CONTROL_PLANE_JSON_BYTES,oo as METERS,lA as METER_KEYS,gA as MICRO_CENTS,Rp as MIN_PROJECTION_CONFIDENCE,pg as MTA_STS_PORT,Na as MaintenanceService,Pa as MaintenanceStore,ie as Messaging,Rm as MetricsManager,Dm as MigrationManager,fm as MockCloudFormation,Am as MockDynamoDB,hm as MockS3,Ro as Monitoring,vm as MultiAccountManager,Sm as MultiRegionManager,py as MultiStepProgress,y as Network,mf as NetworkSecurityManager,Bi as NotificationRouter,Jp as ORIGIN_CONNECTION_ATTEMPTS,Xp as ORIGIN_CONNECTION_TIMEOUT,Kp as ORIGIN_GROUP_ALLOWED_METHODS,bI as ORIGIN_GROUP_ID_SUFFIX,Wp as ORIGIN_GROUP_SELECTION_CRITERIA,nc as OpenSearchClient,mt as OptimisticConcurrencyError,Tm as OrganizationManager,Ug as PAGES_MAX_FILE_BYTES,Jy as PHP_DEFAULT_EXCLUDES,Qy as PHP_LAYER_EXTENSIONS,Zg as PROJECT_LABEL,at as PROXIABLE_RECORD_TYPES,T as ParameterStore,Pm as PerformanceManager,ne as Permissions,ic as PersonalizeClient,Ke as Phone,Jm as PhoneAdvanced,nm as PhoneHandlers,Ta as PlacementService,va as PlacementStore,kn as PollyClient,le as PorkbunProvider,un as PreDeployScanner,tl as PreviewEnvironmentManager,Fr as PreviewEnvironmentService,Ve as PreviewEnvironmentStore,rl as PreviewNotificationService,gy as ProgressBar,ll as ProgressiveDeploymentManager,Ho as ProtectionControlStore,kA as Pseudo,G as Queue,Ti as QueueCancellationError,tf as QueueManagementManager,dI as QueuePresets,to as QueueTimeoutError,ti as R2ApiError,jn as R2NotEnabledError,Si as R2Provider,Kf as R2_NOT_ENABLED_ERROR_CODE,Nl as RATE_LIMIT_KEY_SEPARATOR,J as RDSClient,by as RECOMMENDED_ACCOUNT_STRUCTURES,dC as RECOMMENDED_SCPS,Cf as RELEASE_QUEUE_KINDS,hy as REPL,yy as REPLCommandBuilder,Ay as REPLContext,tp as ROLE_LABEL,iy as RateLimiter,lI as RealtimePresets,_p as RecordingSpendTransport,ji as RecursionGuard,bt as Redirects,Cm as RegionPairManager,Ra as RegionService,wa as RegionStore,je as Registry,Bt as RekognitionClient,Et as ReleaseService,Xo as ReleaseStore,Mf as RemoteBuildService,gl as ReplicaManager,ff as ResourceManagementManager,te as RetryableOperationError,I as Route53Client,tc as Route53DomainsClient,X as Route53Provider,Gm as Route53ResolverManager,hl as Route53RoutingManager,ye as RuntimeOperationService,ca as RuntimeStreamRegistry,La as S3BackupDestinationAdapter,o as S3Client,F as S3Error,ru as SECRET_PATTERNS,Bp as SENSITIVITY_THRESHOLDS,ot as SESClient,V as SMS,it as SNSClient,Qp as SPEND_CYCLE_SECONDS,vd as SPEND_GATE_SETTING,wA as SPEND_LEASE_SETTING,ae as SQSClient,we as SSH_BOOTSTRAP_VERSION,si as SSH_PREFLIGHT_SCRIPT,Re as SSMClient,qp as STATE_DIR_ENV_VAR,Ts as STATIC_SITE_ZONE_SETTINGS,qd as STORAGE_FAILOVER_METADATA_KEY,Se as STSClient,Bn as SchedulerClient,Zt as Search,gn as SecretFindingScanner,Ui as Secrets,pl as SecretsManager,W as SecretsManagerClient,km as SecretsRotationManager,b as Security,tr as SecurityHubManager,ln as SecurityPostureStore,vt as SecurityScannerRunner,xm as SecurityScanningManager,jm as SenderReputationManager,_f as ServerCronJobAdapter,ha as ServerDataAdapter,so as ServerPathVolumeDriver,fl as ServiceMeshManager,zd as Sftp,fo as SignalSource,Xm as SmsAdvanced,Ot as SmsClient,im as SmsHandlers,dc as SmsVoiceClient,Yo as SourceConnectionStore,ir as SourceProviderError,Td as SpendCapError,qr as SpendGate,Fp as SpendLoopLease,Io as SpendNotificationRouter,Up as SpendRunner,Wt as SpendService,Ri as SpendStore,my as Spinner,Nr as SshDriver,fn as SshFleetDriver,Em as StackDependencyManager,EI as StacksIntegration,gf as StaticSiteManager,De as Storage,Rl as StorageAdvancedManager,xn as SupportClient,rr as SyntheticsManager,bu as SystemFleetSshTransport,Pr as SystemSshTransport,aa as SystemdDiscoveryAdapter,xo as TRACE_HEADER,fy as TaskList,At as TelemetryStore,Qd as TemplateBuilder,Yd as TemplateCache,xt as TextractClient,Dn as TranscribeClient,ur as TranslateClient,Hf as TransportDisasterRecoveryDriver,Qf as TransportPlatformMaintenanceDriver,as as TransportRemoteBuildDriver,ia as TrivyImageScanner,Jo as TsCloudApiError,jl as TsCloudClient,TA as URGENT_SPEND_EVENTS,Dp as USER_VISIBLE_ACTIONS,Da as UnavailableRegionalDriver,ue as UnifiedDnsValidator,Ys as UnsupportedSchemaVersionError,lm as ValidationError,mr as VoiceClient,io as VolumeService,jt as VolumeStore,Mc as WORKER_MODULE_TYPE,ls as WorkersApiError,Sc as WorkersPermissionError,Rc as WorkersProvider,LA as Workflow,wm as XRayManager,Ny as abTestManager,zl as activateImmutableRelease,Ng as addDns01ChallengeRecord,An as addSiteToCloudConfig,wt as ageSeconds,pd as aggregateDeltas,yp as allocateSitePorts,rm as amazonLinuxImageId,_A as amazonLinuxImageParameter,SI as analyzeStackDiff,Ni as anomalyOptionsForSignal,Go as applyControlsToDdos,_l as applyControlsToRateLimits,Bs as applyDeclaredZoneSettings,Wr as applyMitigationFactor,Fh as applyPlan,Ls as applyZoneMigration,Al as artifactKey,yt as assertOriginGroupMethods,Zi as assertReleaseStrategy,bA as assertSpendAllows,Vh as attachConflicts,qh as attachIsViable,Gh as attachPreconditions,au as attachProvenanceToRelease,sa as attachSbomToRelease,su as attachVulnerabilitySummary,If as authEncryptionKeyFile,P as authorizeOrganization,xf as authorizeRuntimePath,Fb as autocomplete,vy as awsConfigManager,zu as backupCredentialStatus,Cy as backupManager,lb as batch,eE as batchProcessingManager,Ko as beginOidcAuthorization,Dy as blueGreenManager,KC as bounceComplaintHandler,ft as budgetWindow,Ya as buildAndPushServerlessImage,nE as buildBunRuntimeLayerZip,Xh as buildCertificatePackScript,Kh as buildCertificateStateScript,Yh as buildCertificateUnpackScript,Wd as buildCloudFormationTemplate,xc as buildCloudInitFirstBoot,nd as buildComposeLogsCommand,aI as buildComposeRuntimeCommand,cI as buildComposeScaleCommand,id as buildComposeShellCommand,fp as buildDrainSourceScript,Nh as buildDrainedSiteScanScript,jd as buildFailoverReplicaPolicyStatement,cr as buildFunctionEnv,mp as buildHealthGateScript,Xn as buildHostCleanupDeployScript,Gs as buildHostCleanupInstallScript,Jn as buildHostCleanupScript,Ci as buildHostSitePortsScript,Ud as buildMailEnv,Ks as buildManagementDashboardArtifact,TS as buildMediaCdnPlan,gg as buildMtaStsPolicy,uh as buildMtaStsServer,rE as buildNodeRuntimeLayerZip,FC as buildOptimizationManager,Vd as buildOriginGroup,Xr as buildOriginGroups,gc as buildOriginGuardRule,ap as buildPauseWorkersScript,aE as buildPhpRuntimeLayerZip,tm as buildReplicationConfiguration,em as buildReplicationRole,up as buildRestoreScript,Y as buildRpxConfig,Fe as buildRpxFragmentRefreshScript,Qh as buildSetHostnameScript,Zn as buildSiteDeployScript,lp as buildSnapshotScript,hp as buildSourceStateScript,zn as buildSshArgs,ni as buildSshBootstrapScript,uc as buildStaticSiteCacheRules,ei as buildStaticSiteDeployScript,gp as buildTargetStateScript,ig as buildUploadForm,cp as buildWorkersStateScript,qc as bundleWorker,du as bytes,Zf as cacheRuleParameters,Py as canaryManager,hn as canonicalJson,Tt as capabilities,ar as capacity,Sb as categorizeChanges,LC as certificateManager,Jh as certificatesMatch,eb as checkIAMPermissions,af as checkInvocation,rb as checkServiceQuotas,sy as chunk,WS as cleanupDns01Challenge,nS as clearSigningKeyCache,ea as cloneSourceBinding,oy as cloudConfigSchema,Fg as cloudDrivers,Ty as cloudTrailManager,zf as collectAssets,$o as collectPhpAppEntries,lg as collectServerDnsDomains,Cp as completeComposeVolumeDeletion,Wo as completeOidcAuthorization,HI as composePresets,eo as composeProjectName,Sl as composeServerlessAppTemplate,DA as compositeSpendTransport,Nt as compressBackup,lS as config,lc as configOrigins,yu as connectionGuidance,Ly as containerRegistryManager,rA as controlPlaneDatabaseFile,Jc as controlPlaneMigrations,NI as createApiBackendPreset,na as createApiV1Handler,SS as createAsgBuildDriver,Ku as createBackupQueueHandlers,Wy as createCliHandler,O as createCloudDriver,Bu as createCloudFrontPolicy,JI as createCredentialProvider,UI as createDashboardSite,_I as createDataPipelinePreset,Su as createDataServiceQueueHandlers,sd as createDeploymentQueueHandlers,D as createDnsProvider,yS as createEcsBuildDriver,wd as createEnforcementHandlers,um as createError,Jd as createExistingStaticFullStackPreset,Cu as createFleetQueueHandlers,PI as createFullStackAppPreset,Fs as createGoDaddyValidator,oE as createHandlers,zy as createHttpHandler,BI as createJamstackPreset,Au as createJobQueueHandlers,MI as createLaravelPreset,LI as createMLApiPreset,Pu as createMaintenanceQueueHandlers,CS as createMediaAccessToken,xI as createMicroservicesPreset,Rb as createMockAWS,wI as createNodeJsServerPreset,RI as createNodeJsServerlessPreset,vs as createObjectStorageClient,Ms as createPorkbunValidator,GI as createPreset,Mo as createPresignedUrl,Yy as createPresignedUrlAsync,Ky as createQueueHandler,OI as createRealtimeAppPreset,vu as createRegionQueueHandlers,ou as createReleaseProvenance,Wl as createReleaseQueueHandlers,hS as createRemoteBuildQueueHandlers,Us as createRoute53Validator,Bf as createRuntimeAdapters,JA as createS3Client,AS as createServerBuildDriver,FI as createServerlessLaravelPreset,DI as createServerlessNodePreset,cg as createSmsInfrastructure,et as createSourceAdapter,TI as createStaticSitePreset,$I as createTraditionalWebAppPreset,od as createVolumeQueueHandlers,kI as createWordPressPreset,Je as createZip,zb as crossRegionReferenceManager,En as dashboardActions,zs as dashboardCredentialsFile,mn as dataServiceCapabilities,OC as databaseUserManager,$l as decodeBase32,Oe as decompressBackup,Yf as decryptBackup,Vo as defaultConfig,mm as defaultLocalConfig,Bl as defaultRateLimitRules,yr as delegateZone,Ns as delegateZoneFromConfig,Gu as deleteFailoverReplicaBuckets,Ja as deleteStaticSite,Hc as deployAllComputeSites,xa as deployServerlessApp,Vu as deploySite,Ws as deploySiteRelease,As as deployStaticSite,Xa as deployStaticSiteFull,vn as deployStaticSiteWithExternalDns,Tn as deployStaticSiteWithExternalDnsFull,Md as deploymentCoexistenceError,QA as deriveManagementDashboardPort,ks as describeDelegation,Ol as describePosture,xs as describeZoneSettings,Of as desiredJobProviderState,kp as detectAnomalies,jp as detectDeploymentTargets,pc as detectDnsProvider,bd as detectLatestAnomaly,YI as detectMisconfigurations,Dl as detectServiceRegion,td as diffCompose,hb as diffTemplates,Zo as discoverGitRefs,zo as discoverOidcProvider,lu as discoverRuntimeInventory,ZC as dlqMonitoringManager,mc as dnsProviders,jC as dnssecManager,Pf as dockerWorkloads,cs as documentDigest,Bc as domainStatus,Ey as drManager,Qe as driverStatePath,uu as ecsWorkloads,qt as effectiveCapabilities,WC as emailAnalyticsManager,XC as emailTemplateManager,Ji as encodeBase32,Xf as encryptBackup,cu as ensureDefaultSecurityPolicies,Uu as ensureFailoverReplicaBuckets,gi as ensureFirewall,fi as ensureManagementDashboard,pi as ensureServer,ui as ensureSshKey,ee as escapeSecLang,fd as evaluateBudget,ai as evaluatePreflight,So as evaluateTelemetryAlertRules,hu as eventBridgeScheduleInput,jy as eventToRequest,yA as ewma,ed as exportCompose,Os as exportRoute53Zone,cm as extendPreset,YC as fifoQueueManager,db as findChangedFiles,vp as findMapping,Ep as findPriceEntry,mC as formatAccountStructure,jh as formatAttachPlan,kb as formatBytes,zr as formatCents,II as formatDiff,Bh as formatDrainedSiteRefusal,Bb as formatDuration,Qb as formatFlagSuggestions,Vb as formatHistory,qb as formatHistoryStats,Lh as formatInventory,Ob as formatKeyValue,xb as formatList,Mh as formatPlan,di as formatPreflightFindings,Nb as formatProgressBar,Iy as formatRegion,sC as formatRegionList,Tf as formatScanResults,_b as formatSuggestion,Db as formatTable,Gr as formatTimeToExhaustion,Pb as formatTree,jA as fromEC2Metadata,zA as fromECSMetadata,VA as fromEnvironment,qA as fromSharedCredentials,KA as fromWebIdentity,Cl as functionFingerprint,qn as gatewayHostnames,bl as generateAppImageDockerfile,DC as generateApprovalConfig,rf as generateBootstrap,dy as generateCleanupWorkflow,ly as generateCostReportWorkflow,gC as generateCrossAccountRoleCF,nu as generateCycloneDxSbom,TC as generateDeploymentConfig,IC as generateDeploymentPipeline,fC as generateDeploymentWorkflow,Wa as generateExternalDnsStaticSiteTemplate,FS as generateHttpsServerCode,iu as generateImageSbom,_S as generateLetsEncryptUserData,t as generateLogicalId,vC as generateManualPipeline,SC as generateMatrixWorkflow,wC as generateMultiEnvConfig,bC as generateMultiEnvPipeline,hC as generateMultiEnvWorkflow,AC as generatePRPreviewWorkflow,PC as generateParallelConfig,lf as generatePhpFpmConfig,nf as generatePhpLayerDockerfile,CC as generatePreviewPipeline,cy as generatePreviewWorkflow,r as generateResourceName,RC as generateScheduledConfig,EC as generateScheduledPipeline,yC as generateScheduledWorkflow,hs as generateStaticSiteTemplate,x as generateUbuntuAppCloudInit,dm as getAccountId,Xb as getAllRegions,rC as getClosestRegion,Hb as getCommandUsage,nA as getComposeTemplate,Af as getConfig,$b as getContextualHelp,Hi as getCredentials,Ib as getDeploymentStrategy,bb as getDiffStats,Ab as getDiffSummary,ey as getErrorDetails,el as getLocalConfig,Tb as getLocalCredentials,vb as getLocalEndpoint,wb as getLocalEnvVars,nb as getQuotaUsageSummary,uC as getRecommendedStructure,Gi as getRegion,oC as getRegionStats,Zb as getRegionsByCompliance,Yb as getRegionsByLocation,eC as getRegionsByPricingTier,ty as getRequiredPermissions,iS as getSigningKeyCacheSize,ag as getSmsInfrastructureStatus,uI as getTimestamp,Fo as globMatches,Js as globToRegex,Kb as globalResourceManager,Di as governingLimitCents,Qu as grantFailoverReplicaAccess,wy as guardDutyManager,bo as handleSpendRequest,Vn as hasAutoWwwVariant,er as hasManagementDashboardSite,Wc as hasProxyUpstream,sb as hashBuffer,ob as hashDirectory,gm as hashFile,ab as hashManifest,pm as hashString,dE as healthCheckManager,Un as hostAcceptsIpv6,_t as hostCondition,qo as hotp,Hr as hourBucket,AA as hourBucketsBetween,MC as imageScanningManager,us as infraEnvFromOutputs,vl as inspectInvocation,Vy as installRecursionFetch,Ss as invalidateCache,of as invocationContext,OA as isArmInstanceType,Lb as isLikelyTypo,Hn as isLocalDatabase,Eb as isLocalDevelopment,Zr as isManagementDashboardSiteName,hr as isNameserverRegistrar,sS as isNodeCryptoAvailable,Id as isOperationAllowed,yo as isQuietHours,vo as isS3RestEndpoint,Ai as isSafePattern,Ld as isStateDirConfigured,$d as isStatePath,Kr as isValidCidr,tC as isValidRegion,wi as isValidTimeZone,oS as isWebCryptoAvailable,Ar as isZoneHost,pn as jobProviderCapability,Es as keyMatchesFilters,HC as lambdaConcurrencyManager,qC as lambdaDLQManager,GC as lambdaDestinationsManager,UC as lambdaLayersManager,VC as lambdaVPCManager,QC as lambdaVersionsManager,gu as lambdaWorkloads,Tl as laravelServerlessEnvDefaults,Mr as listComposeTemplates,ts as listSourceReferences,Ll as loadCloudConfig,Jt as loadTelemetryPolicy,By as logsManager,Cd as lookbackHoursForSignal,NA as mailEnabled,Fd as mailFirewallPorts,Uf as maintenanceWindowOpen,hf as makeAWSRequest,eS as makeAWSRequestAsync,Zy as makeAWSRequestOnce,eg as managedRuleInSync,am as managementDashboardSiteName,Tu as manifestDigest,on as matchTotpCounter,bS as mediaObjectHeaders,go as median,Pp as medianAbsoluteDeviation,hd as mergeDecisions,en as mergeInfrastructure,fA as mergePriceBooks,gd as meterTelemetry,kC as metricsManager,rg as migrateObjectStorage,BC as migrationManager,aC as multiAccountManager,jb as multiRegionManager,VS as needsRenewal,lE as networkSecurityManager,Rt as nextScheduleRuns,Ce as normalizePublicIpv6,ke as normalizeRuntimeStatus,tt as normalizeScheduleExpression,Ef as normalizeSourceEvent,Ue as normalizeSshPublicKey,Lp as normalizeTelemetryPolicy,bi as occupiedHostPorts,ra as openApiDocument,ho as optionsForSignal,cC as organizationManager,wl as packagePhpApp,tn as packageServerlessApp,Vf as pagesAssetHash,Gg as pagesDnsRecord,Zd as parallel,ub as parallelMap,gb as parallelWithRetry,Wh as parseCertificateState,El as parseChain,$r as parseCompose,sI as parseComposeCatalog,Df as parseDockerInspect,Xu as parseDotenv,kh as parseDrainedSites,Ei as parseHostSiteFragments,rS as parseJSONResponse,oi as parsePreflightFacts,Ap as parseSourceDrained,Nf as parseSystemdRecords,pp as parseTargetReady,Kc as parseUpstreamPort,dp as parseWorkersPaused,tS as parseXMLResponse,Oi as pathTemplate,jc as pendingSteps,uo as percentOfLimit,xC as performanceManager,Il as phpLayerBuildStage,Hy as phpLayerPackages,nn as phpRuntimeLayerAssets,oI as planComposeTemplateUpgrade,Ad as planEnforcement,sp as planIsDestructive,Vp as planMitigation,Uh as planServerRename,Zh as planSiteMove,_s as planZoneMigration,Mt as policyTag,ci as preflightFailed,ay as previewManager,uy as previewNotifications,Dt as previewSchedule,hA as previousBudgetWindow,ao as priceUsage,pA as priceUsageLines,Oh as probeHostRoutes,Nc as probeOriginTls,fb as processInChunks,eu as processSourceWebhook,is as productionChangeReview,ky as progressiveDeploymentManager,md as projectSpend,Oo as propagationHeaders,Za as providerEndpoint,wu as publicKeyFingerprint,Ln as qualifyName,tE as queueManagementManager,cb as quickHash,qf as r2Endpoint,Qg as r2S3Credentials,kl as rateLimitHeaders,Ki as rateLimitKey,He as readDriverState,_h as reconcile,ug as reconcileAddressRecords,Vg as reconcileCloudflareCdn,Rh as reconcileCloudflareWorkers,Ps as reconcileDeclaredRecords,fS as reconcileJobObservation,rh as reconcileR2Buckets,dn as reconcileSourceWebhook,ns as recordDashboardHostPosture,gS as recordPreDeploySecretScan,pS as recordSkippedSecretScan,_o as recursionBlockedResponse,Be as redactRuntimeConfig,Pd as redactTelemetryText,xi as redactTelemetryValue,Sn as redeployServerlessApp,Wb as regionPairManager,cn as releaseStrategyCapabilities,bf as releaseTrafficPlan,hi as reloadRpxGateway,Cs as remapKey,xg as removeDns01ChallengeRecord,yn as removeSiteFromCloudConfig,tu as removeSourceWebhook,fc as removeStaleServerAddressRecords,rd as renderComposeTemplate,$i as renderDdosInstallScript,xd as renderNftablesRuleset,ss as renderServerCron,Bd as renderSysctlFile,Vc as renderWafConfig,yi as renderWafInstallScript,Gc as renewRpxCertificates,Oy as replicaManager,PA as requestHash,yb as requiresReplacement,iE as resetRecursionRuntime,sE as resolveApp,g as resolveAppDatabase,Hh as resolveAttachTarget,Ze as resolveAuthEncryptionKey,fe as resolveCloudProvider,Hg as resolveCloudflareCdnPlan,Do as resolveCredentials,fs as resolveDashboardAction,Qc as resolveDashboardAuth,HA as resolveDashboardDomain,GA as resolveDashboardDomains,Ds as resolveDeclaredRecords,yI as resolveDeployBucketName,Q as resolveDeploymentMode,Yn as resolveExecStart,Eo as resolveFailoverStatusCodes,wc as resolveHetznerApiToken,Rr as resolveHostCleanupConfig,Mi as resolveMailService,QI as resolveManagementDashboardSite,Qi as resolveManagementDashboardSites,ec as resolveObjectStorage,re as resolveOriginConnection,$h as resolvePlan,p as resolveProjectStackName,Lr as resolveProxyUpstreams,yl as resolveQueueNames,sA as resolveQueuedDeploymentCommand,nr as resolveQueues,Gy as resolveRecursionConfig,WA as resolveRegion,oe as resolveRuntimeInventory,Xt as resolveServerlessAppStackName,Hd as resolveServerlessArtifactBucketName,Fi as resolveServerlessAssetBucketName,qi as resolveServerlessRuntime,fI as resolveSiteBucketName,Xs as resolveSiteDeployTarget,u as resolveSiteKind,mI as resolveSiteResourceName,pI as resolveSiteStackName,ii as resolveSshSettings,d as resolveStatePath,hI as resolveStorageBucketName,Yp as resolveStorageFailover,Gt as resolveUiSource,qu as resolveZoneApex,uE as resourceManagementManager,df as responseToResult,Np as robustZScore,Vt as roleCapabilities,Kl as rollbackImmutableRelease,In as rollbackServerlessApp,mA as roundCents,zC as route53ResolverManager,My as route53RoutingManager,xp as routeMatches,rp as routesFromFragments,zi as ruleMatches,Fy as runBuildHooks,yd as runEnforcement,Lo as runPhpBuildHooks,rt as runRemoteCommand,Ae as runtimeId,Le as s3OriginBucket,Zp as s3RegionalDomain,ac as sameCorsRules,yc as sameLifecycleRules,$n as sameNameservers,ms as sanitizeCloudConfig,s as sanitizeControlPlaneValue,gI as sanitizeName,Hl as sanitizeOidcReturnPath,Rd as saveTelemetryPolicy,vf as scanForSecrets,Xc as scopeContains,ht as scopeKey,Ic as scpUpload,Mb as searchCommands,Zs as searchControlPlane,_y as secretsManager,_C as secretsRotationManager,mS as secureContainerRelease,Ry as securityHubManager,$C as securityScanningManager,se as securityScope,Hu as seedFailoverReplicas,an as sendAuthenticationEmail,JC as senderReputationManager,pb as sequence,Yu as serializeDotenv,mi as serverPublicIpv4,$y as serviceMeshManager,Lu as setAttachToInCloudConfig,dr as setMaintenance,ds as setSitePropertyInCloudConfig,_d as setStateDir,MS as setupDns01Challenge,cc as setupSmsInfrastructure,No as sha256,qy as sharedRecursionGuard,sf as sharedRuntimeLoop,Ip as shipsARelease,dS as signCloudFrontCookies,cS as signCloudFrontUrl,R as signRequest,Pl as signRequestAsync,mo as signalDefinition,_ as siteInstallBase,Ii as siteMoveArchivePath,zh as siteMoveCertArchivePath,zc as siteUnitGlob,Mp as spendNotificationText,Co as spendOpenApiPaths,Tr as sshExec,pe as sshExecOrThrow,Jb as stackDependencyManager,Ka as startLocalDashboardServer,RA as startSpendLoop,Jr as stateDir,L as statePath,cE as staticSiteManager,Xy as storageAdvancedManager,CI as storageFailoverReplicasFromTemplate,SA as streamFocusJsonl,Sd as strongestActiveAction,ym as suggestCommand,Ub as suggestFlags,tb as suggestIAMPolicy,ib as suggestQuotaIncrease,iC as suggestRegionPairs,nC as suggestRegions,es as syncSourceRepositories,ad as synchronizeComposeVolumes,Zu as synchronizeConfiguredConfiguration,la as synchronizeConfiguredJobs,xy as syntheticsManager,kd as sysctlHardening,kf as systemdWorkloads,vA as telemetryBucketLabel,_i as telemetryCursor,Dd as telemetryEstimatedMonthlyCost,EA as telemetryPercentile,$p as telemetryPolicyKey,ry as templateCache,np as tenantsOf,ta as testSourceConnection,cd as tieredMicroCents,tg as toApiLifecycleRule,Oc as toCloudflareZoneSettings,Ao as toFocusJsonl,Ed as toFocusRecords,xh as toInventoryServer,yf as totp,jo as totpUri,ip as unaccountedSites,Rf as unsupportedCapabilities,oA as unsupportedVolumeCapabilities,Du as updateCompatibility,Nu as updateSiteInCloudConfig,ys as uploadStaticFiles,Tp as usageDeltaKey,Kt as utcInstantOfLocal,pC as validateAccountStructure,Cb as validateAgainstSchema,cA as validateAttachment,Jf as validateBackupDestination,Gb as validateCommand,XI as validateConfiguration,ZI as validateCredentials,Sp as validateDeploymentConfig,aA as validateMountPath,St as validateOriginGroups,Dg as validateResourceLimits,op as validateServerName,bg as validateTemplate,wg as validateTemplateSize,Ac as verifyAddressRecord,uS as verifyArtifactSignature,RS as verifyMediaAccessToken,Sf as verifyTotp,Ru as verifyUpdateSignature,$s as verifyZoneParity,no as volumeCapabilities,Jg as wafEventTelemetry,bc as waitForCloudInit,Kn as waitForSsh,sr as webhookEndpoint,KI as withCDN,zI as withCache,og as withContentHash,jI as withDatabase,cf as withInvocation,VI as withMonitoring,WI as withQueue,qI as withSecurity,mb as withTimeout,sg as workerBindings,qs as workerContentHash,Tc as workerInSync,Z as wrapCloudInitUserData,dt as writeDriverState,NC as xrayManager,Eu as zeroCapacity,IA as zeroFill,ld as zoneOffsetMs,co as zonedParts};
|
|
604
|
+
`}async function Xg(l,f,C){let A=`_acme-challenge.${f}`;if(await Wf(l,f,A,C))return;let w=await l.createRecord(f,{name:A,type:"TXT",content:C,ttl:60});if(!w.success)throw Error(`Failed to create DNS challenge record: ${w.message}`)}async function Qg(l,f,C){let A=await l.deleteRecord(f,{name:`_acme-challenge.${f}`,type:"TXT",content:C});if(!A.success)console.warn(`Failed to delete DNS challenge record: ${A.message}`)}async function Wf(l,f,C,A){try{let w=await l.listRecords(f,"TXT"),B=C.replace(/\.$/,"").toLowerCase();return(w.records??[]).some((v)=>v.name.replace(/\.$/,"").toLowerCase()===B&&v.content.replace(/^"|"$/g,"")===A)}catch{return!1}}function ju(l){let{hostedZoneId:f,dnsProvider:C,region:A="us-east-1"}=l;if(C)return D(C);if(f)return new X(A,f);throw Error("Either dnsProvider or hostedZoneId must be provided")}async function rR(l){await Xg(ju(l),l.domain,l.challengeValue)}async function nR(l){await Qg(ju(l),l.domain,l.challengeValue)}function iR(l){try{let{execSync:f}=Xe("node:child_process"),C=f(`openssl x509 -checkend 2592000 -noout -in ${l}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as qu,createSign as Vf,generateKeyPairSync as eg}from"node:crypto";var tg={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class zf{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(l){this.directoryUrl=l.staging?tg.staging:tg.production,this.email=l.email,this.accountKey=l.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:l}=eg("ec",{namedCurve:"P-256"});return l.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let l=await fetch(this.directoryUrl);if(!l.ok)throw Error(`Failed to fetch ACME directory: ${l.status}`);return this.directory=await l.json(),this.directory}async getNonce(){if(this.nonce){let A=this.nonce;return this.nonce=null,A}let l=await this.getDirectory(),C=(await fetch(l.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!C)throw Error("Failed to get nonce from ACME server");return C}getJwk(){let l=this.accountKey.split(`
|
|
605
|
+
`).filter((B)=>!B.startsWith("-----")).join(""),f=Buffer.from(l,"base64"),C=f.length-65,A=f.subarray(C+1,C+33),w=f.subarray(C+33,C+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(A),y:this.base64UrlEncode(w)}}getJwkThumbprint(){let l=this.getJwk(),f=JSON.stringify({crv:l.crv,kty:l.kty,x:l.x,y:l.y}),C=qu("sha256").update(f).digest();return this.base64UrlEncode(C)}base64UrlEncode(l){return(typeof l==="string"?Buffer.from(l):l).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(l,f){let C=await this.getNonce(),A=this.getJwk(),w={alg:"ES256",nonce:C,url:l};if(this.accountUrl)w.kid=this.accountUrl;else w.jwk=A;let B=this.base64UrlEncode(JSON.stringify(w)),v=f===""?"":this.base64UrlEncode(JSON.stringify(f)),ce=`${B}.${v}`,de=Vf("SHA256");de.update(ce);let ct=de.sign(this.accountKey),xe=ct.subarray(4,4+ct[3]),Ut=4+ct[3]+2,Qt=ct.subarray(Ut,Ut+ct[Ut-1]),gt=Buffer.alloc(32),lt=Buffer.alloc(32);xe.copy(gt,32-xe.length),Qt.copy(lt,32-Qt.length);let ut=Buffer.concat([gt,lt]);return JSON.stringify({protected:B,payload:v,signature:this.base64UrlEncode(ut)})}async acmeRequest(l,f){let C=await this.signPayload(l,f),A=await fetch(l,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:C}),w=A.headers.get("replay-nonce");if(w)this.nonce=w;let B,v=A.headers.get("content-type");if(v?.includes("application/json")||v?.includes("application/problem+json"))B=await A.json();else B=await A.text();if(!A.ok)throw Error(`ACME request failed: ${JSON.stringify(B)}`);return{body:B,headers:A.headers}}async registerAccount(){let l=await this.getDirectory(),{body:f,headers:C}=await this.acmeRequest(l.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),A=C.get("location");if(!A)throw Error("No account URL returned");return this.accountUrl=A,A}async createOrder(l){if(!this.accountUrl)await this.registerAccount();let f=await this.getDirectory(),{body:C,headers:A}=await this.acmeRequest(f.newOrder,{identifiers:l.map((B)=>({type:"dns",value:B}))}),w=A.get("location");if(!w)throw Error("No order URL returned");return{orderUrl:w,authorizations:C.authorizations,finalize:C.finalize}}async getAuthorization(l){let{body:f}=await this.acmeRequest(l,""),C=f.identifier.value,A=this.getJwkThumbprint(),w=f.challenges.filter((B)=>B.type==="http-01"||B.type==="dns-01").map((B)=>{let v=`${B.token}.${A}`;if(B.type==="http-01")return{type:"http-01",token:B.token,keyAuthorization:v,identifier:`/.well-known/acme-challenge/${B.token}`};else{let ce=this.base64UrlEncode(qu("sha256").update(v).digest());return{type:"dns-01",token:B.token,keyAuthorization:v,identifier:`_acme-challenge.${C}`,dnsValue:ce}}});return{domain:C,challenges:w}}async respondToChallenge(l){await this.acmeRequest(l,{})}async waitForAuthorization(l,f=30){for(let C=0;C<f;C++){let{body:A}=await this.acmeRequest(l,"");if(A.status==="valid")return;if(A.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(A)}`);await new Promise((w)=>setTimeout(w,2000))}throw Error("Authorization timed out")}generateCsr(l){let{privateKey:f}=eg("rsa",{modulusLength:2048}),C=f.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(l,f),privateKey:C}}createSimpleCsr(l,f){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(l,f){let{csr:C,privateKey:A}=this.generateCsr(f),{body:w}=await this.acmeRequest(l,{csr:this.base64UrlEncode(Buffer.from(C,"base64"))}),B=w.certificate;if(!B)throw Error("Certificate not immediately available - polling not implemented");let ce=await(await fetch(B)).text(),de=ce.split(/(?=-----BEGIN CERTIFICATE-----)/g),ct=de[0],xe=de.slice(1).join("");return{certificate:ct,privateKey:A,chain:xe,fullchain:ce,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var wn=(l)=>l===void 0?void 0:l?"on":"off";function Lc(l){let f={ssl:l.ssl,always_use_https:wn(l.alwaysUseHttps),automatic_https_rewrites:wn(l.automaticHttpsRewrites),min_tls_version:l.minTlsVersion,tls_1_3:wn(l.tls13),brotli:wn(l.brotli),http3:wn(l.http3),"0rtt":wn(l.zeroRtt),early_hints:wn(l.earlyHints),browser_cache_ttl:l.browserCacheTtl,always_online:wn(l.alwaysOnline),websockets:wn(l.websockets),email_obfuscation:wn(l.emailObfuscation)};if(l.hsts)f.security_header={strict_transport_security:{enabled:l.hsts.enabled,max_age:l.hsts.maxAge??31536000,include_subdomains:l.hsts.includeSubdomains??!1,preload:l.hsts.preload??!1,nosniff:l.hsts.noSniff??!0}};for(let C of Object.keys(f))if(f[C]===void 0)delete f[C];return{...f,...l.raw??{}}}var Ts={ssl:"strict",alwaysUseHttps:!0,automaticHttpsRewrites:!0,minTlsVersion:"1.2",tls13:!0,brotli:!0,http3:!0,earlyHints:!0,alwaysOnline:!0,emailObfuscation:!1,browserCacheTtl:0};import{connect as Gf}from"node:tls";async function Fc(l){let{address:f,serverName:C,port:A=443,timeoutMs:w=5000}=l;return new Promise((B)=>{let v=!1,ce=(ct)=>{if(v)return;v=!0;try{de.destroy()}catch{}B(ct)},de=Gf({host:f,port:A,servername:C,rejectUnauthorized:!1,timeout:w});de.once("secureConnect",()=>{if(de.authorized){ce({reachable:!0,trusted:!0});return}ce({reachable:!0,trusted:!1,reason:de.authorizationError?String(de.authorizationError):"origin certificate is not trusted for this hostname"})}),de.once("timeout",()=>{ce({reachable:!1,trusted:!1,reason:`no TLS handshake within ${w}ms`})}),de.once("error",(ct)=>{ce({reachable:!1,trusted:!1,reason:ct.message})})})}function jf(l,f){let C=f.replace(/\.$/,"").toLowerCase();return l.some((A)=>{let w=A.replace(/\.$/,"").toLowerCase();if(w===C)return!0;if(!w.startsWith("*."))return!1;let B=w.slice(2);if(!C.endsWith(`.${B}`))return!1;return!C.slice(0,C.length-B.length-1).includes(".")})}async function Kf(l){let{provider:f,zone:C,hosts:A,ipv4:w,ipv6:B,proxied:v=!0,settings:ce=Ts,cache:de,originGuard:ct,purge:xe=!0,ttl:Ut=300,skipOriginProbe:Qt=!1,skipEdgeCertificateCheck:gt=!1}=l,lt={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(A.length===0)return lt;let ut=[],Ee=v&&!gt?await f.listEdgeCertificateHosts(C):null;for(let ve of A){let Pt=v;if(Pt&&Ee&&!jf(Ee,ve)){Pt=!1;let lr=Ee.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${Ee.join(", ")})`;lt.deferredProxy.push({host:ve,reason:lr}),lt.warnings.push(`${ve}: publishing DNS-only — ${lr}. Proxying it would make Cloudflare terminate TLS with no certificate for the name, which fails the handshake outright rather than degrading. Universal SSL covers the apex and ONE level of subdomain, so a deeper name needs its own certificate; otherwise re-run the deploy once the certificate is active.`)}if(Pt&&!Qt){let lr=await Fc({address:w,serverName:ve});if(!lr.trusted){Pt=!1;let Cr=lr.reason||"origin is not serving a trusted certificate";lt.deferredProxy.push({host:ve,reason:Cr}),lt.warnings.push(`${ve}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${Cr}). The origin issues certificates over HTTP-01, which needs the name to reach it directly; re-run the deploy once it has one and the record will be proxied.`)}}if(Pt)ut.push(ve);let Ht=[{type:"A",content:w}];if(B&&Un(ve))Ht.push({type:"AAAA",content:B});for(let{type:lr,content:Cr}of Ht){let br=await f.upsertRecord(C,{name:ve,type:lr,content:Cr,ttl:Ut,proxied:Pt});if(br.success)lt.records.push({host:ve,type:lr,content:Cr,proxied:Pt});else lt.warnings.push(`${ve} ${lr} → ${Cr} failed: ${br.message||"unknown provider error"}`)}}if(ut.length===0){if(v)lt.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return lt}try{let ve=Lc(ce),Pt=await f.applyZoneSettings(C,ve);lt.settingsChanged=Pt.changed;for(let Ht of Pt.failed)lt.warnings.push(`zone setting '${Ht.id}' could not be applied: ${Ht.error}`)}catch(ve){lt.warnings.push(`zone settings could not be read: ${ve instanceof Error?ve.message:String(ve)}`)}let Ft=uc(ut,de);if(Ft.length>0){let ve=await f.putManagedPhaseRules(C,"http_request_cache_settings",Ft);if(ve.success)lt.cacheRules=Ft.length;else lt.warnings.push(`cache rules could not be written: ${ve.message}`)}if(ct){let ve=gc(ut,ct.header,ct.value);if(ve.length>0){let Pt=await f.putManagedPhaseRules(C,"http_request_late_transform",ve);if(Pt.success)lt.originGuard=!0;else lt.warnings.push(`origin guard header could not be written: ${Pt.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(xe){if(lt.purged=await f.purgeCache(C,{hosts:ut}),!lt.purged)lt.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return lt}var qf=(l)=>process.env[l];function ng(l,f){let C=l.replace(/\.$/,"").toLowerCase();if(f){let A=f.replace(/\.$/,"").toLowerCase();if(C===A||C.endsWith(`.${A}`))return A}return C.split(".").slice(-2).join(".")}function Zf(l,f={}){let C=f.env??qf,A=l.infrastructure?.compute?.proxy?.cdn,w=[];if(!A||A.provider!=="cloudflare")return{plan:null,errors:w};if(A.originDomain)w.push(`compute.proxy.cdn.originDomain (${A.originDomain}) is ignored for Cloudflare: the proxy forwards to the address in the record it fronts, `+"so no separate origin hostname is needed — and publishing one gives clients a documented way around the edge.");let B=C("CLOUDFLARE_API_TOKEN");if(!B)return w.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:w};let v=l.sites??{},ce=A.frontedHosts?.length?[...new Set(A.frontedHosts.map((Qt)=>Qt.toLowerCase()))]:qn(v,{autoWww:l.infrastructure?.compute?.proxy?.autoWww!==!1});if(ce.length===0)return w.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:w};let de=l.infrastructure?.dns?.domain,ct=new Set(ce.map((Qt)=>ng(Qt,de)));if(ct.size>1)return w.push(`Fronted hosts span more than one zone (${[...ct].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:w};let xe=A.cloudflare??{},Ut=A.secret?{header:A.secretHeader??"X-Origin-Verify",value:A.secret}:void 0;return{plan:{zone:[...ct][0],hosts:ce,apiToken:B,zoneId:xe.zoneId??C("CLOUDFLARE_ZONE_ID"),accountId:xe.accountId??C("CLOUDFLARE_ACCOUNT_ID"),proxied:xe.proxied!==!1,settings:xe.settings??Ts,cache:xe.cache,originGuard:Ut,purge:xe.purgeOnDeploy!==!1,skipOriginProbe:xe.skipOriginProbe===!0},errors:w}}var eh=26214400;var th=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class ig{name="cloudflare-pages";apiToken;accountId;constructor(l){if(!l.apiToken)throw Error("Cloudflare Pages needs an API token");if(!l.accountId)throw Error("Cloudflare Pages needs an account id");this.apiToken=l.apiToken,this.accountId=l.accountId}async request(l,f,C){return ac(l,`/accounts/${this.accountId}${f}`,`Bearer ${this.apiToken}`,C)}async getProject(l){try{return await this.request("GET",`/pages/projects/${l}`)}catch(f){if(f instanceof Error&&/\b8000007\b|not found/i.test(f.message))return null;throw f}}async ensureProject(l,f="main"){let C=await this.getProject(l);if(C)return C;return this.request("POST","/pages/projects",{name:l,production_branch:f})}async uploadToken(l){return(await this.request("GET",`/pages/projects/${l}/upload-token`)).jwt}async missingHashes(l,f){let C=await ac("POST","/pages/assets/check-missing",`Bearer ${l}`,{hashes:f});return new Set(C)}async upsertHashes(l,f){await ac("POST","/pages/assets/upsert-hashes",`Bearer ${l}`,{hashes:f})}async uploadBatch(l,f){let C=f.map((A)=>({key:A.hash,value:A.base64,metadata:{contentType:nh(A.extension)},base64:!0}));await ac("POST","/pages/assets/upload",`Bearer ${l}`,C)}async createDeployment(l,f,C){let A={};for(let B of f)A[B.path]=B.hash;let w=new FormData;if(w.append("manifest",JSON.stringify(A)),C)w.append("branch",C);return this.request("POST",`/pages/projects/${l}/deployments`,w)}async deployDirectory(l){let f=await sg(l.directory);if(f.length===0)throw Error(`No files to deploy in ${l.directory}`);let C=await this.uploadToken(l.project),A=await this.missingHashes(C,f.map((de)=>de.hash)),w=f.filter((de)=>A.has(de.hash)),B=[];for(let de=0;de<w.length;de+=100)B.push(w.slice(de,de+100));let v=0;for(let de=0;de<B.length;de+=4){let ct=B.slice(de,de+4);await Promise.all(ct.map((xe)=>this.uploadBatch(C,xe))),v+=ct.reduce((xe,Ut)=>xe+Ut.length,0),l.onProgress?.(v,w.length)}return await this.upsertHashes(C,f.map((de)=>de.hash)),{deployment:await this.createDeployment(l.project,f,l.branch),total:f.length,uploaded:w.length,uploadedBytes:w.reduce((de,ct)=>de+ct.size,0)}}async listCustomDomains(l){return(await this.request("GET",`/pages/projects/${l}/domains`)).map((C)=>C.name)}async attachCustomDomain(l,f){if((await this.listCustomDomains(l)).includes(f))return!1;return await this.request("POST",`/pages/projects/${l}/domains`,{name:f}),!0}}function rh(l,f){return{type:"CNAME",name:l,value:f.endsWith(".pages.dev")?f:`${f}.pages.dev`,ttl:1,proxied:!0}}async function og(l,f){let{blake3:C}=await import("./chunk-7eaech9q.js").then((m)=>aS(m.default,1));return(await C(l+f)).slice(0,32)}async function sg(l){let{readdir:f}=await import("node:fs/promises"),{join:C,relative:A,sep:w}=await import("node:path"),B=[];async function v(ce){let de=await f(ce,{withFileTypes:!0});for(let ct of de){let xe=C(ce,ct.name);if(ct.isDirectory()){await v(xe);continue}if(!ct.isFile())continue;let Ut=`/${A(l,xe).split(w).join("/")}`;if(th.has(Ut))continue;let Qt=await Bun.file(xe).bytes();if(Qt.byteLength>26214400)throw Error(`${Ut} is ${Qt.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let gt=Buffer.from(Qt).toString("base64"),lt=ct.name.lastIndexOf("."),ut=lt>0?ct.name.slice(lt+1):"";B.push({path:Ut,hash:await og(gt,ut),base64:gt,extension:ut,size:Qt.byteLength})}}return await v(l),B.sort((ce,de)=>ce.path.localeCompare(de.path)),B}function nh(l){return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",mjs:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",map:"application/json; charset=utf-8",xml:"application/xml; charset=utf-8",txt:"text/plain; charset=utf-8",svg:"image/svg+xml",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",avif:"image/avif",ico:"image/x-icon",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",pdf:"application/pdf",webmanifest:"application/manifest+json"}[l.toLowerCase()]||"application/octet-stream"}async function ac(l,f,C,A){let w={Authorization:C},B;if(A instanceof FormData)B=A;else if(A!==void 0)w["Content-Type"]="application/json",B=JSON.stringify(A);let v=await fetch(`https://api.cloudflare.com/client/v4${f}`,{method:l,headers:w,body:B}),ce=await v.text(),de;try{de=JSON.parse(ce)}catch{throw Error(`Cloudflare Pages API returned ${v.status} with a non-JSON body: ${ce.slice(0,200)}`)}if(!de.success){let ct=(de.errors??[]).map((xe)=>`${xe.code}: ${xe.message}`).join(", ");throw Error(`Cloudflare Pages API error (${v.status}): ${ct||ce.slice(0,200)}`)}return de.result}import{createHash as ih}from"node:crypto";var fg="https://api.cloudflare.com/client/v4",hg=10042,oh=10006,sh=10059;class ti extends Error{status;errors;constructor(l,f,C=[]){super(l);this.name="R2ApiError",this.status=f,this.errors=C}hasCode(l){return this.errors.some((f)=>f.code===l)}}class jn extends ti{accountId;constructor(l,f,C=[]){super(`R2 is not enabled on Cloudflare account ${l}. Enable it once in the Cloudflare dashboard (R2 Object Storage, then follow the prompt to activate it), then re-run the deploy.`,f,C);this.name="R2NotEnabledError",this.accountId=l}}class Si{name="cloudflare-r2";apiToken;accountId;fetchImpl;constructor(l){if(!l.apiToken)throw Error("Cloudflare R2 needs an API token");if(!l.accountId)throw Error("Cloudflare R2 needs an account id");this.apiToken=l.apiToken,this.accountId=l.accountId,this.fetchImpl=l.fetch??((f,C)=>fetch(f,C))}async requestEnvelope(l,f,C,A={}){let w={Authorization:`Bearer ${this.apiToken}`};if(C!==void 0)w["Content-Type"]="application/json";if(A.jurisdiction&&A.jurisdiction!=="default")w["cf-r2-jurisdiction"]=A.jurisdiction;let B=await this.fetchImpl(`${fg}/accounts/${this.accountId}/r2${f}`,{method:l,headers:w,body:C===void 0?void 0:JSON.stringify(C)}),v=await B.text(),ce;try{ce=JSON.parse(v)}catch{throw new ti(`Cloudflare R2 API returned ${B.status} with a non-JSON body: ${v.slice(0,200)}`,B.status)}if(!ce.success){let de=ce.errors??[];if(de.some((xe)=>xe.code===hg))throw new jn(this.accountId,B.status,de);let ct=de.map((xe)=>`${xe.code}: ${xe.message}`).join(", ");throw new ti(`Cloudflare R2 API error (${B.status}) on ${l} ${f}: ${ct||v.slice(0,200)}`,B.status,de)}return ce}async request(l,f,C,A){return(await this.requestEnvelope(l,f,C,A)).result}bucketPath(l){return`/buckets/${encodeURIComponent(l)}`}async listBuckets(l={}){let f=[],C;do{let A=new URLSearchParams({per_page:"1000"});if(C)A.set("cursor",C);let w=await this.requestEnvelope("GET",`/buckets?${A}`,void 0,l),B=w.result?.buckets??[];f.push(...B),C=B.length>0?w.result_info?.cursor||void 0:void 0}while(C);return f}async getBucket(l,f={}){try{return await this.request("GET",this.bucketPath(l),void 0,f)}catch(C){if(C instanceof jn)throw C;if(C instanceof ti&&(C.hasCode(oh)||C.status===404))return null;throw C}}async ensureBucket(l,f={}){let C={jurisdiction:f.jurisdiction},A=await this.getBucket(l,C);if(A)return{bucket:A,created:!1};let w={name:l};if(f.locationHint)w.locationHint=f.locationHint;let B=await this.request("POST","/buckets",w,C);return{bucket:{...B,name:B?.name||l},created:!0}}async getCors(l,f={}){try{return(await this.request("GET",`${this.bucketPath(l)}/cors`,void 0,f))?.rules??[]}catch(C){if(C instanceof ti&&!(C instanceof jn)&&(C.hasCode(sh)||C.status===404))return[];throw C}}async putCors(l,f,C={}){if(f.length===0){await this.request("DELETE",`${this.bucketPath(l)}/cors`,void 0,C);return}await this.request("PUT",`${this.bucketPath(l)}/cors`,{rules:f},C)}async ensureCors(l,f,C={}){let A=await this.getCors(l,C);if(yc(A,f))return!1;return await this.putCors(l,f,C),!0}async getLifecycle(l,f={}){return(await this.request("GET",`${this.bucketPath(l)}/lifecycle`,void 0,f))?.rules??[]}async putLifecycle(l,f,C={}){await this.request("PUT",`${this.bucketPath(l)}/lifecycle`,{rules:f},C)}async ensureLifecycle(l,f,C={}){let A=await this.getLifecycle(l,C);if(Cc(A,f))return!1;return await this.putLifecycle(l,f,C),!0}async listCustomDomains(l,f={}){return(await this.request("GET",`${this.bucketPath(l)}/domains/custom`,void 0,f))?.domains??[]}async attachCustomDomain(l,f,C={}){return this.request("POST",`${this.bucketPath(l)}/domains/custom`,{domain:f.domain,zoneId:f.zoneId,enabled:f.enabled??!0,minTLS:f.minTLS??"1.2"},C)}async updateCustomDomain(l,f,C,A={}){return this.request("PUT",`${this.bucketPath(l)}/domains/custom/${encodeURIComponent(f)}`,C,A)}async ensureCustomDomain(l,f,C={},A){let w=f.minTLS??"1.2",v=(A??await this.listCustomDomains(l,C)).find((ct)=>ct.domain.toLowerCase()===f.domain.toLowerCase());if(!v){let ct=await this.attachCustomDomain(l,{...f,minTLS:w,enabled:!0},C);return{action:"attached",domain:{...ct,domain:ct?.domain||f.domain}}}let ce=v.minTLS??"1.0";if(v.enabled&&ce===w)return{action:"unchanged",domain:v};let de=await this.updateCustomDomain(l,v.domain,{enabled:!0,minTLS:w},C);return{action:"updated",domain:{...v,...de}}}async getManagedDomain(l,f={}){return this.request("GET",`${this.bucketPath(l)}/domains/managed`,void 0,f)}async setManagedDomain(l,f,C={}){let A=await this.getManagedDomain(l,C);if(A?.enabled===f)return{changed:!1,domain:A};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(l)}/domains/managed`,{enabled:f},C)}}}function yg(l){return`https://${l}.r2.cloudflarestorage.com`}async function ah(l){let{apiToken:f,accountId:C}=l;if(!f)throw Error("r2S3Credentials needs an API token");if(!C)throw Error("r2S3Credentials needs an account id");let A=l.fetch??((v,ce)=>fetch(v,ce)),w=[],B;for(let v of[`/accounts/${C}/tokens/verify`,"/user/tokens/verify"]){let ce=await A(`${fg}${v}`,{method:"GET",headers:{Authorization:`Bearer ${f}`}}),de=await ce.json().catch(()=>null);if(ce.ok&&de?.success&&de.result?.id){B=de.result.id;break}let ct=de?.errors?.map((xe)=>`${xe.code}: ${xe.message}`).join(", ");w.push(`${v} -> ${ce.status}${ct?` (${ct})`:""}`)}if(!B)throw Error(`Could not verify the Cloudflare API token to derive R2 credentials: ${w.join("; ")}`);return{accessKeyId:B,secretAccessKey:ih("sha256").update(f).digest("hex"),endpoint:yg(C),region:"auto"}}function ws(l){if(Array.isArray(l))return`[${l.map(ws).join(",")}]`;if(l&&typeof l==="object")return`{${Object.entries(l).filter(([,C])=>C!==void 0).sort(([C],[A])=>C.localeCompare(A)).map(([C,A])=>`${JSON.stringify(C)}:${ws(A)}`).join(",")}}`;return JSON.stringify(l)}function mg(l,f){let C=(A)=>A&&A.length>0?[...A].map(String).sort():void 0;return{id:f?l.id:void 0,allowed:{origins:C(l.allowed?.origins),methods:C(l.allowed?.methods?.map((A)=>A.toUpperCase())),headers:C(l.allowed?.headers?.map((A)=>A.toLowerCase()))},exposeHeaders:C(l.exposeHeaders?.map((A)=>A.toLowerCase())),maxAgeSeconds:l.maxAgeSeconds}}function yc(l,f){if(l.length!==f.length)return!1;return f.every((C,A)=>{let w=C.id!==void 0;return ws(mg(l[A],w))===ws(mg(C,w))})}function Cc(l,f){if(l.length!==f.length)return!1;let C=(A)=>ws([...A].map((w)=>({...w,storageClassTransitions:w.storageClassTransitions?.length?w.storageClassTransitions:void 0})).sort((w,B)=>w.id.localeCompare(B.id)));return C(l)===C(f)}var ch="r2 cache",lh=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function dh(l,f={}){let C=f.log??(()=>{}),A={buckets:[],warnings:[]},w=l.infrastructure?.r2??l.r2,B=Object.entries(w?.buckets??{});if(B.length===0)return C("R2: no buckets declared, skipping."),A;if(!f.apiToken||!f.accountId){let xe=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),Ut=`R2: ${B.length} bucket(s) declared but ${xe} is not set, skipping.`;return C(Ut),A.warnings.push(Ut),A}let v=f.dryRun===!0,ce=new Si({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),de=new M(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),ct=new Map;for(let[xe,Ut]of B){let Qt=Ut?.name;if(!Qt||!lh.test(Qt)){A.warnings.push(`R2: bucket '${xe}' has an invalid name '${Qt??""}' (3-63 chars: lowercase letters, digits, hyphens), skipping.`);continue}C(`R2: ${v?"checking":"reconciling"} bucket ${Qt}...`);let gt={name:Qt,changes:[],domains:[]};if(A.buckets.push(gt),await ph(Ut,{r2:ce,cloudflare:de,dryRun:v,summary:gt,warnings:A.warnings,claimed:ct,log:C}),gt.changes.length===0)C(`R2: ${Qt} is in sync.`);else for(let lt of gt.changes)C(`R2: ${Qt}: ${lt}`)}return A}async function ph(l,f){let{r2:C,dryRun:A,summary:w,warnings:B}=f,v=l.name,ce={jurisdiction:l.jurisdiction},de=(gt,lt)=>{let ut=A?lt&&`would ${lt}`:gt;if(ut)w.changes.push(ut)},ct;if(A)ct=await C.getBucket(v,ce)!==null;else{let{created:gt}=await C.ensureBucket(v,{locationHint:l.locationHint,jurisdiction:l.jurisdiction});if(ct=!0,gt)de("created","")}if(!ct)de("","create bucket");let xe=gh(l.customDomains);await Is(f,`cors on ${v}`,async()=>{if(!l.cors)return;if(!ct){de("cors updated","set cors");return}let gt=await C.getCors(v,ce);if(yc(gt,l.cors))return;if(!A)await C.putCors(v,l.cors,ce);de(l.cors.length===0?"cors removed":"cors updated",l.cors.length===0?"remove cors":"update cors")}),await Is(f,`lifecycle on ${v}`,async()=>{if(!l.lifecycle)return;let gt=l.lifecycle.map(Rg);if(ct){let lt=await C.getLifecycle(v,ce);if(Cc(lt,gt))return}if(!A)await C.putLifecycle(v,gt,ce);de("lifecycle updated","update lifecycle")}),await Is(f,`r2.dev URL on ${v}`,async()=>{let gt=l.publicDevUrl===!0;if(!ct){if(gt)de("r2.dev URL enabled","enable r2.dev URL");return}if((await C.getManagedDomain(v,ce))?.enabled===gt)return;if(!A)await C.setManagedDomain(v,gt,ce);de(gt?"r2.dev URL enabled":"r2.dev URL disabled",gt?"enable r2.dev URL":"disable r2.dev URL")});let Ut=[];if(xe.length>0&&ct)try{Ut=await C.listCustomDomains(v,ce)}catch(gt){if(gt instanceof jn)throw gt;B.push(`R2: could not list custom domains on ${v}: ${Bc(gt)}`)}let Qt=new Map;for(let{domain:gt,minTLS:lt}of xe){let ut=f.claimed.get(gt);if(ut&&ut!==v){B.push(`R2: ${gt} is declared on both ${ut} and ${v}; leaving it on ${ut}.`);continue}f.claimed.set(gt,v);let Ee=Ut.find((ve)=>ve.domain.toLowerCase()===gt),Ft=lt??"1.2";if(Ee&&Ee.enabled&&(Ee.minTLS??"1.0")===Ft){if(w.domains.push({domain:gt,status:Mc(Ee)}),Ee.zoneId)Qt.set(gt,Ee.zoneId);continue}await Is(f,`custom domain ${gt} on ${v}`,async()=>{if(Ee){if(!A)await C.updateCustomDomain(v,Ee.domain,{enabled:!0,minTLS:Ft},ce);if(de(`custom domain ${gt} updated`,`update custom domain ${gt}`),w.domains.push({domain:gt,status:Mc({...Ee,enabled:!0})}),Ee.zoneId)Qt.set(gt,Ee.zoneId);return}let ve=await f.cloudflare.zoneIdFor(gt);if(Qt.set(gt,ve),!A)await C.ensureCustomDomain(v,{domain:gt,zoneId:ve,minTLS:Ft},ce,Ut);de(`custom domain ${gt} attached`,`attach custom domain ${gt}`),w.domains.push({domain:gt,status:A?"not attached":"pending"})},()=>w.domains.push({domain:gt,status:"error"}))}if(l.cache&&xe.length>0)await mh(l,xe.map((gt)=>gt.domain).filter((gt)=>f.claimed.get(gt)===v),Qt,f,de)}async function mh(l,f,C,A,w){let B=Cg(l.cache);if(!B||f.length===0)return;let v=new Map;for(let ce of f){let de=C.get(ce);if(!de)try{de=await A.cloudflare.zoneIdFor(ce)}catch(ct){A.warnings.push(`R2: could not resolve the zone for ${ce}, cache rule skipped: ${Bc(ct)}`);continue}v.set(de,[...v.get(de)??[],ce])}for(let ce of v.values()){let de={action:"set_cache_settings",description:`${Lt} ${ch}`,expression:`(${_t(ce)})`,enabled:!0,action_parameters:B};await Is(A,`cache rule for ${ce.join(", ")}`,async()=>{let ct=await A.cloudflare.getPhaseRules(ce[0],"http_request_cache_settings");if(Sg(ct,de))return;if(!A.dryRun){let xe=await A.cloudflare.putManagedPhaseRules(ce[0],"http_request_cache_settings",[de]);if(!xe.success)throw Error(xe.message||"cache rule write failed")}w(`cache rule updated for ${ce.join(", ")}`,`update cache rule for ${ce.join(", ")}`)})}}function Cg(l){if(l.edgeTtl===void 0&&l.browserTtl===void 0)return null;let f={cache:!0};if(l.edgeTtl!==void 0)f.edge_ttl={mode:"override_origin",default:l.edgeTtl};if(l.browserTtl!==void 0)f.browser_ttl={mode:"override_origin",default:l.browserTtl};return f}function Sg(l,f){let C=$t(f.expression),A=_n(f.expression),w=(ce)=>(ce.description||"").startsWith(Lt),B=(ce)=>ce.action===f.action&&ce.description===f.description&&(ce.enabled??!0)===(f.enabled??!0)&&_n(ce.expression)===A&&Sc(ce.action_parameters)===Sc(f.action_parameters),v=!1;for(let ce of l){if(!w(ce))continue;let de=$t(ce.expression);if(!C.some((xe)=>de.includes(xe)))continue;if(B(ce)&&C.every((xe)=>de.includes(xe))&&!v){v=!0;continue}return!1}return v}function Rg(l){let f={id:l.id,enabled:l.enabled??!0,conditions:{prefix:l.prefix??""}};if(l.expireAfterDays!==void 0)f.deleteObjectsTransition={condition:{type:"Age",maxAge:_c(l.expireAfterDays)}};else if(l.expireOn!==void 0)f.deleteObjectsTransition={condition:{type:"Date",date:l.expireOn}};if(l.abortMultipartUploadsAfterDays!==void 0)f.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:_c(l.abortMultipartUploadsAfterDays)}};if(l.infrequentAccessAfterDays!==void 0)f.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:_c(l.infrequentAccessAfterDays)}}];return f}function _c(l){return Math.round(l*86400)}function gh(l){let f=new Set,C=[];for(let A of l??[]){let w=typeof A==="string"?{domain:A}:A,B=w.domain?.trim().replace(/\.$/,"").toLowerCase();if(!B||f.has(B))continue;f.add(B),C.push({domain:B,minTLS:w.minTLS})}return C}function Mc(l){if(!l.enabled)return"disabled";let f=l.status?.ownership,C=l.status?.ssl;if(f==="active"&&C==="active")return"active";for(let A of[f,C])if(A==="error"||A==="blocked"||A==="deactivated")return A;return"pending"}async function Is(l,f,C,A){try{await C()}catch(w){if(w instanceof jn)throw w;l.warnings.push(`R2: ${f} failed: ${Bc(w)}`),A?.()}}function Bc(l){return l instanceof Error?l.message:String(l)}function Sc(l){if(Array.isArray(l))return`[${l.map(Sc).join(",")}]`;if(l&&typeof l==="object")return`{${Object.entries(l).filter(([,C])=>C!==void 0).sort(([C],[A])=>C.localeCompare(A)).map(([C,A])=>`${JSON.stringify(C)}:${Sc(A)}`).join(",")}}`;return JSON.stringify(l)}import{basename as bh,extname as Ah}from"node:path";import{createHash as fh}from"node:crypto";var hh="https://api.cloudflare.com/client/v4",Qn="TS_CLOUD_CONTENT_HASH",Vs="2025-09-01",xl="application/javascript+module",yh=10007,Ch=[1e4,9109];class ls extends Error{status;errors;constructor(l,f,C=[]){super(l);this.name="WorkersApiError",this.status=f,this.errors=C}hasCode(l){return this.errors.some((f)=>f.code===l)}}class Rc extends ls{permission;constructor(l,f,C,A=[]){super(`The Cloudflare API token is missing the "${l}" permission (${f}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,C,A);this.name="WorkersPermissionError",this.permission=l}}class Tc{name="cloudflare-workers";apiToken;accountId;fetchImpl;constructor(l){if(!l.apiToken)throw Error("Cloudflare Workers needs an API token");if(!l.accountId)throw Error("Cloudflare Workers needs an account id");this.apiToken=l.apiToken,this.accountId=l.accountId,this.fetchImpl=l.fetch??((f,C)=>fetch(f,C))}async request(l,f,C){let A={Authorization:`Bearer ${this.apiToken}`},w;if(C instanceof FormData)w=C;else if(C!==void 0)A["Content-Type"]="application/json",w=JSON.stringify(C);let B=await this.fetchImpl(`${hh}/accounts/${this.accountId}/workers${f}`,{method:l,headers:A,body:w}),v=await B.text(),ce;try{ce=JSON.parse(v)}catch{throw new ls(`Cloudflare Workers API returned ${B.status} with a non-JSON body: ${v.slice(0,200)}`,B.status)}if(!ce.success){let de=ce.errors??[],ct=de.map((xe)=>`${xe.code}: ${xe.message}`).join(", ");if(Sh(B.status,de))throw new Rc(Rh(f),`${l} ${f} -> ${B.status}${ct?`, ${ct}`:""}`,B.status,de);throw new ls(`Cloudflare Workers API error (${B.status}) on ${l} ${f}: ${ct||v.slice(0,200)}`,B.status,de)}return ce.result}scriptPath(l){return`/scripts/${encodeURIComponent(l)}`}async getSettings(l){try{return await this.request("GET",`${this.scriptPath(l)}/settings`)}catch(f){if(f instanceof Rc)throw f;if(f instanceof ls&&(f.hasCode(yh)||f.status===404))return null;throw f}}async getScript(l){return this.getSettings(l)}async uploadModuleScript(l,f){return this.request("PUT",this.scriptPath(l),Ag(f))}async ensureModuleScript(l,f){let C=qs(f),A=await this.getSettings(l);if(A&&Pc(A,f,C))return{action:"unchanged",hash:C};return await this.uploadModuleScript(l,Tg(f,C)),{action:A?"updated":"created",hash:C}}async listCustomDomains(l={}){let f=new URLSearchParams;if(l.service)f.set("service",l.service);if(l.hostname)f.set("hostname",l.hostname);if(l.zoneId)f.set("zone_id",l.zoneId);let C=f.toString(),A=C?`?${C}`:"";return await this.request("GET",`/domains${A}`)??[]}async attachCustomDomain(l,f){let C={hostname:l,service:f.service,environment:f.environment??"production"};if(f.zoneId)C.zone_id=f.zoneId;return this.request("PUT","/domains",C)}async detachCustomDomain(l){await this.request("DELETE",`/domains/${encodeURIComponent(l)}`)}async ensureCustomDomain(l,f,C){let w=(C??await this.listCustomDomains({hostname:l})).find((v)=>v.hostname.toLowerCase()===l.toLowerCase());if(w&&w.service===f.service)return{action:"unchanged",domain:w};if(w)throw Error(`${l} is attached to the Worker '${w.service}'. Detach it there first (Workers & Pages, ${w.service}, Settings, Domains & Routes); ts-cloud does not move it.`);let B=await this.attachCustomDomain(l,f);return{action:"attached",domain:{...B,hostname:B?.hostname||l}}}}function Sh(l,f){if(f.some((C)=>Ch.includes(C.code)))return!0;return(l===401||l===403)&&f.length===0}function Rh(l){if(l.startsWith("/domains"))return"Workers Routes: Edit (zone, for Workers custom domains) and Workers Scripts: Edit (account)";return"Workers Scripts: Edit (account)"}function Ag(l){if(!l.modules.some((A)=>A.name===l.mainModule))throw Error(`Worker main module '${l.mainModule}' is not one of the uploaded modules`);let f={main_module:l.mainModule,bindings:l.bindings??[],compatibility_date:l.compatibilityDate??Vs,compatibility_flags:l.compatibilityFlags??[],keep_bindings:["secret_text"]},C=new FormData;C.append("metadata",JSON.stringify(f));for(let A of l.modules)C.append(A.name,new Blob([A.content],{type:A.type}),A.name);return C}function qs(l){let f={mainModule:l.mainModule,modules:[...l.modules].sort((C,A)=>C.name.localeCompare(A.name)).map((C)=>({name:C.name,type:C.type,sha256:bg(C.content)})),bindings:[...l.bindings??[]].filter((C)=>C.name!==Qn).sort((C,A)=>C.name.localeCompare(A.name)),compatibilityDate:l.compatibilityDate??Vs,compatibilityFlags:[...l.compatibilityFlags??[]].sort()};return bg(qc(f))}function Tg(l,f=qs(l)){return{...l,bindings:[...(l.bindings??[]).filter((C)=>C.name!==Qn),{type:"plain_text",name:Qn,text:f}]}}function Pc(l,f,C){let A=l.bindings??[],w=A.find((B)=>B.name===Qn&&B.type==="plain_text");if(!w||w.text!==C)return!1;return(f.bindings??[]).every((B)=>{let v=A.find((de)=>de.name===B.name);if(!v||v.type!==B.type)return!1;let ce=B.type==="r2_bucket"?"bucket_name":B.type==="plain_text"?"text":void 0;return!ce||v[ce]===B[ce]})}function bg(l){return fh("sha256").update(l).digest("hex")}function qc(l){if(Array.isArray(l))return`[${l.map(qc).join(",")}]`;if(l&&typeof l==="object")return`{${Object.entries(l).filter(([,C])=>C!==void 0).sort(([C],[A])=>C.localeCompare(A)).map(([C,A])=>`${JSON.stringify(C)}:${qc(A)}`).join(",")}}`;return JSON.stringify(l)}async function $u(l){if(!await Bun.file(l).exists())throw Error(`Worker entry not found: ${l}`);let f;try{f=await Bun.build({entrypoints:[l],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(w){throw Error(`Bundling Worker ${l} failed: ${Th(w)}`)}if(!f.success)throw Error(`Bundling Worker ${l} failed: ${f.logs.map((w)=>String(w.message??w)).join("; ")}`);if(f.outputs.length!==1)throw Error(`Bundling Worker ${l} produced ${f.outputs.length} files (${f.outputs.map((w)=>w.path).join(", ")}); a Worker is uploaded as a single module, so remove the dynamic imports or asset imports that split it.`);let C=f.outputs[0];if(C.kind!=="entry-point")throw Error(`Bundling Worker ${l} produced a ${C.kind} instead of an entry module`);let A=await C.text();return{name:`${bh(l,Ah(l))}.js`,content:A,type:xl,size:new TextEncoder().encode(A).byteLength}}function Th(l){if(l instanceof AggregateError&&l.errors.length>0)return l.errors.map((f)=>f instanceof Error?f.message:String(f?.message??f)).join("; ");return l instanceof Error?l.message:String(l)}import{isAbsolute as Ph,resolve as wh}from"node:path";var Ih="https://api.cloudflare.com/client/v4",Dh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function vh(l,f={}){let C=f.log??(()=>{}),A={workers:[],warnings:[]},w=Object.entries(l.infrastructure?.workers??l.workers??{});if(w.length===0)return C("Workers: none declared, skipping."),A;if(!f.apiToken||!f.accountId){let ce=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),de=`Workers: ${w.length} Worker(s) declared but ${ce} is not set, skipping.`;return C(de),A.warnings.push(de),A}let B=l.infrastructure?.r2??l.r2,v={workers:new Tc({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),r2:new Si({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),cloudflare:new M(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),apiToken:f.apiToken,fetch:f.fetch??((ce,de)=>fetch(ce,de)),projectRoot:f.projectRoot??process.cwd(),dryRun:f.dryRun===!0,warnings:A.warnings,log:C,r2ConfigDomains:bS(B),r2Buckets:B,claimed:new Map};for(let[ce,de]of w){let ct=de?.name;if(!ct||!Dh.test(ct)){A.warnings.push(`Workers: '${ce}' has an invalid name '${ct??""}' (1-63 chars: lowercase letters, digits, '-' and '_'), skipping.`);continue}if(!de.entry){A.warnings.push(`Workers: ${ct} has no entry, skipping.`);continue}C(`Workers: ${v.dryRun?"checking":"reconciling"} ${ct}...`);let xe={name:ct,changes:[],domains:[]};A.workers.push(xe),await Eh(de,xe,v);for(let Ut of xe.changes)C(`Workers: ${ct}: ${Ut}`)}return A}async function Eh(l,f,C){let A=l.name,w=Ph(l.entry)?l.entry:wh(C.projectRoot,l.entry),B;try{B=await $u(w)}catch(ce){throw Error(`Worker ${A}: ${gs(ce)}`)}f.changes.push(`bundled ${PS(B.size)}`);let v={mainModule:B.name,modules:[{name:B.name,content:B.content,type:B.type}],bindings:Pg(l,C),compatibilityDate:l.compatibilityDate??Vs,compatibilityFlags:l.compatibilityFlags??[]};if(C.dryRun){let ce=await C.workers.getSettings(A);f.changes.push(ce&&Pc(ce,v,qs(v))?"unchanged":"would upload")}else{let{action:ce}=await C.workers.ensureModuleScript(A,v);f.changes.push(ce==="unchanged"?"unchanged":"uploaded")}for(let ce of TS(l.customDomains))await cS(A,ce,f,C)}async function cS(l,f,C,A){let w=(gt)=>{C.domains.push({domain:f,status:gt})},B=(gt)=>{A.warnings.push(`Workers: ${gt}`),w("conflict")},v=A.claimed.get(f);if(v&&v!==l){B(`${f} is declared on both ${v} and ${l}; leaving it on ${v}.`);return}A.claimed.set(f,l);let ce=A.r2ConfigDomains.get(f);if(ce){B(`${f} is also declared as a custom domain of the R2 bucket '${ce}' (r2.buckets). A hostname serves either a bucket or a Worker. Remove it from the bucket's customDomains and detach it in the dashboard (R2, ${ce}, Settings, Custom Domains) first; to serve the bucket through the Worker, bind it with bindings.r2Buckets instead.`);return}let de=await dS(A);if(de===null){w("error");return}let ct=de.find((gt)=>gt.hostname.toLowerCase()===f);if(ct?.service===l){w("active");return}if(ct){B(`${f} is attached to the Worker '${ct.service}'. Detach it there first (Workers & Pages, ${ct.service}, Settings, Domains & Routes); it is not moved automatically.`);return}let xe=(await CS(A))?.get(f);if(xe){B(`${f} is attached to the R2 bucket '${xe}' as a custom domain. Detach it first (R2, ${xe}, Settings, Custom Domains, then re-run the deploy); it is not detached automatically. To serve the bucket through the Worker, bind it with bindings.r2Buckets.`);return}let Ut;try{Ut=await A.cloudflare.zoneIdFor(f)}catch(gt){A.warnings.push(`Workers: could not resolve the zone for ${f}, not attached: ${gs(gt)}`),w("error");return}let Qt=await RS(A,Ut,f);if(Qt.length>0){let gt=Qt.map((lt)=>`${lt.type} ${lt.content}`).join(", ");B(`${f} already has a DNS record (${gt}). A Worker custom domain creates its own record, so Cloudflare will not attach over it. Delete the record first (DNS, Records), then re-run the deploy; it is not deleted automatically.`);return}if(A.dryRun){C.changes.push(`would attach custom domain ${f}`),w("not attached");return}try{await A.workers.ensureCustomDomain(f,{service:l,zoneId:Ut},de),C.changes.push(`custom domain ${f} attached`),de.push({id:"",hostname:f,service:l,zone_id:Ut}),w("pending")}catch(gt){A.warnings.push(`Workers: custom domain ${f} on ${l} failed: ${gs(gt)}`),w("error")}}async function dS(l){if(l.attached!==void 0)return l.attached;try{l.attached=await l.workers.listCustomDomains()}catch(f){l.warnings.push(`Workers: could not list Worker custom domains, none attached: ${gs(f)}`),l.attached=null}return l.attached}async function CS(l){if(l.r2AccountDomains!==void 0)return l.r2AccountDomains;let f=new Map;try{let C=(await l.r2.listBuckets()).map((A)=>({name:A.name}));for(let A of Object.values(l.r2Buckets?.buckets??{}))if(A.jurisdiction&&A.jurisdiction!=="default")C.push({name:A.name,jurisdiction:A.jurisdiction});for(let A of C){let w=await l.r2.listCustomDomains(A.name,{jurisdiction:A.jurisdiction}).catch(()=>[]);for(let B of w)f.set(B.domain.toLowerCase(),A.name)}l.r2AccountDomains=f}catch(C){l.log(`Workers: could not check R2 custom domains (${gs(C)}); relying on the DNS check.`),l.r2AccountDomains=null}return l.r2AccountDomains}async function RS(l,f,C){try{let A=await l.fetch(`${Ih}/zones/${f}/dns_records?name=${encodeURIComponent(C)}&per_page=100`,{method:"GET",headers:{Authorization:`Bearer ${l.apiToken}`}}),w=await A.json();if(!w?.success)throw Error(`HTTP ${A.status}`);return(w.result??[]).filter((B)=>B.name?.toLowerCase()===C).map((B)=>({type:B.type??"?",content:B.content??""}))}catch(A){return l.log(`Workers: could not read DNS records for ${C} (${gs(A)}); attaching anyway.`),[]}}function Pg(l,f){let C=[],A=new Set,w=(v)=>{if(v===Qn)return f.warnings.push(`Workers: ${l.name}: binding name ${Qn} is reserved for ts-cloud, ignored.`),!1;if(A.has(v))return f.warnings.push(`Workers: ${l.name}: binding ${v} is declared twice; the first one wins.`),!1;return A.add(v),!0},B=new Map;for(let v of Object.values(f.r2Buckets?.buckets??{}))if(v.jurisdiction&&v.jurisdiction!=="default")B.set(v.name,v.jurisdiction);for(let[v,ce]of Object.entries(l.bindings?.r2Buckets??{})){if(!w(v))continue;let de=B.get(ce);C.push(de?{type:"r2_bucket",name:v,bucket_name:ce,jurisdiction:de}:{type:"r2_bucket",name:v,bucket_name:ce})}for(let[v,ce]of Object.entries(l.bindings?.vars??{}))if(w(v))C.push({type:"plain_text",name:v,text:String(ce)});return C}function bS(l){let f=new Map;for(let C of Object.values(l?.buckets??{}))for(let A of C?.customDomains??[]){let w=$g(typeof A==="string"?A:A.domain);if(w)f.set(w,C.name)}return f}function TS(l){return[...new Set((l??[]).map($g).filter(Boolean))]}function $g(l){return(l??"").trim().replace(/\.$/,"").toLowerCase()}function PS(l){if(l<1024)return`${l} B`;if(l<1048576)return`${(l/1024).toFixed(1)} KB`;return`${(l/1024/1024).toFixed(1)} MB`}function gs(l){return l instanceof Error?l.message:String(l)}export{dl as ABTestManager,ge as ACMClient,Sr as ACMDnsValidator,tg as ACME_DIRECTORIES,Pe as AI,ql as API_IDEMPOTENCY_TTL_MS,Gl as API_TOKEN_DEFAULT_TTL_MS,Vl as API_TOKEN_MAX_TTL_MS,rs as API_VERSION,me as AUTHORIZATION_CAPABILITIES,Fl as AUTH_ACTION_TOKEN_TTL_MS,Ul as AUTH_MFA_CHALLENGE_TTL_MS,Ql as AUTH_OIDC_TRANSACTION_TTL_MS,Ye as AUTH_SESSION_ABSOLUTE_TTL_MS,Ml as AUTH_SESSION_IDLE_TTL_MS,YA as AWSAPIError,n as AWSClient,h as AWSCloudFormationClient,S as AWSCloudFrontClient,sl as AWSConfigManager,vI as AWS_PSEUDO_PARAMETERS,Ne as AWS_REGIONS,zf as AcmeClient,jr as AlertEvaluator,ki as AlertStore,po as AnomalyConfigStore,Kd as ApiGateway,i as ApiServiceError,oc as ApplicationAutoScalingClient,Yr as Arn,k as AssetHasher,q as Auth,Xi as AuthenticationStore,Li as AutomationApiService,Yi as AutomationIdentityStore,ma as AwsAuroraDataAdapter,Sa as AwsAuroraTransport,$a as AwsDatabaseBackupSource,vr as AwsDriver,fa as AwsElastiCacheDataAdapter,Ia as AwsElastiCacheTransport,wf as AwsIamCapabilityScanner,Ha as AwsInfrastructureBackupSource,pa as AwsRdsDataAdapter,ya as AwsRdsTransport,Ff as AwsRegionalDriver,Va as AwsSecretsManagerConfigurationBackend,Hp as AwsSpendTransport,qa as AwsSsmConfigurationBackend,ps as BackupCoordinator,nl as BackupManager,_a as BackupStore,ef as BatchProcessingManager,Nn as BedrockClient,Pn as BedrockRuntimeClient,Yl as BitbucketSourceAdapter,cl as BlueGreenManager,Vm as BounceComplaintHandler,_m as BuildOptimizationManager,Iu as BunDockerRuntime,Ju as BunDockerVolumeRuntime,Wu as BunFilesystemArchiveRuntime,he as CDN,Bo as CHAIN_HEADER,Lt as CLOUDFLARE_MANAGED_RULE_PREFIX,Gd as CLOUDFRONT_FAILOVER_STATUS_CODES,lC as COMMON_CROSS_ACCOUNT_ROLES,Qn as CONTENT_HASH_BINDING,Ge as CONTROL_PLANE_SCHEMA_VERSION,wo as Cache,Vi as CanaryManager,Bm as CertificateManager,dA as CloudBlockVolumeDriver,js as CloudDriverFactory,We as CloudError,sm as CloudFormationBuilder,h as CloudFormationClient,S as CloudFrontClient,ol as CloudTrailManager,Ie as CloudWatchLogsClient,ig as CloudflarePagesProvider,M as CloudflareProvider,Sy as CommandHistory,z as Communication,Qr as ComposeApplicationService,zt as ComposeApplicationStore,kt as ComprehendClient,a as Compute,Gp as ComputeSpendTransport,Po as ConfigurationError,za as ConfigurationService,Ga as ConfigurationStore,Rn as ConnectClient,Aa as ContainerDataAdapter,ml as ContainerRegistryManager,Qa as ControlPlaneBackupSource,ka as ControlPlaneCleanupDriver,vi as ControlPlaneStore,lo as CounterTracker,Ct as CredentialError,Im as CrossRegionReferenceManager,MA as DASHBOARD_ENTRY,FA as DASHBOARD_PORT_BASE,UA as DASHBOARD_PORT_SPAN,$A as DASHBOARD_STATE_DIR,Qo as DEFAULT_ATTACK_MODE_HOURS,Vs as DEFAULT_COMPATIBILITY_DATE,Nd as DEFAULT_DDOS_THRESHOLDS,zp as DEFAULT_FAILOVER_STATUS_CODES,ud as DEFAULT_METER_MAPPINGS,dd as DEFAULT_PRICE_BOOK,rn as DEFAULT_RECURSION_LIMITS,Gn as DEFAULT_RPX_CERTS_DIR,K as DEFAULT_SERVICE_LIMITS,Od as DEFAULT_STATE_DIR,dg as DEFAULT_STATIC_ASSET_EXTENSIONS,xA as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,CA as DEFAULT_TELEMETRY_POLICY,wp as DEFAULT_THRESHOLDS,iA as DEPLOYMENT_QUEUE_KINDS,ko as DEPTH_HEADER,Vr as DETECTABLE_SIGNALS,fu as DIAGNOSTIC_PRESETS,Zm as DLQMonitoringManager,H as DNS,Hm as DNSSECManager,os as DataServiceLifecycle,ga as DataServiceStore,Yt as Database,Nm as DatabaseUserManager,U as DebugLogger,BA as DependencyGraph,j as Deployment,XA as DeploymentError,il as DisasterRecoveryManager,Mn as DnsProviderFactory,or as DockerDataTransport,oa as DockerDiscoveryAdapter,Ur as DockerNamedVolumeDriver,Ua as DockerVolumeBackupSource,c as DurableOperationQueue,ro as DurableQueueWorker,_e as DynamoDBClient,Br as EC2Client,$e as ECRClient,nt as ECSClient,fr as EFSClient,rc as ELBv2Client,uA as ENFORCEMENT_ACTIONS,Pi as ENFORCEMENT_DESCRIPTIONS,N as ENFORCEMENT_SEVERITY,ep as ENVIRONMENT_LABEL,pu as EcsRuntimeAdapter,Uo as EdgeRateLimiter,st as ElastiCacheClient,m as Email,Km as EmailAdvanced,qm as EmailAnalyticsManager,On as EmailClient,Wm as EmailHandlers,zm as EmailTemplateManager,ba as EncryptedDataSecretStore,ZA as ErrorCodes,pr as EventBridgeClient,Lf as EventBridgeJobAdapter,ja as ExternalConfigurationBackend,To as FAILOVER_REPLICA_POLICY_SID,Ym as FIFOQueueManager,$S as FLY_MACHINES_API,Op as FOCUS_VERSION,Xd as FileCache,ze as FileSystem,Ma as FilesystemBackupSource,Ea as FleetService,Ca as FleetStore,sc as FlyApiError,Dg as FlyClient,e as Fn,Zl as GiteaSourceAdapter,Jl as GithubSourceAdapter,Xl as GitlabSourceAdapter,bm as GlobalResourceManager,Me as GoDaddyProvider,al as GuardDutyManager,pt as HOST_SITES_DIR,ny as HashCache,pf as HealthCheckManager,qe as HealthCheckRunner,Dr as HetznerClient,Te as HetznerDriver,be as IAMClient,hc as IPV6_EXCLUDED_HOST_LABELS,Om as ImageScanningManager,_g as InfrastructureGenerator,Yc as InvalidOperationTransitionError,It as JobLoader,$f as JobProviderReconciler,ua as JobService,da as JobStore,gr as KendraClient,uf as LARAVEL_SERVERLESS_BUILD_STEPS,E as LambdaClient,Mm as LambdaConcurrencyManager,Qm as LambdaDLQManager,Fm as LambdaDestinationsManager,Lm as LambdaLayersManager,mu as LambdaRuntimeAdapter,Um as LambdaVPCManager,$m as LambdaVersionsManager,Cn as LocalEncryptedConfigurationBackend,Fa as LogicalDatabaseBackupSource,ul as LogsManager,Uy as MANAGED_NODE_VERSIONS,Uc as MANAGEMENT_DASHBOARD_SITE,om as MANAGEMENT_DASHBOARD_SITE_PREFIX,Wi as MAX_CONTROL_HOURS,Zc as MAX_CONTROL_PLANE_ERROR_BYTES,bp as MAX_CONTROL_PLANE_JSON_BYTES,oo as METERS,lA as METER_KEYS,gA as MICRO_CENTS,Rp as MIN_PROJECTION_CONFIDENCE,pg as MTA_STS_PORT,Na as MaintenanceService,Pa as MaintenanceStore,ie as Messaging,Rm as MetricsManager,Dm as MigrationManager,fm as MockCloudFormation,Am as MockDynamoDB,hm as MockS3,Ro as Monitoring,vm as MultiAccountManager,Sm as MultiRegionManager,py as MultiStepProgress,y as Network,mf as NetworkSecurityManager,Bi as NotificationRouter,Jp as ORIGIN_CONNECTION_ATTEMPTS,Xp as ORIGIN_CONNECTION_TIMEOUT,Kp as ORIGIN_GROUP_ALLOWED_METHODS,bI as ORIGIN_GROUP_ID_SUFFIX,Wp as ORIGIN_GROUP_SELECTION_CRITERIA,nc as OpenSearchClient,mt as OptimisticConcurrencyError,Tm as OrganizationManager,eh as PAGES_MAX_FILE_BYTES,Jy as PHP_DEFAULT_EXCLUDES,Qy as PHP_LAYER_EXTENSIONS,Zg as PROJECT_LABEL,at as PROXIABLE_RECORD_TYPES,T as ParameterStore,Pm as PerformanceManager,ne as Permissions,ic as PersonalizeClient,Ke as Phone,Jm as PhoneAdvanced,nm as PhoneHandlers,Ta as PlacementService,va as PlacementStore,kn as PollyClient,le as PorkbunProvider,un as PreDeployScanner,tl as PreviewEnvironmentManager,Fr as PreviewEnvironmentService,Ve as PreviewEnvironmentStore,rl as PreviewNotificationService,gy as ProgressBar,ll as ProgressiveDeploymentManager,Ho as ProtectionControlStore,kA as Pseudo,G as Queue,Ti as QueueCancellationError,tf as QueueManagementManager,dI as QueuePresets,to as QueueTimeoutError,ti as R2ApiError,jn as R2NotEnabledError,Si as R2Provider,hg as R2_NOT_ENABLED_ERROR_CODE,Nl as RATE_LIMIT_KEY_SEPARATOR,J as RDSClient,by as RECOMMENDED_ACCOUNT_STRUCTURES,dC as RECOMMENDED_SCPS,Cf as RELEASE_QUEUE_KINDS,hy as REPL,yy as REPLCommandBuilder,Ay as REPLContext,tp as ROLE_LABEL,iy as RateLimiter,lI as RealtimePresets,_p as RecordingSpendTransport,ji as RecursionGuard,bt as Redirects,Cm as RegionPairManager,Ra as RegionService,wa as RegionStore,je as Registry,Bt as RekognitionClient,Et as ReleaseService,Xo as ReleaseStore,Mf as RemoteBuildService,gl as ReplicaManager,ff as ResourceManagementManager,te as RetryableOperationError,I as Route53Client,tc as Route53DomainsClient,X as Route53Provider,Gm as Route53ResolverManager,hl as Route53RoutingManager,ye as RuntimeOperationService,ca as RuntimeStreamRegistry,La as S3BackupDestinationAdapter,o as S3Client,F as S3Error,ru as SECRET_PATTERNS,Bp as SENSITIVITY_THRESHOLDS,ot as SESClient,V as SMS,it as SNSClient,Qp as SPEND_CYCLE_SECONDS,vd as SPEND_GATE_SETTING,wA as SPEND_LEASE_SETTING,ae as SQSClient,we as SSH_BOOTSTRAP_VERSION,si as SSH_PREFLIGHT_SCRIPT,Re as SSMClient,qp as STATE_DIR_ENV_VAR,Ts as STATIC_SITE_ZONE_SETTINGS,qd as STORAGE_FAILOVER_METADATA_KEY,Se as STSClient,Bn as SchedulerClient,Zt as Search,gn as SecretFindingScanner,Ui as Secrets,pl as SecretsManager,W as SecretsManagerClient,km as SecretsRotationManager,b as Security,tr as SecurityHubManager,ln as SecurityPostureStore,vt as SecurityScannerRunner,xm as SecurityScanningManager,jm as SenderReputationManager,_f as ServerCronJobAdapter,ha as ServerDataAdapter,so as ServerPathVolumeDriver,fl as ServiceMeshManager,zd as Sftp,fo as SignalSource,Xm as SmsAdvanced,Ot as SmsClient,im as SmsHandlers,dc as SmsVoiceClient,Yo as SourceConnectionStore,ir as SourceProviderError,Td as SpendCapError,qr as SpendGate,Fp as SpendLoopLease,Io as SpendNotificationRouter,Up as SpendRunner,Wt as SpendService,Ri as SpendStore,my as Spinner,Nr as SshDriver,fn as SshFleetDriver,Em as StackDependencyManager,EI as StacksIntegration,gf as StaticSiteManager,De as Storage,Rl as StorageAdvancedManager,xn as SupportClient,rr as SyntheticsManager,bu as SystemFleetSshTransport,Pr as SystemSshTransport,aa as SystemdDiscoveryAdapter,xo as TRACE_HEADER,fy as TaskList,At as TelemetryStore,Qd as TemplateBuilder,Yd as TemplateCache,xt as TextractClient,Dn as TranscribeClient,ur as TranslateClient,Hf as TransportDisasterRecoveryDriver,Qf as TransportPlatformMaintenanceDriver,as as TransportRemoteBuildDriver,ia as TrivyImageScanner,Jo as TsCloudApiError,jl as TsCloudClient,TA as URGENT_SPEND_EVENTS,Dp as USER_VISIBLE_ACTIONS,Da as UnavailableRegionalDriver,ue as UnifiedDnsValidator,Ys as UnsupportedSchemaVersionError,lm as ValidationError,mr as VoiceClient,io as VolumeService,jt as VolumeStore,xl as WORKER_MODULE_TYPE,ls as WorkersApiError,Rc as WorkersPermissionError,Tc as WorkersProvider,LA as Workflow,wm as XRayManager,Ny as abTestManager,zl as activateImmutableRelease,Xg as addDns01ChallengeRecord,An as addSiteToCloudConfig,wt as ageSeconds,pd as aggregateDeltas,yp as allocateSitePorts,rm as amazonLinuxImageId,_A as amazonLinuxImageParameter,SI as analyzeStackDiff,Ni as anomalyOptionsForSignal,Go as applyControlsToDdos,_l as applyControlsToRateLimits,Bs as applyDeclaredZoneSettings,Wr as applyMitigationFactor,Fh as applyPlan,Ls as applyZoneMigration,Al as artifactKey,yt as assertOriginGroupMethods,Zi as assertReleaseStrategy,bA as assertSpendAllows,Vh as attachConflicts,qh as attachIsViable,Gh as attachPreconditions,au as attachProvenanceToRelease,sa as attachSbomToRelease,su as attachVulnerabilitySummary,If as authEncryptionKeyFile,P as authorizeOrganization,xf as authorizeRuntimePath,Fb as autocomplete,vy as awsConfigManager,zu as backupCredentialStatus,Cy as backupManager,lb as batch,eE as batchProcessingManager,Ko as beginOidcAuthorization,Dy as blueGreenManager,KC as bounceComplaintHandler,ft as budgetWindow,Ya as buildAndPushServerlessImage,nE as buildBunRuntimeLayerZip,Xh as buildCertificatePackScript,Kh as buildCertificateStateScript,Yh as buildCertificateUnpackScript,Wd as buildCloudFormationTemplate,xc as buildCloudInitFirstBoot,nd as buildComposeLogsCommand,aI as buildComposeRuntimeCommand,cI as buildComposeScaleCommand,id as buildComposeShellCommand,fp as buildDrainSourceScript,Nh as buildDrainedSiteScanScript,jd as buildFailoverReplicaPolicyStatement,cr as buildFunctionEnv,mp as buildHealthGateScript,Xn as buildHostCleanupDeployScript,Gs as buildHostCleanupInstallScript,Jn as buildHostCleanupScript,Ci as buildHostSitePortsScript,Ud as buildMailEnv,Ks as buildManagementDashboardArtifact,WS as buildMediaCdnPlan,gg as buildMtaStsPolicy,uh as buildMtaStsServer,rE as buildNodeRuntimeLayerZip,FC as buildOptimizationManager,Vd as buildOriginGroup,Xr as buildOriginGroups,gc as buildOriginGuardRule,ap as buildPauseWorkersScript,aE as buildPhpRuntimeLayerZip,tm as buildReplicationConfiguration,em as buildReplicationRole,up as buildRestoreScript,Y as buildRpxConfig,Fe as buildRpxFragmentRefreshScript,Qh as buildSetHostnameScript,Zn as buildSiteDeployScript,lp as buildSnapshotScript,hp as buildSourceStateScript,zn as buildSshArgs,ni as buildSshBootstrapScript,uc as buildStaticSiteCacheRules,ei as buildStaticSiteDeployScript,gp as buildTargetStateScript,Ag as buildUploadForm,cp as buildWorkersStateScript,$u as bundleWorker,du as bytes,Cg as cacheRuleParameters,Py as canaryManager,hn as canonicalJson,Tt as capabilities,ar as capacity,Sb as categorizeChanges,LC as certificateManager,Jh as certificatesMatch,eb as checkIAMPermissions,af as checkInvocation,rb as checkServiceQuotas,sy as chunk,nR as cleanupDns01Challenge,nS as clearSigningKeyCache,ea as cloneSourceBinding,oy as cloudConfigSchema,Fg as cloudDrivers,Ty as cloudTrailManager,sg as collectAssets,$o as collectPhpAppEntries,lg as collectServerDnsDomains,Cp as completeComposeVolumeDeletion,Wo as completeOidcAuthorization,HI as composePresets,eo as composeProjectName,Sl as composeServerlessAppTemplate,DA as compositeSpendTransport,Nt as compressBackup,lS as config,lc as configOrigins,yu as connectionGuidance,Ly as containerRegistryManager,rA as controlPlaneDatabaseFile,Jc as controlPlaneMigrations,NI as createApiBackendPreset,na as createApiV1Handler,SS as createAsgBuildDriver,Ku as createBackupQueueHandlers,Wy as createCliHandler,O as createCloudDriver,Bu as createCloudFrontPolicy,JI as createCredentialProvider,UI as createDashboardSite,_I as createDataPipelinePreset,Su as createDataServiceQueueHandlers,sd as createDeploymentQueueHandlers,D as createDnsProvider,yS as createEcsBuildDriver,wd as createEnforcementHandlers,um as createError,Jd as createExistingStaticFullStackPreset,Cu as createFleetQueueHandlers,PI as createFullStackAppPreset,Fs as createGoDaddyValidator,oE as createHandlers,zy as createHttpHandler,BI as createJamstackPreset,Au as createJobQueueHandlers,MI as createLaravelPreset,LI as createMLApiPreset,Pu as createMaintenanceQueueHandlers,_S as createMediaAccessToken,xI as createMicroservicesPreset,Rb as createMockAWS,wI as createNodeJsServerPreset,RI as createNodeJsServerlessPreset,vs as createObjectStorageClient,Ms as createPorkbunValidator,GI as createPreset,Mo as createPresignedUrl,Yy as createPresignedUrlAsync,Ky as createQueueHandler,OI as createRealtimeAppPreset,vu as createRegionQueueHandlers,ou as createReleaseProvenance,Wl as createReleaseQueueHandlers,hS as createRemoteBuildQueueHandlers,Us as createRoute53Validator,Bf as createRuntimeAdapters,JA as createS3Client,AS as createServerBuildDriver,FI as createServerlessLaravelPreset,DI as createServerlessNodePreset,cg as createSmsInfrastructure,et as createSourceAdapter,TI as createStaticSitePreset,$I as createTraditionalWebAppPreset,od as createVolumeQueueHandlers,kI as createWordPressPreset,Je as createZip,zb as crossRegionReferenceManager,En as dashboardActions,zs as dashboardCredentialsFile,mn as dataServiceCapabilities,OC as databaseUserManager,$l as decodeBase32,Oe as decompressBackup,Yf as decryptBackup,Vo as defaultConfig,mm as defaultLocalConfig,Bl as defaultRateLimitRules,yr as delegateZone,Ns as delegateZoneFromConfig,Gu as deleteFailoverReplicaBuckets,Ja as deleteStaticSite,Hc as deployAllComputeSites,xa as deployServerlessApp,Vu as deploySite,Ws as deploySiteRelease,As as deployStaticSite,Xa as deployStaticSiteFull,vn as deployStaticSiteWithExternalDns,Tn as deployStaticSiteWithExternalDnsFull,kS as deployToFly,Md as deploymentCoexistenceError,QA as deriveManagementDashboardPort,ks as describeDelegation,Ol as describePosture,xs as describeZoneSettings,Of as desiredJobProviderState,kp as detectAnomalies,jp as detectDeploymentTargets,pc as detectDnsProvider,bd as detectLatestAnomaly,YI as detectMisconfigurations,Dl as detectServiceRegion,td as diffCompose,hb as diffTemplates,Zo as discoverGitRefs,zo as discoverOidcProvider,lu as discoverRuntimeInventory,ZC as dlqMonitoringManager,mc as dnsProviders,jC as dnssecManager,Pf as dockerWorkloads,cs as documentDigest,Mc as domainStatus,Ey as drManager,Qe as driverStatePath,uu as ecsWorkloads,qt as effectiveCapabilities,WC as emailAnalyticsManager,XC as emailTemplateManager,Ji as encodeBase32,Xf as encryptBackup,cu as ensureDefaultSecurityPolicies,Uu as ensureFailoverReplicaBuckets,gi as ensureFirewall,fi as ensureManagementDashboard,pi as ensureServer,ui as ensureSshKey,ee as escapeSecLang,fd as evaluateBudget,ai as evaluatePreflight,So as evaluateTelemetryAlertRules,hu as eventBridgeScheduleInput,jy as eventToRequest,yA as ewma,ed as exportCompose,Os as exportRoute53Zone,cm as extendPreset,YC as fifoQueueManager,db as findChangedFiles,vp as findMapping,Ep as findPriceEntry,DS as flyDeployOptions,Ou as flyIpType,vg as flyMachineConfig,mC as formatAccountStructure,jh as formatAttachPlan,kb as formatBytes,zr as formatCents,II as formatDiff,Bh as formatDrainedSiteRefusal,Bb as formatDuration,Qb as formatFlagSuggestions,Vb as formatHistory,qb as formatHistoryStats,Lh as formatInventory,Ob as formatKeyValue,xb as formatList,Mh as formatPlan,di as formatPreflightFindings,Nb as formatProgressBar,Iy as formatRegion,sC as formatRegionList,Tf as formatScanResults,_b as formatSuggestion,Db as formatTable,Gr as formatTimeToExhaustion,Pb as formatTree,jA as fromEC2Metadata,zA as fromECSMetadata,VA as fromEnvironment,qA as fromSharedCredentials,KA as fromWebIdentity,Cl as functionFingerprint,qn as gatewayHostnames,bl as generateAppImageDockerfile,DC as generateApprovalConfig,rf as generateBootstrap,dy as generateCleanupWorkflow,ly as generateCostReportWorkflow,gC as generateCrossAccountRoleCF,nu as generateCycloneDxSbom,TC as generateDeploymentConfig,IC as generateDeploymentPipeline,fC as generateDeploymentWorkflow,Wa as generateExternalDnsStaticSiteTemplate,tR as generateHttpsServerCode,iu as generateImageSbom,eR as generateLetsEncryptUserData,t as generateLogicalId,vC as generateManualPipeline,SC as generateMatrixWorkflow,wC as generateMultiEnvConfig,bC as generateMultiEnvPipeline,hC as generateMultiEnvWorkflow,AC as generatePRPreviewWorkflow,PC as generateParallelConfig,lf as generatePhpFpmConfig,nf as generatePhpLayerDockerfile,CC as generatePreviewPipeline,cy as generatePreviewWorkflow,r as generateResourceName,RC as generateScheduledConfig,EC as generateScheduledPipeline,yC as generateScheduledWorkflow,hs as generateStaticSiteTemplate,x as generateUbuntuAppCloudInit,dm as getAccountId,Xb as getAllRegions,rC as getClosestRegion,Hb as getCommandUsage,nA as getComposeTemplate,Af as getConfig,$b as getContextualHelp,Hi as getCredentials,Ib as getDeploymentStrategy,bb as getDiffStats,Ab as getDiffSummary,ey as getErrorDetails,el as getLocalConfig,Tb as getLocalCredentials,vb as getLocalEndpoint,wb as getLocalEnvVars,nb as getQuotaUsageSummary,uC as getRecommendedStructure,Gi as getRegion,oC as getRegionStats,Zb as getRegionsByCompliance,Yb as getRegionsByLocation,eC as getRegionsByPricingTier,ty as getRequiredPermissions,iS as getSigningKeyCacheSize,ag as getSmsInfrastructureStatus,uI as getTimestamp,Fo as globMatches,Js as globToRegex,Kb as globalResourceManager,Di as governingLimitCents,Qu as grantFailoverReplicaAccess,wy as guardDutyManager,bo as handleSpendRequest,Vn as hasAutoWwwVariant,er as hasManagementDashboardSite,Wc as hasProxyUpstream,sb as hashBuffer,ob as hashDirectory,gm as hashFile,ab as hashManifest,pm as hashString,dE as healthCheckManager,Un as hostAcceptsIpv6,_t as hostCondition,qo as hotp,Hr as hourBucket,AA as hourBucketsBetween,MC as imageScanningManager,us as infraEnvFromOutputs,vl as inspectInvocation,Vy as installRecursionFetch,Ss as invalidateCache,of as invocationContext,OA as isArmInstanceType,Lb as isLikelyTypo,Hn as isLocalDatabase,Eb as isLocalDevelopment,Zr as isManagementDashboardSiteName,hr as isNameserverRegistrar,sS as isNodeCryptoAvailable,Id as isOperationAllowed,yo as isQuietHours,vo as isS3RestEndpoint,Ai as isSafePattern,Ld as isStateDirConfigured,$d as isStatePath,Kr as isValidCidr,tC as isValidRegion,wi as isValidTimeZone,oS as isWebCryptoAvailable,Ar as isZoneHost,pn as jobProviderCapability,Es as keyMatchesFilters,HC as lambdaConcurrencyManager,qC as lambdaDLQManager,GC as lambdaDestinationsManager,UC as lambdaLayersManager,VC as lambdaVPCManager,QC as lambdaVersionsManager,gu as lambdaWorkloads,Tl as laravelServerlessEnvDefaults,Mr as listComposeTemplates,ts as listSourceReferences,Ll as loadCloudConfig,Jt as loadTelemetryPolicy,By as logsManager,Cd as lookbackHoursForSignal,NA as mailEnabled,Fd as mailFirewallPorts,Uf as maintenanceWindowOpen,hf as makeAWSRequest,eS as makeAWSRequestAsync,Zy as makeAWSRequestOnce,Sg as managedRuleInSync,am as managementDashboardSiteName,Tu as manifestDigest,on as matchTotpCounter,BS as mediaObjectHeaders,go as median,Pp as medianAbsoluteDeviation,hd as mergeDecisions,en as mergeInfrastructure,fA as mergePriceBooks,gd as meterTelemetry,kC as metricsManager,rg as migrateObjectStorage,BC as migrationManager,aC as multiAccountManager,jb as multiRegionManager,iR as needsRenewal,lE as networkSecurityManager,Rt as nextScheduleRuns,Ce as normalizePublicIpv6,ke as normalizeRuntimeStatus,tt as normalizeScheduleExpression,Ef as normalizeSourceEvent,Ue as normalizeSshPublicKey,Lp as normalizeTelemetryPolicy,bi as occupiedHostPorts,ra as openApiDocument,ho as optionsForSignal,cC as organizationManager,wl as packagePhpApp,tn as packageServerlessApp,og as pagesAssetHash,rh as pagesDnsRecord,Zd as parallel,ub as parallelMap,gb as parallelWithRetry,Wh as parseCertificateState,El as parseChain,$r as parseCompose,sI as parseComposeCatalog,Df as parseDockerInspect,Xu as parseDotenv,kh as parseDrainedSites,Ei as parseHostSiteFragments,rS as parseJSONResponse,oi as parsePreflightFacts,Ap as parseSourceDrained,Nf as parseSystemdRecords,pp as parseTargetReady,Kc as parseUpstreamPort,dp as parseWorkersPaused,tS as parseXMLResponse,Oi as pathTemplate,jc as pendingSteps,uo as percentOfLimit,xC as performanceManager,Il as phpLayerBuildStage,Hy as phpLayerPackages,nn as phpRuntimeLayerAssets,oI as planComposeTemplateUpgrade,Ad as planEnforcement,sp as planIsDestructive,Vp as planMitigation,Uh as planServerRename,Zh as planSiteMove,_s as planZoneMigration,Mt as policyTag,ci as preflightFailed,ay as previewManager,uy as previewNotifications,Dt as previewSchedule,hA as previousBudgetWindow,ao as priceUsage,pA as priceUsageLines,Oh as probeHostRoutes,Fc as probeOriginTls,fb as processInChunks,eu as processSourceWebhook,is as productionChangeReview,ky as progressiveDeploymentManager,md as projectSpend,Oo as propagationHeaders,Za as providerEndpoint,wu as publicKeyFingerprint,Ln as qualifyName,tE as queueManagementManager,cb as quickHash,yg as r2Endpoint,ah as r2S3Credentials,kl as rateLimitHeaders,Ki as rateLimitKey,He as readDriverState,_h as reconcile,ug as reconcileAddressRecords,Kf as reconcileCloudflareCdn,vh as reconcileCloudflareWorkers,Ps as reconcileDeclaredRecords,fS as reconcileJobObservation,dh as reconcileR2Buckets,dn as reconcileSourceWebhook,ns as recordDashboardHostPosture,gS as recordPreDeploySecretScan,pS as recordSkippedSecretScan,_o as recursionBlockedResponse,Be as redactRuntimeConfig,Pd as redactTelemetryText,xi as redactTelemetryValue,Sn as redeployServerlessApp,Wb as regionPairManager,cn as releaseStrategyCapabilities,bf as releaseTrafficPlan,hi as reloadRpxGateway,Cs as remapKey,Qg as removeDns01ChallengeRecord,yn as removeSiteFromCloudConfig,tu as removeSourceWebhook,fc as removeStaleServerAddressRecords,rd as renderComposeTemplate,$i as renderDdosInstallScript,xd as renderNftablesRuleset,ss as renderServerCron,Bd as renderSysctlFile,Vc as renderWafConfig,yi as renderWafInstallScript,Gc as renewRpxCertificates,Oy as replicaManager,PA as requestHash,yb as requiresReplacement,iE as resetRecursionRuntime,sE as resolveApp,g as resolveAppDatabase,Hh as resolveAttachTarget,Ze as resolveAuthEncryptionKey,fe as resolveCloudProvider,Zf as resolveCloudflareCdnPlan,Do as resolveCredentials,fs as resolveDashboardAction,Qc as resolveDashboardAuth,HA as resolveDashboardDomain,GA as resolveDashboardDomains,Ds as resolveDeclaredRecords,yI as resolveDeployBucketName,Q as resolveDeploymentMode,Yn as resolveExecStart,Eo as resolveFailoverStatusCodes,wc as resolveHetznerApiToken,Rr as resolveHostCleanupConfig,Mi as resolveMailService,QI as resolveManagementDashboardSite,Qi as resolveManagementDashboardSites,ec as resolveObjectStorage,re as resolveOriginConnection,$h as resolvePlan,p as resolveProjectStackName,Lr as resolveProxyUpstreams,yl as resolveQueueNames,sA as resolveQueuedDeploymentCommand,nr as resolveQueues,Gy as resolveRecursionConfig,WA as resolveRegion,oe as resolveRuntimeInventory,Xt as resolveServerlessAppStackName,Hd as resolveServerlessArtifactBucketName,Fi as resolveServerlessAssetBucketName,qi as resolveServerlessRuntime,fI as resolveSiteBucketName,Xs as resolveSiteDeployTarget,u as resolveSiteKind,mI as resolveSiteResourceName,pI as resolveSiteStackName,ii as resolveSshSettings,d as resolveStatePath,hI as resolveStorageBucketName,Yp as resolveStorageFailover,Gt as resolveUiSource,ng as resolveZoneApex,uE as resourceManagementManager,df as responseToResult,Np as robustZScore,Vt as roleCapabilities,Kl as rollbackImmutableRelease,In as rollbackServerlessApp,mA as roundCents,zC as route53ResolverManager,My as route53RoutingManager,xp as routeMatches,rp as routesFromFragments,zi as ruleMatches,Fy as runBuildHooks,yd as runEnforcement,Lo as runPhpBuildHooks,rt as runRemoteCommand,Ae as runtimeId,Le as s3OriginBucket,Zp as s3RegionalDomain,yc as sameCorsRules,Cc as sameLifecycleRules,$n as sameNameservers,ms as sanitizeCloudConfig,s as sanitizeControlPlaneValue,gI as sanitizeName,Hl as sanitizeOidcReturnPath,Rd as saveTelemetryPolicy,vf as scanForSecrets,Xc as scopeContains,ht as scopeKey,Ic as scpUpload,Mb as searchCommands,Zs as searchControlPlane,_y as secretsManager,_C as secretsRotationManager,mS as secureContainerRelease,Ry as securityHubManager,$C as securityScanningManager,se as securityScope,Hu as seedFailoverReplicas,an as sendAuthenticationEmail,JC as senderReputationManager,pb as sequence,Yu as serializeDotenv,mi as serverPublicIpv4,$y as serviceMeshManager,Lu as setAttachToInCloudConfig,dr as setMaintenance,ds as setSitePropertyInCloudConfig,_d as setStateDir,rR as setupDns01Challenge,cc as setupSmsInfrastructure,No as sha256,qy as sharedRecursionGuard,sf as sharedRuntimeLoop,Ip as shipsARelease,FS as signCloudFrontCookies,LS as signCloudFrontUrl,R as signRequest,Pl as signRequestAsync,mo as signalDefinition,_ as siteInstallBase,Ii as siteMoveArchivePath,zh as siteMoveCertArchivePath,zc as siteUnitGlob,Mp as spendNotificationText,Co as spendOpenApiPaths,Tr as sshExec,pe as sshExecOrThrow,Jb as stackDependencyManager,Ka as startLocalDashboardServer,RA as startSpendLoop,Jr as stateDir,L as statePath,cE as staticSiteManager,Xy as storageAdvancedManager,CI as storageFailoverReplicasFromTemplate,SA as streamFocusJsonl,Sd as strongestActiveAction,ym as suggestCommand,Ub as suggestFlags,tb as suggestIAMPolicy,ib as suggestQuotaIncrease,iC as suggestRegionPairs,nC as suggestRegions,es as syncSourceRepositories,ad as synchronizeComposeVolumes,Zu as synchronizeConfiguredConfiguration,la as synchronizeConfiguredJobs,xy as syntheticsManager,kd as sysctlHardening,kf as systemdWorkloads,vA as telemetryBucketLabel,_i as telemetryCursor,Dd as telemetryEstimatedMonthlyCost,EA as telemetryPercentile,$p as telemetryPolicyKey,ry as templateCache,np as tenantsOf,ta as testSourceConnection,cd as tieredMicroCents,Rg as toApiLifecycleRule,Lc as toCloudflareZoneSettings,Ao as toFocusJsonl,Ed as toFocusRecords,xh as toInventoryServer,yf as totp,jo as totpUri,ip as unaccountedSites,Rf as unsupportedCapabilities,oA as unsupportedVolumeCapabilities,Du as updateCompatibility,Nu as updateSiteInCloudConfig,ys as uploadStaticFiles,Tp as usageDeltaKey,Kt as utcInstantOfLocal,pC as validateAccountStructure,Cb as validateAgainstSchema,cA as validateAttachment,Jf as validateBackupDestination,Gb as validateCommand,XI as validateConfiguration,ZI as validateCredentials,Sp as validateDeploymentConfig,aA as validateMountPath,St as validateOriginGroups,Ug as validateResourceLimits,op as validateServerName,Mg as validateTemplate,Hg as validateTemplateSize,Ac as verifyAddressRecord,uS as verifyArtifactSignature,MS as verifyMediaAccessToken,Sf as verifyTotp,Ru as verifyUpdateSignature,$s as verifyZoneParity,no as volumeCapabilities,Jg as wafEventTelemetry,bc as waitForCloudInit,Kn as waitForSsh,sr as webhookEndpoint,KI as withCDN,zI as withCache,Tg as withContentHash,jI as withDatabase,cf as withInvocation,VI as withMonitoring,WI as withQueue,qI as withSecurity,mb as withTimeout,Pg as workerBindings,qs as workerContentHash,Pc as workerInSync,Z as wrapCloudInitUserData,dt as writeDriverState,NC as xrayManager,Eu as zeroCapacity,IA as zeroFill,ld as zoneOffsetMs,co as zonedParts};
|