@stacksjs/ts-cloud 0.16.14 → 0.16.16
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/aws/index.js +1 -1
- package/dist/bin/{chunk-r7k2mkn7.js → chunk-0znhykt9.js} +5 -5
- package/dist/bin/{chunk-23nxkj19.js → chunk-1baj8p0r.js} +1 -1
- package/dist/bin/{chunk-9j7qhwe0.js → chunk-2943bszc.js} +1 -1
- package/dist/bin/chunk-2tn43y0d.js +1 -0
- package/dist/bin/{chunk-b7b87gxb.js → chunk-2v91xnqx.js} +2 -2
- package/dist/bin/{chunk-gwpmn3a3.js → chunk-2w591cvg.js} +1 -1
- package/dist/bin/{chunk-5jf6veax.js → chunk-3qfd0vnc.js} +3 -3
- package/dist/bin/{chunk-489c9r4g.js → chunk-3x4p2s2r.js} +3 -3
- package/dist/bin/chunk-4v6f496n.js +1 -0
- package/dist/bin/chunk-64cdtvar.js +1 -0
- package/dist/bin/chunk-66egshmp.js +1 -0
- package/dist/bin/chunk-7raskz63.js +1 -0
- package/dist/bin/{chunk-zm95j24a.js → chunk-80295akq.js} +3 -3
- package/dist/bin/{chunk-fjd8tw77.js → chunk-90c3rkd8.js} +4 -4
- package/dist/bin/chunk-9bxyy4th.js +1 -0
- package/dist/bin/{chunk-pm2vz6zp.js → chunk-b3yp7bak.js} +3 -3
- package/dist/bin/chunk-bbt0vyzj.js +1 -0
- package/dist/bin/{chunk-tb4ek3s5.js → chunk-bhay1f8a.js} +1 -1
- package/dist/bin/chunk-cpcae7e2.js +1 -0
- package/dist/bin/{chunk-cb47f0pb.js → chunk-cs6a98r1.js} +2 -2
- package/dist/bin/{chunk-3eht1tp2.js → chunk-dczw0nxw.js} +5 -5
- package/dist/bin/{chunk-3z65v87m.js → chunk-dp2fsnpe.js} +6 -6
- package/dist/bin/chunk-dsc7ef1w.js +1 -0
- package/dist/bin/{chunk-21am8b1b.js → chunk-edfh9ts2.js} +1 -1
- package/dist/bin/chunk-f2wn46nw.js +1 -0
- package/dist/bin/chunk-fddwwac7.js +1 -0
- package/dist/bin/chunk-ffcyj2jj.js +1 -0
- package/dist/bin/{chunk-2cyhks5n.js → chunk-fjz07v7g.js} +1 -1
- package/dist/bin/chunk-gbejgj71.js +1 -0
- package/dist/bin/{chunk-58phgtc8.js → chunk-grs2cwm7.js} +2 -2
- package/dist/bin/{chunk-p0vyt3fq.js → chunk-gv9deppc.js} +2 -2
- package/dist/bin/{chunk-5ffj7508.js → chunk-j0wfftk1.js} +1 -1
- package/dist/bin/{chunk-yas09vmt.js → chunk-j76935z3.js} +3 -3
- package/dist/bin/{chunk-0y4a84jm.js → chunk-khta83xb.js} +12 -12
- package/dist/bin/chunk-kjbkwzxd.js +1 -0
- package/dist/bin/chunk-knthwdhz.js +1 -0
- package/dist/bin/{chunk-31tmm8kx.js → chunk-m2kr333s.js} +2 -2
- package/dist/bin/chunk-m5wc1ent.js +1 -0
- package/dist/bin/{chunk-s4z1knq4.js → chunk-n02421y9.js} +1 -1
- package/dist/bin/{chunk-9bshng4v.js → chunk-nm000jpj.js} +81 -81
- package/dist/bin/{chunk-kft7wdhy.js → chunk-pd8tk3z5.js} +1 -1
- package/dist/bin/chunk-pjgbnk3q.js +1 -0
- package/dist/bin/chunk-rn0pgnt4.js +1 -0
- package/dist/bin/{chunk-hdr0q89a.js → chunk-tc24txss.js} +5 -5
- package/dist/bin/{chunk-nazx54p5.js → chunk-tfasfg4a.js} +2 -2
- package/dist/bin/{chunk-r0qynqff.js → chunk-tvv6vdx6.js} +5 -5
- package/dist/bin/chunk-v93xyx1p.js +1 -0
- package/dist/bin/chunk-vx9mmpaz.js +1 -0
- package/dist/bin/{chunk-me81g606.js → chunk-vx9qk1g1.js} +1 -1
- package/dist/bin/{chunk-0ed5yh3v.js → chunk-whww424p.js} +47 -47
- package/dist/bin/chunk-xtzy90zh.js +1 -0
- package/dist/bin/{chunk-4nbq68h4.js → chunk-xxf1vhfr.js} +1 -1
- package/dist/bin/{chunk-2a8twtvv.js → chunk-y4c26gaf.js} +1 -1
- package/dist/bin/{chunk-9gcmpcmq.js → chunk-yk4p2k8w.js} +1 -1
- package/dist/bin/chunk-z6mnhd0j.js +1 -0
- package/dist/bin/{chunk-4mpfdw94.js → chunk-zacbzz1w.js} +2 -2
- package/dist/bin/{chunk-3d8y4a6d.js → chunk-zzmk290g.js} +109 -109
- package/dist/bin/cli.js +150 -150
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/chunk-051jwkd2.js +1 -0
- package/dist/{chunk-tgzp1h6j.js → chunk-0bbrbzf9.js} +4 -4
- package/dist/chunk-1gne7rkf.js +1 -0
- package/dist/chunk-38c310s1.js +1 -0
- package/dist/{chunk-80vxhxt5.js → chunk-4twnkjyq.js} +2 -2
- package/dist/{chunk-dns94gs7.js → chunk-4xta1s4z.js} +1 -1
- package/dist/{chunk-dxcwfj3h.js → chunk-6eq5xfcx.js} +1 -1
- package/dist/{chunk-g8tp1zj4.js → chunk-a21phhyj.js} +3 -3
- package/dist/{chunk-55cmjg49.js → chunk-a6aw2jtz.js} +6 -6
- package/dist/{chunk-bpvpq6w6.js → chunk-acpxtkfy.js} +90 -90
- package/dist/chunk-dk3t3hgq.js +1 -0
- package/dist/{chunk-21b8nage.js → chunk-emx1j2yt.js} +1 -1
- package/dist/{chunk-4yb7hf91.js → chunk-fdn4wnd8.js} +7 -7
- package/dist/{chunk-aesvajfc.js → chunk-fz70vxrk.js} +1 -1
- package/dist/{chunk-22ybphxa.js → chunk-g0yyw5k8.js} +1 -1
- package/dist/{chunk-pwpd6jt2.js → chunk-gn42mekr.js} +1 -1
- package/dist/{chunk-0hf0rdze.js → chunk-gstz8w2d.js} +2 -2
- package/dist/{chunk-mmdd5thg.js → chunk-jgv0x24e.js} +1 -1
- package/dist/{chunk-d72ddm5x.js → chunk-jncbm332.js} +130 -130
- package/dist/{chunk-9be2pb0b.js → chunk-pekptc1b.js} +5 -5
- package/dist/chunk-qc2v4h2q.js +1 -0
- package/dist/{chunk-kt6qnc6f.js → chunk-rgw06xbk.js} +4 -4
- package/dist/{chunk-7pk6cctr.js → chunk-rmn71xjb.js} +41 -41
- package/dist/{chunk-2jgx2s5y.js → chunk-sm5rn3db.js} +19 -19
- package/dist/{chunk-8a02v9gs.js → chunk-ss4q8kge.js} +2 -2
- package/dist/{chunk-s40cx3fh.js → chunk-v9t92ak2.js} +2 -2
- package/dist/{chunk-ffjc6gev.js → chunk-wdrqt329.js} +135 -135
- package/dist/{chunk-nw5yqgtn.js → chunk-whwg2nzb.js} +5 -5
- package/dist/{chunk-sw1p9qge.js → chunk-yxn6tpbg.js} +1 -1
- package/dist/{chunk-3bz7xz2d.js → chunk-z87dekhm.js} +1 -1
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/cloudfront-origin.d.ts +15 -26
- package/dist/drivers/shared/deploy-script.d.ts +62 -29
- package/dist/index.js +39 -39
- package/dist/operations/index.js +1 -1
- package/dist/protection/index.js +1 -1
- package/dist/spend/index.js +1 -1
- 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 +6 -6
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +5 -5
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +6 -6
- package/dist/ui/data/services.html +5 -5
- 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 +5 -5
- 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 +5 -5
- 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 +2 -2
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +6 -6
- package/dist/ui/server/deployments.html +5 -5
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +5 -5
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +5 -5
- package/dist/ui/server/security.html +2 -2
- package/dist/ui/server/services.html +2 -2
- 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 +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +1 -1
- package/dist/ui/serverless/cost.html +1 -1
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +2 -2
- 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 +5 -5
- 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-01tmdqe3.js +0 -1
- package/dist/bin/chunk-3bwy7atq.js +0 -1
- package/dist/bin/chunk-3rsvrp09.js +0 -1
- package/dist/bin/chunk-4gf4mk0b.js +0 -1
- package/dist/bin/chunk-5wms0mx3.js +0 -1
- package/dist/bin/chunk-c7sqa85j.js +0 -1
- package/dist/bin/chunk-cejjg0ts.js +0 -1
- package/dist/bin/chunk-e3hn6atg.js +0 -1
- package/dist/bin/chunk-e4gqzp7n.js +0 -1
- package/dist/bin/chunk-fbq61aj0.js +0 -1
- package/dist/bin/chunk-g4dytx12.js +0 -1
- package/dist/bin/chunk-hssaw82j.js +0 -1
- package/dist/bin/chunk-k4x1pq4t.js +0 -1
- package/dist/bin/chunk-kcvvpvte.js +0 -1
- package/dist/bin/chunk-n8a76gys.js +0 -1
- package/dist/bin/chunk-p1k08e45.js +0 -1
- package/dist/bin/chunk-ps8ev3tq.js +0 -1
- package/dist/bin/chunk-q8s9v9hv.js +0 -1
- package/dist/bin/chunk-qcvmyfp7.js +0 -1
- package/dist/bin/chunk-qncvqmzy.js +0 -1
- package/dist/bin/chunk-rt9nbrwd.js +0 -1
- package/dist/bin/chunk-xhwjntw1.js +0 -1
- package/dist/chunk-29xhksd3.js +0 -1
- package/dist/chunk-67wrhk75.js +0 -1
- package/dist/chunk-6n5wgv3d.js +0 -1
- package/dist/chunk-7nq2rwjs.js +0 -1
- package/dist/chunk-xdsaxgny.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import{Bp,x,xp,hf,Ey,ff,vy,Ty,wy,Ry,Dy,Py,Ny,ky,By,xy,_p,Op,od,ad,Js,_,d,cd,Lp,O,dd,p,Af,fi,ld,ud,le,pd,_y,r,t,Oy,Ly,g,$y,My,Fy,Uy,Qy,Ft,gd,Xs,yf,Hy,Gy,Ee,He,ve,L,I,o,f,Ge,m,If,qe,M,ut,qy,Sf,F,md,Te,Ut,Ys,Y,hd,Z,Cf,Zs,U,Q,D,Ai,E,Qt,pt,H,e,eo,Vy,$p,fd,jy,zy,Ky,Wy,Ad,Jy,Xy,Yy,Zy,eI,tI,rI,nI,iI,sI,oI,aI,bf,Ef,vf,Tf,wf,Rf,Df,Ht,Mp,Fp,_r,yi,cI,Up,dI,lI,Or,uI,pI,gI,mI,hI,fI,Pf,Nf,kf,Bf,xf,to,yI,_f,Of,Lf,G,II,Ve,ro,Gt,$f,Qp,Mf,Ff,Uf,Hp,ee,SI,CI,bI,EI,Qf,vI,q,TI,wI,RI,Gp,qp,DI,Vp,jp,PI,NI,kI,BI,xI,Hf,yd,_I,OI,LI,$I,MI,Gf,qf,FI,UI,QI,HI,GI,qI,VI,jI,zI,zp,Id,KI,WI,JI,XI,Kp,Wp,Jp,YI,Xp,ZI,eS,tS,rS,Yp,nS,iS,sS,oS,aS,cS,dS,lS,Vf,jf,zf,Kf,Zp,uS,pS,gS,mS,hS,fS,AS,yS,IS,Wf,Jf,Xf,Yf,SS,CS,eg,bS,tg,rg,ng,ig,ES,vS,TS,wS,we,Ii,RS,DS,PS,NS,kS,BS,xS,_S,Zf,OS,LS,sg,og,$S,MS,eA,FS,US,QS,HS,GS,qS,VS,jS,zS,KS,WS,JS,XS,YS,ZS,eC,tC,rC,nC,iC,sC,ag,oC,cg,aC,dg,cC,lg,dC,ug,lC,Lr,uC,pg,pC,no,gC,gg,mC,mg,hC,hg,fC,fg,AC,Ag,yC,$r,IC,yg,SC,Ig,CC,Sg,bC,Cg,EC,bg,vC,Eg,TC,vg,wC,Tg,RC,wg,DC,Rg,PC,Dg,NC,Pg,kC,Ng,BC,kg,xC,Bg,_C,xg,OC,_g,LC,Og,$C,Lg,MC,$g,FC,Mg,UC,Fg,QC,Ug,HC,Qg,GC,Hg,qC,tA,rA,nA,iA,Gg,VC,qg,jC,Vg,zC,jg,KC,Si,sA,oA,io,Sd,Mr,aA,so,qt,Cd,bd,cA,dA,zg,lA,Ed,Kg,WC,JC,oo,ao,co,vd,Ci,Td,wd,lo,Rd,Dd,Wg,uA,pA,gA,XC,mA,hA,YC,fA,Jg,AA,yA,IA,ZC,SA,bi,Pd,CA,eb,bA,uo,po,Nd,Xg,tb,Yg,rb,Zg,nb,em,ib,tm,sb}from"./chunk-d72ddm5x.js";import{yo,rm,$d,vA,wi,Md,Io,nm,im,Fr,So,Fd,je,Ud,Qd,Hd,Ri,Ur,sm,ze,Gd,Co,bo,Eo,qd,Vd,jd,Di,vo,zd,Qr,Pi,To,gt,om,Kd,Wd,am,Jd,wo,Vt,Xd,Yd,Zd,el,Ke,cm,tl,jt,Ro,Do,Po,Ni,ki,Hr,rl,Bi,No,ko,Gr,nl,qr,dm,lm,mt,Vr,Bo,um,il,sl,xo,ol,al,cl,TA,te,dl,wA,RA,xi,_i,DA,ue,pm,ht,Re,De,ft,ll,ul,pl,gl,gm,mm,_o,hm,fm,Oo,ml,hl,Am,re,ym,fl,pe,Lo,We,At,yt,jr,Oi,Al,PA,$o,Im,Sm,Cm,bm,Mo,Fo,yl,zr,Uo,Il,Li,Sl,Qo,Ho,Go,qo,Vo,jo,zo,Ko,Cl,zt,Wo,bl,Kr,El,Jo,Xo,vl,Kt,Yo,Zo,Em,NA,$i,kA,BA,xA,ea,ta,Tl,vm,ra,Wr,wl,Mi,Rl,Dl,Pl,na,Tm,ia,Nl,wm,sa,Rm,Jr,Xr,kl,Fi,$l,Ql,Qi,Wt,aa,Yr,Zr,Jt,Je,Om,da,Lm,$m,ql,la,Gi,Vl,ua,St,Ne,jl,pa,ga,zl,ma,ha,fa,Aa,Kl,Wl,tn,ya,Ia,Sa,Ca,Jl,qi,rn,Vi,ba}from"./chunk-ffjc6gev.js";import{B,Sr,Cc,Ts,u,op,ap}from"./chunk-0hf0rdze.js";import{ot,Sc,Zn,ei,ti,sp}from"./chunk-kt6qnc6f.js";import{mh,hh,fh,Uu,Qu,Hu,Ah,Gu,qu,yh,Ih,Vu,Sh,Ch,yc,ju,bh,Eh,zu,vh,Th,wh,Rh,Dh,Ph,Nh,Yn,Ic,Ku,Wu,Ju,Xu,Yu,Zu,ep,tp,rp,np,ip,kh,Bh,xh,_h,Oh,Lh,$h}from"./chunk-2jgx2s5y.js";import{Fe,bc,de,Bt,Ec,w,xt,at,vc,ws,Uh,cp,Tc,s,ri,Rs,Cr,wc,Rc,br,Qh,Dc,Iy,Sy,Ds,Cy,by,Pc,Nc,ni,Ps,X,c,Ns,Ue,Er,Hh,Gh,kc,_t,qh,ks,Vh,jh,Bs,Bc,vr,xs,zh,xc,dp,Ot,Tr,Kh,_s,Wh,R,Jh,_c,lp,Os,Xh,Yh,Zh,Oc,ii,Ls,Lc,Lt,ct,ef,wr,tf,$c,up,pp,$s,Mc,Fc,dt,gp,si,Uc,Ms,Rr,mp,oi,Qc,Hc,ai,hp,Gc,qc,Vc,jc,Fs,fp,Ap,rf,yp,zc,ci,Ip,Sp,Us,Dr,Qs,Hs,Gs,Kc,Cp,Wc,qs,nf,$t,sf,Jc,Pr,Xc,of,Yc,bp,di,Nr,Vs,li,Qe,af,Ep,vp,Mt,Zc,ed,td,ui,pi,gi,cf,df,lt,js,lf,kr,Tp,zs,uf,wp,Rp,Dp,pf,Pp,Np,gf,i,mf,mi,Ks,Ws}from"./chunk-7pk6cctr.js";import{n}from"./chunk-8a02v9gs.js";import{a}from"./chunk-3bz7xz2d.js";import{ge,Yi,Zi,Zl,Ra,Da,es,Pa,Xe,V,Ye,ne,C,me,an,Na,ke,ka,cn,dn,ln,Ct,bt,Et,un,Yt,Ba,Zt,er,Ze,pn,_a,vt,tr,gn,La,nu,iu,$a,rr}from"./chunk-55cmjg49.js";import{tt,se,xe,su,hn,Ma,Fa,rs,fe,Tt,fn,ns,is,nr,ir,An,sr,ss,os,as,cs,z,ds,ls,us,ps,oe,gs,ms,hs,T,Ua,yn,Qa,ae,or}from"./chunk-s40cx3fh.js";import{he,et,mn}from"./chunk-g8tp1zj4.js";import{j}from"./chunk-dxcwfj3h.js";import{ou,Ha,Ae,Ga,In,au,qa,cu,du,Wm,Cn,As,bn,En,vn,K,_e,N,ur,wn,pr,ce,za,Rn,Ka,gr,Xa,Oe,W,Le,$e,nt,Se,mr,Ce,Nn,kn,Bn,xn,_n,On,Ln,hr,k,Ss,Nu,ic,Mn,Un,Qn,Hn,Gn,qn,Vn,zn,gc,Cs,mc,Nt,Kn,bs,Es,hc,Wn,fc}from"./chunk-bpvpq6w6.js";import{kd,go,Ei,vi,mo,Bd,xd,Ti,ho,fo,Od,Ld,Ao}from"./chunk-mmdd5thg.js";import{Ea,nn,sn,ji,zi,Ki,Wi,va,Ta}from"./chunk-nw5yqgtn.js";import{wa}from"./chunk-tgzp1h6j.js";import{A}from"./chunk-sw1p9qge.js";import{Be}from"./chunk-dns94gs7.js";import{y}from"./chunk-21b8nage.js";import{J,Jn,vs,Ac,Xn,Fu}from"./chunk-9be2pb0b.js";import{Ar,be}from"./chunk-aesvajfc.js";import{h}from"./chunk-22ybphxa.js";import{uh,Me}from"./chunk-80vxhxt5.js";import{rd,Br,nd,id,sd,hi,kp,xr}from"./chunk-4yb7hf91.js";import{createHmac as fs,createSign as Ol,timingSafeEqual as xl}from"node:crypto";function Ui(l){let S=l instanceof Date?l.getTime():l;if(!Number.isFinite(S))throw TypeError("Media access timestamp must be finite");return Math.floor(S/1000)}function ys(l){return Buffer.from(l).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function Ll(l){return Buffer.from(l).toString("base64url")}function Is(l,S=!1){if(!l||/[\r\n]/.test(l))throw TypeError("Media resource is invalid");let b=S?l.replaceAll("*","wildcard"):l,P=new URL(b);if(!["http:","https:"].includes(P.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!S&&l.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function ec(l,S){let b=Ol("RSA-SHA1");return b.update(l),b.end(),ys(b.sign(S))}function tc(l){Is(l.resource,!0);let b={DateLessThan:{"AWS:EpochTime":Ui(l.expiresAt)}};if(l.activeAt!==void 0)b.DateGreaterThan={"AWS:EpochTime":Ui(l.activeAt)};if(l.ipAddress)b.IpAddress={"AWS:SourceIp":l.ipAddress};return JSON.stringify({Statement:[{Resource:l.resource,Condition:b}]})}function $u(l,S,b){Is(l);let P=Ui(S),v=l.includes("?")?"&":"?",it=tc({resource:l,expiresAt:S}),Pe=ec(it,b.privateKey);return`${l}${v}Expires=${P}&Signature=${encodeURIComponent(Pe)}&Key-Pair-Id=${encodeURIComponent(b.keyPairId)}`}function Du(l,S){let b=tc(l);return{"CloudFront-Key-Pair-Id":S.keyPairId,"CloudFront-Policy":ys(Buffer.from(b)),"CloudFront-Signature":ec(b,S.privateKey)}}function Iu(l){if(!l.resource||/[\r\n]/.test(l.resource))throw TypeError("Media resource is invalid");let S=Ll(Buffer.from(JSON.stringify({resource:l.resource,expiresAt:Ui(l.expiresAt),...l.keyId?{keyId:l.keyId}:{},...l.audience?{audience:l.audience}:{}}))),b=fs("sha256",l.secret).update(S).digest("base64url");return`${S}.${b}`}function wu(l,S){let[b,P,v]=l.split(".");if(!b||!P||v)return null;let it=fs("sha256",S.secret).update(b).digest(),Pe;try{Pe=Buffer.from(P,"base64url")}catch{return null}if(it.length!==Pe.length||!xl(it,Pe))return null;try{let Ie=JSON.parse(Buffer.from(b,"base64url").toString("utf8")),rt=Ui(S.now??Date.now());if(!Ie.resource||!Number.isSafeInteger(Ie.expiresAt)||Ie.expiresAt<=rt)return null;if(S.resource&&Ie.resource!==S.resource)return null;if(S.audience&&Ie.audience!==S.audience)return null;return Ie}catch{return null}}function Eu(l,S=!1){let b=new URL(l,"https://media.invalid").pathname.toLowerCase(),P=/\.(?:m3u8|mpd|vtt|json)$/.test(b),v=/\.(?:key|license)$/.test(b)||b.includes("/keys/")||b.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":S&&(P||v)?"private, no-store":P?"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 Ou(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 S=l.prefix?`/${l.prefix.replace(/^\/+|\/+$/g,"")}`:"",b=l.protected??!1,P="public, max-age=31536000, immutable",v=b?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${l.bucket}.s3.${l.region}.amazonaws.com`,originPath:S,domain:l.domain,trustedKeyGroupIds:[...new Set(l.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:v,compress:!0,signed:b},{pathPattern:"*.mpd",cacheControl:v,compress:!0,signed:b},{pathPattern:"*.vtt",cacheControl:v,compress:!0,signed:b},{pathPattern:"*",cacheControl:P,compress:!1,signed:b}],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 Fl{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;constructor(l){this.config=l.config,this.environment=l.environment,this.builder=new pd(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let S=this.config.environments[this.environment]?.infrastructure;if(!S)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...S,compute:{...this.config.infrastructure?.compute,...S.compute},storage:{...this.config.infrastructure?.storage,...S.storage},functions:{...this.config.infrastructure?.functions,...S.functions},servers:{...this.config.infrastructure?.servers,...S.servers},databases:{...this.config.infrastructure?.databases,...S.databases},cdn:{...this.config.infrastructure?.cdn,...S.cdn},sftp:S.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...S.queues},redirects:{...this.config.infrastructure?.redirects,...S.redirects},realtime:{...this.config.infrastructure?.realtime,...S.realtime},cache:{...this.config.infrastructure?.cache,...S.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...S.fileSystem},email:{...this.config.infrastructure?.email,...S.email},search:{...this.config.infrastructure?.search,...S.search},ai:{...this.config.infrastructure?.ai,...S.ai}}}}shouldDeploy(l){if(l.environments&&!l.environments.includes(this.environment))return!1;if(l.requiresFeatures){let S=this.config.features||{};if(!l.requiresFeatures.every((P)=>S[P]===!0))return!1}if(l.regions){let S=this.config.environments[this.environment]?.region||this.config.project.region;if(!l.regions.includes(S))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,S=Number(l||3008);return Number.isFinite(S)&&S>0?S: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,S){return l==="public"||S.routeCompute===!0}storageBucketName(l,S,b){return this.mergedConfig.infrastructure?.storage?.[b]?.bucket??`${l}-${S}-${b}`}fileSystemLogicalId(l,S,b){return t(r({slug:`${l}-${b}`,environment:S,resourceType:"efs"}))}resolveSftpStorage(l,S,b){let P=l.storage;if(P?.type==="efs"&&P.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[P.fileSystem])throw Error(`sftp: storage.fileSystem "${P.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(S,b,P.fileSystem)},posixProfile:P.posixProfile}}if(P?.type==="s3"&&P.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[P.storageBucket])throw Error(`sftp: storage.storageBucket "${P.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(S,b,P.storageBucket)}}return}resolveComputeCachePathPatterns(l){if(l&&l.length>0)return l;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(l,S){return{PathPattern:l,TargetOriginId:S,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,S,b,P,v,it){let Pe=this.serverEipLogicalIds.get("app"),Ie=this.serverEipLogicalIds.get("appInstance");if(!Pe)return;let rt=`EC2-${P}-${v}-api`,Rt=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",st=Rt==="us-east-1"?".compute-1.amazonaws.com":`.${Rt}.compute.amazonaws.com`,cr={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:Pe}]}]},st]]},lr=this.resolveApiOriginPort();if(l.push({Id:rt,DomainName:cr,CustomOriginConfig:{HTTPPort:lr,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),b.push(Pe),Ie)b.push(Ie);for(let fr of it)S.push(this.createComputeCacheBehavior(fr,rt))}buildCaddyfile(l){let S=l.filter(([,v])=>typeof v.domain==="string"&&v.domain&&typeof v.port==="number");if(S.length===0)return;let b=new Map;for(let[,v]of S){let it=b.get(v.domain)??[];it.push({port:v.port,path:v.path}),b.set(v.domain,it)}let P=[];for(let[v,it]of b){let Ie=[...it].sort((rt,Rt)=>{let st=!rt.path||rt.path==="/",cr=!Rt.path||Rt.path==="/";if(st&&!cr)return 1;if(!st&&cr)return-1;return(Rt.path?.length??0)-(rt.path?.length??0)}).map((rt)=>{let Rt=!rt.path||rt.path==="/",st=`reverse_proxy localhost:${rt.port}`;return Rt?` handle {
|
|
1
|
+
import{Fp,_,Up,Ef,ky,bf,By,_y,xy,Oy,Ly,$y,My,Fy,Uy,Qy,Qp,Hp,cd,dd,Ys,x,d,ld,Gp,O,ud,p,vf,Ai,pd,gd,le,md,Hy,r,t,Gy,qy,g,Vy,jy,zy,Ky,Wy,Ft,hd,Zs,Tf,Jy,Xy,ve,He,fd,qp,Vp,Yy,wf,jp,yi,xr,Ad,ue,L,I,o,f,Ge,m,Rf,qe,M,ut,Zy,Df,F,yd,Te,Ut,eo,Y,Id,Z,Pf,to,U,Q,D,Ii,b,Qt,pt,H,e,ro,eI,zp,Sd,tI,rI,nI,iI,Cd,sI,oI,aI,cI,dI,lI,uI,pI,gI,mI,hI,fI,Nf,kf,Bf,_f,xf,Of,Lf,Ht,Kp,Wp,Or,Si,yI,Jp,II,SI,Lr,CI,EI,bI,vI,TI,wI,$f,Mf,Ff,Uf,Qf,no,RI,Hf,Gf,qf,G,DI,Ve,io,Gt,Vf,Xp,jf,zf,Kf,Yp,ee,PI,NI,kI,BI,Wf,_I,q,xI,OI,LI,Zp,eg,$I,tg,rg,MI,FI,UI,QI,HI,Jf,Ed,GI,qI,VI,jI,zI,Xf,Yf,KI,WI,JI,XI,YI,ZI,eS,tS,rS,ng,bd,nS,iS,sS,oS,ig,sg,og,aS,ag,cS,dS,lS,uS,cg,pS,gS,mS,hS,fS,AS,yS,IS,Zf,eA,tA,rA,dg,SS,CS,ES,bS,vS,TS,wS,RS,DS,nA,iA,sA,oA,PS,NS,lg,kS,ug,pg,gg,mg,BS,_S,xS,OS,we,Ci,LS,$S,MS,FS,US,QS,HS,GS,aA,qS,VS,hg,fg,jS,zS,cA,KS,WS,JS,XS,YS,ZS,eC,tC,rC,nC,iC,sC,oC,aC,cC,dC,lC,uC,pC,gC,mC,Ag,hC,yg,fC,Ig,AC,Sg,yC,Cg,IC,$r,SC,Eg,CC,so,EC,bg,bC,vg,vC,Tg,TC,wg,wC,Rg,RC,Mr,DC,Dg,PC,Pg,NC,Ng,kC,kg,BC,Bg,_C,_g,xC,xg,OC,Og,LC,Lg,$C,$g,MC,Mg,FC,Fg,UC,Ug,QC,Qg,HC,Hg,GC,Gg,qC,qg,VC,Vg,jC,jg,zC,zg,KC,Kg,WC,Wg,JC,Jg,XC,Xg,YC,Yg,ZC,dA,lA,uA,pA,Zg,eE,em,tE,tm,rE,rm,nE,Ei,gA,mA,oo,vd,Fr,hA,ao,qt,Td,wd,fA,AA,nm,yA,Rd,im,iE,sE,co,lo,uo,Dd,bi,Pd,Nd,po,kd,Bd,sm,IA,SA,CA,oE,EA,bA,aE,vA,om,TA,wA,RA,cE,DA,vi,_d,PA,dE,NA,go,mo,xd,am,lE,cm,uE,dm,pE,lm,gE,um,mE}from"./chunk-jncbm332.js";import{So,pm,Qd,BA,Di,Hd,Co,gm,mm,Ur,Eo,Gd,je,qd,Vd,jd,Pi,Qr,hm,ze,zd,bo,vo,To,Kd,Wd,Jd,Ni,wo,Xd,Hr,ki,Ro,gt,fm,Yd,Zd,Am,el,Do,Vt,tl,rl,nl,il,Ke,ym,sl,jt,Po,No,ko,Bi,_i,Gr,ol,xi,Bo,_o,qr,al,Vr,Im,Sm,mt,jr,xo,Cm,cl,dl,Oo,ll,ul,pl,_A,te,gl,xA,OA,Oi,Li,LA,pe,Em,ht,Re,De,ft,ml,hl,fl,Al,bm,vm,Lo,Tm,wm,$o,yl,Il,Rm,re,Dm,Sl,ge,Mo,We,At,yt,zr,$i,Cl,$A,Fo,Pm,Nm,km,Bm,Uo,Qo,El,Kr,Ho,bl,Mi,vl,Go,qo,Vo,jo,zo,Ko,Wo,Jo,Tl,zt,Xo,wl,Wr,Rl,Yo,Zo,Dl,Kt,ea,ta,_m,MA,Fi,FA,UA,QA,ra,na,Pl,xm,ia,Jr,Nl,Ui,kl,Bl,_l,sa,Om,oa,xl,Lm,aa,$m,Xr,Yr,Ol,Qi,Ql,Vl,Gi,Wt,da,Zr,en,Jt,Je,Vm,ua,jm,zm,Kl,pa,Vi,Wl,ga,St,Ne,Jl,ma,ha,Xl,fa,Aa,ya,Ia,Yl,Zl,rn,Sa,Ca,Ea,ba,eu,ji,nn,zi,va}from"./chunk-wdrqt329.js";import{B,Sr,bc,Rs,u,gp,mp}from"./chunk-gstz8w2d.js";import{ot,Ec,ei,ti,ri,pp}from"./chunk-rgw06xbk.js";import{Ch,Eh,bh,zu,Ku,Wu,vh,Ju,Xu,Th,wh,Yu,Rh,Dh,Sc,Zu,Ph,Nh,ep,kh,Bh,_h,xh,Oh,Lh,$h,Zn,Cc,tp,rp,np,ip,sp,op,ap,cp,dp,lp,up,Mh,Fh,Uh,Qh,Hh,Gh,qh}from"./chunk-sm5rn3db.js";import{Fe,vc,de,Bt,Tc,w,_t,at,wc,Ds,zh,hp,Rc,s,ni,Ps,Cr,Dc,Pc,Er,Kh,Nc,Ry,Dy,Ns,Py,Ny,kc,Bc,ii,ks,X,c,Bs,Ue,br,Wh,Jh,_c,xt,Xh,_s,Yh,Zh,xs,xc,vr,Os,ef,Oc,fp,Ot,Tr,tf,Ls,rf,R,nf,Lc,Ap,$s,sf,of,af,$c,si,Ms,Mc,Lt,ct,cf,wr,df,Fc,yp,Ip,Fs,Uc,Qc,dt,Sp,oi,Hc,Us,Rr,Cp,ai,Gc,qc,ci,Ep,Vc,jc,zc,Kc,Qs,bp,vp,lf,Tp,Wc,di,wp,Rp,Hs,Dr,Gs,qs,Vs,Jc,Dp,Xc,js,uf,$t,pf,Yc,Pr,Zc,gf,ed,Pp,li,Nr,zs,ui,Qe,mf,Np,kp,Mt,td,rd,nd,pi,gi,mi,hf,ff,lt,Ks,Af,kr,Bp,Ws,yf,_p,xp,Op,If,Lp,$p,Sf,i,Cf,hi,Js,Xs}from"./chunk-rmn71xjb.js";import{n}from"./chunk-ss4q8kge.js";import{a}from"./chunk-z87dekhm.js";import{me,es,ts,nu,Pa,Na,rs,ka,Xe,V,Ye,ne,C,he,cn,Ba,ke,_a,dn,ln,un,Ct,Et,bt,pn,Yt,xa,Zt,er,Ze,gn,La,vt,tr,mn,Ma,au,cu,Fa,rr}from"./chunk-a6aw2jtz.js";import{tt,se,_e,du,fn,Ua,Qa,is,Ae,Tt,An,ss,os,nr,ir,yn,sr,as,cs,ds,ls,z,us,ps,gs,ms,oe,hs,fs,As,T,Ha,In,Ga,ae,or}from"./chunk-v9t92ak2.js";import{fe,et,hn}from"./chunk-a21phhyj.js";import{j}from"./chunk-6eq5xfcx.js";import{lu,qa,ye,Va,Sn,uu,ja,pu,gu,sh,En,Is,bn,vn,Tn,K,xe,N,ur,Rn,pr,ce,Wa,Dn,Ja,gr,Za,Oe,W,Le,$e,nt,Ce,mr,Ee,kn,Bn,_n,xn,On,Ln,$n,hr,k,Es,xu,oc,Un,Qn,Hn,Gn,qn,Vn,jn,Kn,hc,bs,fc,Nt,Wn,vs,Ts,Ac,Jn,yc}from"./chunk-acpxtkfy.js";import{Od,ho,Ti,wi,fo,Ld,$d,Ri,Ao,yo,Fd,Ud,Io}from"./chunk-jgv0x24e.js";import{Ta,sn,on,Ki,Wi,Ji,Xi,wa,Ra}from"./chunk-whwg2nzb.js";import{Da}from"./chunk-0bbrbzf9.js";import{A}from"./chunk-yxn6tpbg.js";import{Be}from"./chunk-4xta1s4z.js";import{y}from"./chunk-emx1j2yt.js";import{J,Xn,ws,Ic,Yn,ju}from"./chunk-pekptc1b.js";import{Ar,be}from"./chunk-fz70vxrk.js";import{h}from"./chunk-g0yyw5k8.js";import{yh,Me}from"./chunk-4twnkjyq.js";import{id,Br,sd,od,ad,fi,Mp,_r}from"./chunk-fdn4wnd8.js";import{createHmac as Ss,createSign as $l,timingSafeEqual as Ll}from"node:crypto";function qi(l){let S=l instanceof Date?l.getTime():l;if(!Number.isFinite(S))throw TypeError("Media access timestamp must be finite");return Math.floor(S/1000)}function ec(l){return Buffer.from(l).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function Fl(l){return Buffer.from(l).toString("base64url")}function tc(l,S=!1){if(!l||/[\r\n]/.test(l))throw TypeError("Media resource is invalid");let P=S?l.replaceAll("*","wildcard"):l,E=new URL(P);if(!["http:","https:"].includes(E.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!S&&l.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function rc(l,S){let P=$l("RSA-SHA1");return P.update(l),P.end(),ec(P.sign(S))}function nc(l){tc(l.resource,!0);let P={DateLessThan:{"AWS:EpochTime":qi(l.expiresAt)}};if(l.activeAt!==void 0)P.DateGreaterThan={"AWS:EpochTime":qi(l.activeAt)};if(l.ipAddress)P.IpAddress={"AWS:SourceIp":l.ipAddress};return JSON.stringify({Statement:[{Resource:l.resource,Condition:P}]})}function Eu(l,S,P){tc(l);let E=qi(S),v=l.includes("?")?"&":"?",it=nc({resource:l,expiresAt:S}),Pe=rc(it,P.privateKey);return`${l}${v}Expires=${E}&Signature=${encodeURIComponent(Pe)}&Key-Pair-Id=${encodeURIComponent(P.keyPairId)}`}function Ou(l,S){let P=nc(l);return{"CloudFront-Key-Pair-Id":S.keyPairId,"CloudFront-Policy":ec(Buffer.from(P)),"CloudFront-Signature":rc(P,S.privateKey)}}function vu(l){if(!l.resource||/[\r\n]/.test(l.resource))throw TypeError("Media resource is invalid");let S=Fl(Buffer.from(JSON.stringify({resource:l.resource,expiresAt:qi(l.expiresAt),...l.keyId?{keyId:l.keyId}:{},...l.audience?{audience:l.audience}:{}}))),P=Ss("sha256",l.secret).update(S).digest("base64url");return`${S}.${P}`}function Nu(l,S){let[P,E,v]=l.split(".");if(!P||!E||v)return null;let it=Ss("sha256",S.secret).update(P).digest(),Pe;try{Pe=Buffer.from(E,"base64url")}catch{return null}if(it.length!==Pe.length||!Ll(it,Pe))return null;try{let Ie=JSON.parse(Buffer.from(P,"base64url").toString("utf8")),rt=qi(S.now??Date.now());if(!Ie.resource||!Number.isSafeInteger(Ie.expiresAt)||Ie.expiresAt<=rt)return null;if(S.resource&&Ie.resource!==S.resource)return null;if(S.audience&&Ie.audience!==S.audience)return null;return Ie}catch{return null}}function ku(l,S=!1){let P=new URL(l,"https://media.invalid").pathname.toLowerCase(),E=/\.(?:m3u8|mpd|vtt|json)$/.test(P),v=/\.(?:key|license)$/.test(P)||P.includes("/keys/")||P.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":S&&(E||v)?"private, no-store":E?"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 Lu(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 S=l.prefix?`/${l.prefix.replace(/^\/+|\/+$/g,"")}`:"",P=l.protected??!1,E="public, max-age=31536000, immutable",v=P?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${l.bucket}.s3.${l.region}.amazonaws.com`,originPath:S,domain:l.domain,trustedKeyGroupIds:[...new Set(l.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:v,compress:!0,signed:P},{pathPattern:"*.mpd",cacheControl:v,compress:!0,signed:P},{pathPattern:"*.vtt",cacheControl:v,compress:!0,signed:P},{pathPattern:"*",cacheControl:E,compress:!1,signed:P}],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 Ml{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;constructor(l){this.config=l.config,this.environment=l.environment,this.builder=new md(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let S=this.config.environments[this.environment]?.infrastructure;if(!S)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...S,compute:{...this.config.infrastructure?.compute,...S.compute},storage:{...this.config.infrastructure?.storage,...S.storage},functions:{...this.config.infrastructure?.functions,...S.functions},servers:{...this.config.infrastructure?.servers,...S.servers},databases:{...this.config.infrastructure?.databases,...S.databases},cdn:{...this.config.infrastructure?.cdn,...S.cdn},sftp:S.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...S.queues},redirects:{...this.config.infrastructure?.redirects,...S.redirects},realtime:{...this.config.infrastructure?.realtime,...S.realtime},cache:{...this.config.infrastructure?.cache,...S.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...S.fileSystem},email:{...this.config.infrastructure?.email,...S.email},search:{...this.config.infrastructure?.search,...S.search},ai:{...this.config.infrastructure?.ai,...S.ai}}}}shouldDeploy(l){if(l.environments&&!l.environments.includes(this.environment))return!1;if(l.requiresFeatures){let S=this.config.features||{};if(!l.requiresFeatures.every((E)=>S[E]===!0))return!1}if(l.regions){let S=this.config.environments[this.environment]?.region||this.config.project.region;if(!l.regions.includes(S))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,S=Number(l||3008);return Number.isFinite(S)&&S>0?S: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,S){return l==="public"||S.routeCompute===!0}storageBucketName(l,S,P){return this.mergedConfig.infrastructure?.storage?.[P]?.bucket??`${l}-${S}-${P}`}fileSystemLogicalId(l,S,P){return t(r({slug:`${l}-${P}`,environment:S,resourceType:"efs"}))}resolveSftpStorage(l,S,P){let E=l.storage;if(E?.type==="efs"&&E.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[E.fileSystem])throw Error(`sftp: storage.fileSystem "${E.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(S,P,E.fileSystem)},posixProfile:E.posixProfile}}if(E?.type==="s3"&&E.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[E.storageBucket])throw Error(`sftp: storage.storageBucket "${E.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(S,P,E.storageBucket)}}return}resolveComputeCachePathPatterns(l){if(l&&l.length>0)return l;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(l,S){return{PathPattern:l,TargetOriginId:S,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,S,P,E,v,it){let Pe=this.serverEipLogicalIds.get("app"),Ie=this.serverEipLogicalIds.get("appInstance");if(!Pe)return;let rt=`EC2-${E}-${v}-api`,Pt=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",st=Pt==="us-east-1"?".compute-1.amazonaws.com":`.${Pt}.compute.amazonaws.com`,cr={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:Pe}]}]},st]]},lr=this.resolveApiOriginPort();if(l.push({Id:rt,DomainName:cr,CustomOriginConfig:{HTTPPort:lr,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),P.push(Pe),Ie)P.push(Ie);for(let fr of it)S.push(this.createComputeCacheBehavior(fr,rt))}buildCaddyfile(l){let S=l.filter(([,v])=>typeof v.domain==="string"&&v.domain&&typeof v.port==="number");if(S.length===0)return;let P=new Map;for(let[,v]of S){let it=P.get(v.domain)??[];it.push({port:v.port,path:v.path}),P.set(v.domain,it)}let E=[];for(let[v,it]of P){let Ie=[...it].sort((rt,Pt)=>{let st=!rt.path||rt.path==="/",cr=!Pt.path||Pt.path==="/";if(st&&!cr)return 1;if(!st&&cr)return-1;return(Pt.path?.length??0)-(rt.path?.length??0)}).map((rt)=>{let Pt=!rt.path||rt.path==="/",st=`reverse_proxy localhost:${rt.port}`;return Pt?` handle {
|
|
2
2
|
${st}
|
|
3
3
|
}`:` handle ${rt.path} {
|
|
4
4
|
${st}
|
|
5
|
-
}`});
|
|
5
|
+
}`});E.push(`${v} {
|
|
6
6
|
${Ie.join(`
|
|
7
7
|
`)}
|
|
8
|
-
}`)}return
|
|
8
|
+
}`)}return E.join(`
|
|
9
9
|
|
|
10
|
-
`)}normalizeMountPath(l){let S=l?.mountPath||l?.path;if(!S||S==="/")return;let b=`/${S}`.replace(/\/+/g,"/").replace(/\/$/,"");return b==="/"?void 0:b}storageBucketLogicalId(l,S,b){return`${l}-${S}-s3-${b}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((P)=>P.charAt(0).toUpperCase()+P.slice(1)).join("")}pathMountRewriteFunctionCode(l,S="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(l)}; var rewriteStyle = ${JSON.stringify(S)}; 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,S=this.environment,b=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),P=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),v=!!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,S),this.generateContainerInfrastructure(l,S);if(b)this.generateServerless(l,S);if(P)this.generateServer(l,S);if(v)this.generateComputeApp(l,S);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(l,S);if(this.generateSharedInfrastructure(l,S),this.config.tags)this.applyGlobalTags(this.config.tags);return this}applyGlobalTags(l){}generateNetworkInfrastructure(l,S){if(this.builder.hasResource("VPC"))return;let P=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:v,logicalId:it}=f.createVpc({slug:l,environment:S,cidr:P,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",v);let Pe=`${l}${S}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pe,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${l}-${S}-igw`},{Key:"Environment",Value:S}]}});let Ie=`${l}${S}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ie,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:Pe}}});let rt=`${l}${S}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(rt,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${l}-${S}-public-rt`},{Key:"Environment",Value:S}]}}),this.builder.addResource(`${l}${S}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:rt},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:Pe}},DependsOn:Ie});let Rt=this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1",st=["a","b"];for(let cr=0;cr<2;cr++){let lr=`PublicSubnet${cr+1}`;this.builder.addResource(lr,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${cr}.0/24`,AvailabilityZone:`${Rt}${st[cr]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${l}-${S}-public-${st[cr]}`},{Key:"Environment",Value:S}]}}),this.builder.addResource(`${lr}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:lr},RouteTableId:{Ref:rt}}})}}generateContainerInfrastructure(l,S){let b=this.mergedConfig.infrastructure?.containers;if(!b)return;let P=this.mergedConfig.infrastructure?.loadBalancer,v=this.mergedConfig.infrastructure?.ssl,it=this.mergedConfig.infrastructure?.dns,Pe;if(v?.enabled&&v.domains?.length)if(v.certificateArn);else{let st=v.domains[0],cr=v.domains.slice(1).map((It)=>{if(It.includes(".")&&It.endsWith(st))return It.replace(`.${st}`,"");return It}),{certificate:lr,logicalId:fr}=I.createCertificate({domain:st,subdomains:cr,slug:l,environment:S,validationMethod:"DNS",hostedZoneId:it?.hostedZoneId});Pe=fr,this.builder.addResource(fr,lr)}let Ie="ECSCluster";this.builder.addResource(Ie,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${l}-${S}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${l}-${S}`},{Key:"Environment",Value:S}]}});let rt=`${l}${S}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(rt,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${l}-${S}`,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}-${S}-alb-sg`},{Key:"Environment",Value:S}]}});let Rt=`${l}${S}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[st,cr]of Object.entries(b)){let lr=cr.port||3000;this.builder.addResource(Rt,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${l}-${S}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:lr,ToPort:lr,SourceSecurityGroupId:{Ref:rt},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${l}-${S}-ecs-sg`},{Key:"Environment",Value:S}]}});let fr=`${l}${S}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(fr,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${S}-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 It=`${l}${S}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(It,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${S}-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 Pt=`${l}${S}${st}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),ye=`/ecs/${l}-${S}-${st}`;this.builder.addResource(Pt,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:ye,RetentionInDays:30}});let kt=`${l}${S}${st}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),ie=String(cr.cpu||512),Dt=String(cr.memory||1024);this.builder.addResource(kt,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${S}-${st}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:ie,Memory:Dt,ExecutionRoleArn:{"Fn::GetAtt":[fr,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[It,"Arn"]},ContainerDefinitions:[{Name:st,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${l}:latest`},Essential:!0,PortMappings:[{ContainerPort:lr,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":ye,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":st}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${lr}${cr.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${l}-${S}-${st}`},{Key:"Environment",Value:S}]},DependsOn:[fr,It,Pt]});let wt=`${l}${S}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(P?.enabled!==!1){this.builder.addResource(wt,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${l}-${S}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:rt}],Tags:[{Key:"Name",Value:`${l}-${S}-alb`},{Key:"Environment",Value:S}]}});let Xt=`${l}${S}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),ar=P?.healthCheck?.path||cr.healthCheck||"/health";this.builder.addResource(Xt,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${l}-${S}-tg`,Port:lr,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:ar,HealthCheckIntervalSeconds:P?.healthCheck?.interval||30,HealthyThresholdCount:P?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:P?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${l}-${S}-tg`},{Key:"Environment",Value:S}]}});let dr=`${l}${S}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(v?.enabled&&v?.redirectHttp)this.builder.addResource(dr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(dr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Xt}}]}});if(v?.enabled){let Sn=v.certificateArn||(Pe?{Ref:Pe}:void 0);if(Sn){let Pn=`${l}${S}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pn,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Sn}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Xt}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Ir=`${l}${S}${st}Service`.replace(/[^a-zA-Z0-9]/g,""),en=cr.desiredCount||1;this.builder.addResource(Ir,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-${st}`,Cluster:{Ref:Ie},TaskDefinition:{Ref:kt},DesiredCount:en,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Rt}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:st,ContainerPort:lr,TargetGroupArn:{Ref:Xt}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${l}-${S}-${st}`},{Key:"Environment",Value:S}]},DependsOn:[kt,dr,Xt]});let yr=cr.autoScaling;if(yr){let Sn=`${l}${S}${st}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Sn,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:yr.max||10,MinCapacity:yr.min||1,ResourceId:{"Fn::Sub":`service/\${${Ie}}/${l}-${S}-${st}`},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:Ir}),yr.targetCpuUtilization)this.builder.addResource(`${l}${S}${st}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${S}-${st}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Sn},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:yr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(yr.targetMemoryUtilization)this.builder.addResource(`${l}${S}${st}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${S}-${st}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Sn},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:yr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(it?.domain&&it?.hostedZoneId)this.builder.addResource(`${l}${S}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:it.hostedZoneId,Name:`api.${it.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[wt,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[wt,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[Ie,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${l}-${S}-${st}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[wt,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let Xt=`${l}${S}${st}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Xt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-${st}`,Cluster:{Ref:Ie},TaskDefinition:{Ref:kt},DesiredCount:cr.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Rt}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${l}-${S}-${st}`},{Key:"Environment",Value:S}]},DependsOn:[kt]})}break}}generateServerless(l,S){if(this.mergedConfig.infrastructure?.functions)for(let[b,P]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(P))continue;let{role:v,logicalId:it}=Y.createRole({slug:l,environment:S,roleName:`${l}-${S}-${b}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(it,v);let{lambdaFunction:Pe,logicalId:Ie}=o.createLambdaFunction({slug:l,environment:S,functionName:`${l}-${S}-${b}`,handler:P.handler||"index.handler",runtime:P.runtime||"nodejs20.x",code:{zipFile:P.code||"export const handler = async () => ({ statusCode: 200 });"},role:it,timeout:P.timeout,memorySize:P.memorySize});this.builder.addResource(Ie,Pe)}if(this.mergedConfig.infrastructure?.api){let{restApi:b,logicalId:P}=hd.createRestApi({slug:l,environment:S,apiName:`${l}-${S}-api`});this.builder.addResource(P,b)}}generateServer(l,S){if(!this.mergedConfig.infrastructure?.servers)return;let b=this.mergedConfig.infrastructure.servers,P=this.mergedConfig.infrastructure?.compute,v=this.mergedConfig.infrastructure?.ssl;if(Object.values(b).some((Pe)=>!Pe.privateNetwork||Pe.privateNetwork==="create"))this.generateNetworkInfrastructure(l,S);for(let[Pe,Ie]of Object.entries(b)){let rt=Ie.instanceType||Ie.size||P?.size,st=(rt?o.InstanceSize.specs[rt]:void 0)?.instanceType||rt||"t3.micro",cr=Ie.type||"app",lr=Ie.userData||Ie.startupScript;if(!lr)lr=o.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:Ie.bunVersion||"latest",webServer:"none",domain:Ie.domain,enableSsl:!!v?.enabled,sslEmail:v?.letsEncrypt?.email,installRedis:cr==="cache",installDatabaseClients:!!Ie.database});let fr=Ie.privateNetwork&&Ie.privateNetwork!=="create"?Ie.privateNetwork:{Ref:"VPC"},It=Ie.subnet||{Ref:"PublicSubnet1"},ye=!!this.mergedConfig.infrastructure?.email?.server?.enabled,kt=[22,80,443,this.resolveApiOriginPort()];if(ye)kt.push(25,465,587,143,993);let ie=o.createServerModeStack({slug:`${l}-${Pe}`,environment:S,vpcId:fr,subnetId:It,instanceType:st,keyName:Ie.keyName||`${l}-${S}`,domain:Ie.domain,userData:lr,volumeSize:Ie.diskSize||20,imageId:Ie.image,allowedPorts:kt});for(let[Dt,wt]of Object.entries(ie.resources))this.builder.addResource(Dt,wt);this.serverEipLogicalIds.set(Pe,ie.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${Pe}Instance`,ie.outputs.instanceLogicalId),this.builder.addOutput(`${Pe}InstanceId`,{Value:{Ref:ie.outputs.instanceLogicalId},Description:`Instance ID for ${Pe} server`}),this.builder.addOutput(`${Pe}PublicIp`,{Value:{Ref:ie.outputs.eipLogicalId},Description:`Public IP for ${Pe} server`})}}generateComputeApp(l,S){let b=this.mergedConfig.infrastructure?.compute;if(!b)return;let P=this.mergedConfig.sites||{},v=Object.entries(P),Pe=this.mergedConfig.infrastructure?.dns?.domain,Ie=this.mergedConfig.infrastructure?.database,rt=b.size,st=(rt?o.InstanceSize.specs[rt]:void 0)?.instanceType||rt||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(l,S);let cr=this.buildCaddyfile(v),lr=o.UserData.generateBunAppScript({runtime:b.runtime||"bun",runtimeVersion:b.runtimeVersion||"latest",systemPackages:b.systemPackages,database:Ie,caddyfile:cr}),fr=As(b.appUpdates),It=fr.length>0?`${lr}
|
|
10
|
+
`)}normalizeMountPath(l){let S=l?.mountPath||l?.path;if(!S||S==="/")return;let P=`/${S}`.replace(/\/+/g,"/").replace(/\/$/,"");return P==="/"?void 0:P}storageBucketLogicalId(l,S,P){return`${l}-${S}-s3-${P}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((E)=>E.charAt(0).toUpperCase()+E.slice(1)).join("")}pathMountRewriteFunctionCode(l,S="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(l)}; var rewriteStyle = ${JSON.stringify(S)}; 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,S=this.environment,P=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),E=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),v=!!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,S),this.generateContainerInfrastructure(l,S);if(P)this.generateServerless(l,S);if(E)this.generateServer(l,S);if(v)this.generateComputeApp(l,S);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(l,S);if(this.generateSharedInfrastructure(l,S),this.config.tags)this.applyGlobalTags(this.config.tags);return this}applyGlobalTags(l){}generateNetworkInfrastructure(l,S){if(this.builder.hasResource("VPC"))return;let E=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:v,logicalId:it}=f.createVpc({slug:l,environment:S,cidr:E,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",v);let Pe=`${l}${S}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pe,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${l}-${S}-igw`},{Key:"Environment",Value:S}]}});let Ie=`${l}${S}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ie,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:Pe}}});let rt=`${l}${S}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(rt,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${l}-${S}-public-rt`},{Key:"Environment",Value:S}]}}),this.builder.addResource(`${l}${S}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:rt},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:Pe}},DependsOn:Ie});let Pt=this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1",st=["a","b"];for(let cr=0;cr<2;cr++){let lr=`PublicSubnet${cr+1}`;this.builder.addResource(lr,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${cr}.0/24`,AvailabilityZone:`${Pt}${st[cr]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${l}-${S}-public-${st[cr]}`},{Key:"Environment",Value:S}]}}),this.builder.addResource(`${lr}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:lr},RouteTableId:{Ref:rt}}})}}generateContainerInfrastructure(l,S){let P=this.mergedConfig.infrastructure?.containers;if(!P)return;let E=this.mergedConfig.infrastructure?.loadBalancer,v=this.mergedConfig.infrastructure?.ssl,it=this.mergedConfig.infrastructure?.dns,Pe;if(v?.enabled&&v.domains?.length)if(v.certificateArn);else{let st=v.domains[0],cr=v.domains.slice(1).map((Dt)=>{if(Dt.includes(".")&&Dt.endsWith(st))return Dt.replace(`.${st}`,"");return Dt}),{certificate:lr,logicalId:fr}=I.createCertificate({domain:st,subdomains:cr,slug:l,environment:S,validationMethod:"DNS",hostedZoneId:it?.hostedZoneId});Pe=fr,this.builder.addResource(fr,lr)}let Ie="ECSCluster";this.builder.addResource(Ie,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${l}-${S}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${l}-${S}`},{Key:"Environment",Value:S}]}});let rt=`${l}${S}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(rt,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${l}-${S}`,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}-${S}-alb-sg`},{Key:"Environment",Value:S}]}});let Pt=`${l}${S}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[st,cr]of Object.entries(P)){let lr=cr.port||3000;this.builder.addResource(Pt,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${l}-${S}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:lr,ToPort:lr,SourceSecurityGroupId:{Ref:rt},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${l}-${S}-ecs-sg`},{Key:"Environment",Value:S}]}});let fr=`${l}${S}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(fr,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${S}-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 Dt=`${l}${S}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Dt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${S}-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 Rt=`${l}${S}${st}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),Se=`/ecs/${l}-${S}-${st}`;this.builder.addResource(Rt,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:Se,RetentionInDays:30}});let kt=`${l}${S}${st}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),ie=String(cr.cpu||512),It=String(cr.memory||1024);this.builder.addResource(kt,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${S}-${st}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:ie,Memory:It,ExecutionRoleArn:{"Fn::GetAtt":[fr,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[Dt,"Arn"]},ContainerDefinitions:[{Name:st,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${l}:latest`},Essential:!0,PortMappings:[{ContainerPort:lr,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":Se,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":st}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${lr}${cr.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${l}-${S}-${st}`},{Key:"Environment",Value:S}]},DependsOn:[fr,Dt,Rt]});let wt=`${l}${S}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(E?.enabled!==!1){this.builder.addResource(wt,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${l}-${S}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:rt}],Tags:[{Key:"Name",Value:`${l}-${S}-alb`},{Key:"Environment",Value:S}]}});let Xt=`${l}${S}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),ar=E?.healthCheck?.path||cr.healthCheck||"/health";this.builder.addResource(Xt,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${l}-${S}-tg`,Port:lr,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:ar,HealthCheckIntervalSeconds:E?.healthCheck?.interval||30,HealthyThresholdCount:E?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:E?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${l}-${S}-tg`},{Key:"Environment",Value:S}]}});let dr=`${l}${S}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(v?.enabled&&v?.redirectHttp)this.builder.addResource(dr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(dr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Xt}}]}});if(v?.enabled){let Cn=v.certificateArn||(Pe?{Ref:Pe}:void 0);if(Cn){let Pn=`${l}${S}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pn,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Cn}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Xt}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Ir=`${l}${S}${st}Service`.replace(/[^a-zA-Z0-9]/g,""),tn=cr.desiredCount||1;this.builder.addResource(Ir,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-${st}`,Cluster:{Ref:Ie},TaskDefinition:{Ref:kt},DesiredCount:tn,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Pt}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:st,ContainerPort:lr,TargetGroupArn:{Ref:Xt}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${l}-${S}-${st}`},{Key:"Environment",Value:S}]},DependsOn:[kt,dr,Xt]});let yr=cr.autoScaling;if(yr){let Cn=`${l}${S}${st}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Cn,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:yr.max||10,MinCapacity:yr.min||1,ResourceId:{"Fn::Sub":`service/\${${Ie}}/${l}-${S}-${st}`},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:Ir}),yr.targetCpuUtilization)this.builder.addResource(`${l}${S}${st}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${S}-${st}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Cn},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:yr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(yr.targetMemoryUtilization)this.builder.addResource(`${l}${S}${st}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${S}-${st}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Cn},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:yr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(it?.domain&&it?.hostedZoneId)this.builder.addResource(`${l}${S}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:it.hostedZoneId,Name:`api.${it.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[wt,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[wt,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[Ie,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${l}-${S}-${st}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[wt,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let Xt=`${l}${S}${st}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Xt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-${st}`,Cluster:{Ref:Ie},TaskDefinition:{Ref:kt},DesiredCount:cr.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Pt}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${l}-${S}-${st}`},{Key:"Environment",Value:S}]},DependsOn:[kt]})}break}}generateServerless(l,S){if(this.mergedConfig.infrastructure?.functions)for(let[P,E]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(E))continue;let{role:v,logicalId:it}=Y.createRole({slug:l,environment:S,roleName:`${l}-${S}-${P}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(it,v);let{lambdaFunction:Pe,logicalId:Ie}=o.createLambdaFunction({slug:l,environment:S,functionName:`${l}-${S}-${P}`,handler:E.handler||"index.handler",runtime:E.runtime||"nodejs20.x",code:{zipFile:E.code||"export const handler = async () => ({ statusCode: 200 });"},role:it,timeout:E.timeout,memorySize:E.memorySize});this.builder.addResource(Ie,Pe)}if(this.mergedConfig.infrastructure?.api){let{restApi:P,logicalId:E}=Id.createRestApi({slug:l,environment:S,apiName:`${l}-${S}-api`});this.builder.addResource(E,P)}}generateServer(l,S){if(!this.mergedConfig.infrastructure?.servers)return;let P=this.mergedConfig.infrastructure.servers,E=this.mergedConfig.infrastructure?.compute,v=this.mergedConfig.infrastructure?.ssl;if(Object.values(P).some((Pe)=>!Pe.privateNetwork||Pe.privateNetwork==="create"))this.generateNetworkInfrastructure(l,S);for(let[Pe,Ie]of Object.entries(P)){let rt=Ie.instanceType||Ie.size||E?.size,st=(rt?o.InstanceSize.specs[rt]:void 0)?.instanceType||rt||"t3.micro",cr=Ie.type||"app",lr=Ie.userData||Ie.startupScript;if(!lr)lr=o.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:Ie.bunVersion||"latest",webServer:"none",domain:Ie.domain,enableSsl:!!v?.enabled,sslEmail:v?.letsEncrypt?.email,installRedis:cr==="cache",installDatabaseClients:!!Ie.database});let fr=Ie.privateNetwork&&Ie.privateNetwork!=="create"?Ie.privateNetwork:{Ref:"VPC"},Dt=Ie.subnet||{Ref:"PublicSubnet1"},Se=!!this.mergedConfig.infrastructure?.email?.server?.enabled,kt=[22,80,443,this.resolveApiOriginPort()];if(Se)kt.push(25,465,587,143,993);let ie=o.createServerModeStack({slug:`${l}-${Pe}`,environment:S,vpcId:fr,subnetId:Dt,instanceType:st,keyName:Ie.keyName||`${l}-${S}`,domain:Ie.domain,userData:lr,volumeSize:Ie.diskSize||20,imageId:Ie.image,allowedPorts:kt});for(let[It,wt]of Object.entries(ie.resources))this.builder.addResource(It,wt);this.serverEipLogicalIds.set(Pe,ie.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${Pe}Instance`,ie.outputs.instanceLogicalId),this.builder.addOutput(`${Pe}InstanceId`,{Value:{Ref:ie.outputs.instanceLogicalId},Description:`Instance ID for ${Pe} server`}),this.builder.addOutput(`${Pe}PublicIp`,{Value:{Ref:ie.outputs.eipLogicalId},Description:`Public IP for ${Pe} server`})}}generateComputeApp(l,S){let P=this.mergedConfig.infrastructure?.compute;if(!P)return;let E=this.mergedConfig.sites||{},v=Object.entries(E),Pe=this.mergedConfig.infrastructure?.dns?.domain,Ie=this.mergedConfig.infrastructure?.database,rt=P.size,st=(rt?o.InstanceSize.specs[rt]:void 0)?.instanceType||rt||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(l,S);let cr=this.buildCaddyfile(v),lr=o.UserData.generateBunAppScript({runtime:P.runtime||"bun",runtimeVersion:P.runtimeVersion||"latest",systemPackages:P.systemPackages,database:Ie,caddyfile:cr}),fr=Is(P.appUpdates),Dt=fr.length>0?`${lr}
|
|
11
11
|
${fr.join(`
|
|
12
12
|
`)}
|
|
13
|
-
`:lr,
|
|
14
|
-
else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`}});let xa=[{Id:Hi,DomainName:{"Fn::Sub":`\${${dr}}.s3.${$n}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:ye}}],oa=[],Va=[];if(this.shouldRouteStorageBucketToCompute(ie,Dt)){this.appendComputeAppOrigin(xa,oa,Va,l,S,this.resolveComputeCachePathPatterns(Dt.computeRoutes));for(let on of kt){let ca=`S3-${l}-${S}-${on.name}`,Wa=`${l}${S}${on.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Wa,{Type:"AWS::CloudFront::Function",Properties:{Name:`${l}-${S}-${on.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${l} ${S} ${on.name} at ${on.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(on.mountPath,on.rewriteStyle)}}),xa.push({Id:ca,DomainName:{"Fn::Sub":`\${${on.logicalId}}.s3.${$n}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:ye}}),Va.push(on.logicalId,Wa);for(let pc of[on.mountPath,`${on.mountPath}/*`])oa.push({PathPattern:pc,TargetOriginId:ca,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":[Wa,"FunctionARN"]}}]})}}let ts={Type:"AWS::CloudFront::Distribution",DependsOn:[dr,ye,...Dn?[Dn]:[],...Va],Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${S} ${ie} site`,DefaultRootObject:"index.html",Origins:xa,DefaultCacheBehavior:{TargetOriginId:Hi,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...Dn?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Dn,"FunctionARN"]}}]}:{}},...oa.length>0?{CacheBehaviors:oa}:{},...yr.length>0?{Aliases:yr}:{},ViewerCertificate:Xi,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:jn}}};if(Ie)ts.DependsOn.push(Ie);this.builder.addResource(en,ts);let uc=`${dr}CloudFrontPolicy`;if(this.builder.addResource(uc,{Type:"AWS::S3::BucketPolicy",DependsOn:[dr,en],Properties:{Bucket:{Ref:dr},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${dr}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${en}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(ie,Dt))for(let on of kt){let ca=`${on.logicalId}CloudFrontPolicy`;this.builder.addResource(ca,{Type:"AWS::S3::BucketPolicy",DependsOn:[on.logicalId,en],Properties:{Bucket:{Ref:on.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:::\${${on.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${en}}`}}}}]}}})}if(yr.length>0)Pe.push({name:ie,bucketLogicalId:dr,distLogicalId:en,oacLogicalId:ye,aliases:yr});this.builder.addOutput(`${ie}CloudFrontDomain`,{Value:{"Fn::GetAtt":[en,"DomainName"]},Description:`CloudFront domain for ${ie}`}),this.builder.addOutput(`${ie}CloudFrontDistributionId`,{Value:{Ref:en},Description:`CloudFront distribution ID for ${ie}`})}if(this.builder.addOutput(`${ie}BucketName`,{Value:{Ref:dr},Description:`S3 bucket name for ${ie}`}),ie==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:dr},Description:"Frontend S3 bucket name"});if(ie==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:dr},Description:"Documentation S3 bucket name"});if(ie==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:dr},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let Pt=this.mergedConfig.infrastructure.sftp,ye=md.create({...Pt,storage:this.resolveSftpStorage(Pt,l,S)??Pt.storage,slug:l,environment:S});for(let[kt,ie]of Object.entries(ye.resources))this.builder.addResource(kt,ie);this.builder.addOutput("SftpServerId",{Value:{Ref:ye.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${ye.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:ye.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(it&&Pe.length>0)for(let{name:Pt,distLogicalId:ye,aliases:kt}of Pe)for(let ie of kt){let Dt=ie.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Dt}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[ye],Properties:{HostedZoneId:it,Name:ie,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[ye,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${Dt}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[ye],Properties:{HostedZoneId:it,Name:ie,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[ye,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[Pt,ye]of Object.entries(this.mergedConfig.infrastructure.databases))if(ye.engine==="dynamodb"){let{table:kt,logicalId:ie}=Ut.createTable({slug:l,environment:S,tableName:`${l}-${S}-${Pt}`,partitionKey:ye.partitionKey||{name:"id",type:"S"},sortKey:ye.sortKey});this.builder.addResource(ie,kt)}else if(ye.engine==="postgres"){let{dbInstance:kt,logicalId:ie}=Ut.createPostgres({slug:l,environment:S,dbInstanceIdentifier:`${l}-${S}-${Pt}`,masterUsername:ye.username||"admin",masterUserPassword:ye.password||"changeme123",allocatedStorage:ye.storage||20,dbInstanceClass:ye.instanceClass||"db.t3.micro"});this.builder.addResource(ie,kt)}else if(ye.engine==="mysql"){let{dbInstance:kt,logicalId:ie}=Ut.createMysql({slug:l,environment:S,dbInstanceIdentifier:`${l}-${S}-${Pt}`,masterUsername:ye.username||"admin",masterUserPassword:ye.password||"changeme123",allocatedStorage:ye.storage||20,dbInstanceClass:ye.instanceClass||"db.t3.micro"});this.builder.addResource(ie,kt)}}if(this.mergedConfig.infrastructure?.cdn)for(let[Pt,ye]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!ye.origin)continue;let kt=typeof ye.customDomain==="string"?ye.customDomain:ye.customDomain?.domain||ye.domain,ie=typeof ye.customDomain==="object"?ye.customDomain?.certificateArn:ye.certificateArn,Dt=ie||rt,wt=`${l}${S}${Pt}CDN`.replace(/[^a-zA-Z0-9]/g,""),Xt=`S3-${l}-${S}-${Pt}-cdn`,ar=[{Id:Xt,DomainName:ye.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:ye.originShield?{Enabled:!0,OriginShieldRegion:ye.originShieldRegion||this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1}}],dr=[],Ir=[];if(ye.routeCompute)this.appendComputeAppOrigin(ar,dr,Ir,l,S,this.resolveComputeCachePathPatterns(ye.computeRoutes));let en=Dt&&kt?{AcmCertificateArn:Ie&&!ie?{Ref:Ie}:Dt,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},yr=[...Ir];if(Ie&&!ie&&kt)yr.push(Ie);let Sn={Type:"AWS::CloudFront::Distribution",...yr.length>0?{DependsOn:yr}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${S} ${Pt} CDN`,DefaultRootObject:"index.html",Origins:ar,DefaultCacheBehavior:{TargetOriginId:Xt,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:ye.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...dr.length>0?{CacheBehaviors:dr}:{},...kt&&Dt?{Aliases:[kt]}:{},ViewerCertificate:en,PriceClass:"PriceClass_100",HttpVersion:ye.http3?"http2and3":"http2"}}};if(this.builder.addResource(wt,Sn),it&&kt&&Dt){let Pn=kt.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Pn}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[wt,...Ie&&!ie?[Ie]:[]],Properties:{HostedZoneId:it,Name:kt,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[wt,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[Pt,ye]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(ye))continue;let{queue:kt,logicalId:ie}=M.createQueue({slug:l,environment:S,name:`${l}-${S}-${Pt}`,fifo:ye.fifo,visibilityTimeout:ye.visibilityTimeout,messageRetentionPeriod:ye.messageRetentionPeriod,delaySeconds:ye.delaySeconds,maxMessageSize:ye.maxMessageSize,receiveMessageWaitTime:ye.receiveMessageWaitTime,contentBasedDeduplication:ye.contentBasedDeduplication,encrypted:ye.encrypted,kmsKeyId:ye.kmsKeyId});this.builder.addResource(ie,kt);let Dt;if(ye.deadLetterQueue){let{deadLetterQueue:wt,updatedSourceQueue:Xt,deadLetterLogicalId:ar}=M.createDeadLetterQueue(ie,{slug:l,environment:S,maxReceiveCount:ye.maxReceiveCount});Dt=ar,this.builder.addResource(ar,wt);let Ir=this.builder.getResources()[ie];if(Ir?.Properties)Ir.Properties.RedrivePolicy=Xt.Properties?.RedrivePolicy}if(ye.trigger){let wt=ye.trigger,Xt=`${l}${S}${wt.functionName}`.replace(/[^a-zA-Z0-9]/g,""),ar={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[ie,"Arn"]},FunctionName:{Ref:Xt},BatchSize:wt.batchSize||10,MaximumBatchingWindowInSeconds:wt.batchWindow||0,Enabled:!0,...wt.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...wt.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:wt.maxConcurrency}},...wt.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(wt.filterPattern)}]}}},DependsOn:[ie,Xt]};this.builder.addResource(`${ie}Trigger`,ar)}if(ye.alarms?.enabled){let wt=ye.alarms,Xt=wt.notificationTopicArn;if(!Xt&&wt.notificationEmails?.length){let Ir=`${ie}AlarmTopic`;this.builder.addResource(Ir,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-${Pt}-alarms`,DisplayName:`${Pt} Queue Alarms`}}),wt.notificationEmails.forEach((en,yr)=>{this.builder.addResource(`${Ir}Sub${yr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Ir},Protocol:"email",Endpoint:en}})}),Xt={Ref:Ir}}let ar=wt.queueDepthThreshold||1000;this.builder.addResource(`${ie}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Pt}-queue-depth`,AlarmDescription:`Queue ${Pt} depth exceeds ${ar} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:ar,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ie,"QueueName"]}}],...Xt&&{AlarmActions:[Xt],OKActions:[Xt]}}});let dr=wt.messageAgeThreshold||3600;if(this.builder.addResource(`${ie}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Pt}-message-age`,AlarmDescription:`Queue ${Pt} oldest message exceeds ${dr} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:dr,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ie,"QueueName"]}}],...Xt&&{AlarmActions:[Xt],OKActions:[Xt]}}}),Dt&&wt.dlqAlarm!==!1)this.builder.addResource(`${Dt}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Pt}-dlq-messages`,AlarmDescription:`Dead letter queue for ${Pt} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[Dt,"QueueName"]}}],...Xt&&{AlarmActions:[Xt]}}})}if(ye.subscribe){let wt=ye.subscribe,Xt=wt.topicArn;if(!Xt&&wt.topicName)Xt={Ref:wt.topicName};if(Xt){this.builder.addResource(`${ie}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:ie}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[ie,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":Xt}}}]}}});let ar={TopicArn:Xt,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[ie,"Arn"]},RawMessageDelivery:wt.rawMessageDelivery||!1};if(wt.filterPolicy)ar.FilterPolicy=wt.filterPolicy,ar.FilterPolicyScope=wt.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${ie}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:ar,DependsOn:`${ie}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(l,S);else this.generateRealtimeResources(l,S);let Rt=this.mergedConfig.infrastructure?.redirects;if(Rt){let Pt=Rt.target||this.mergedConfig.infrastructure?.dns?.domain||"",ye=Rt.protocol||"https";if(Rt.domains?.length&&Pt)for(let kt of Rt.domains){let{bucket:ie,bucketPolicy:Dt,logicalId:wt,policyLogicalId:Xt}=pt.createDomainRedirectBucket({slug:l,environment:S,sourceDomain:kt,targetDomain:Pt,protocol:ye});this.builder.addResource(wt,ie),this.builder.addResource(Xt,Dt)}if(Rt.paths&&Object.keys(Rt.paths).length>0){let kt=pt.fromMapping(Rt.paths,{statusCode:Rt.statusCode||301}),{function:ie,logicalId:Dt}=pt.createPathRedirectFunction({slug:l,environment:S,rules:kt});this.builder.addResource(Dt,ie)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[Pt,ye]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:kt,logicalId:ie}=Zs.createAlarm({slug:l,environment:S,alarmName:`${l}-${S}-${Pt}`,metricName:ye.metricName||"Errors",namespace:ye.namespace||"AWS/Lambda",threshold:ye.threshold||1,comparisonOperator:ye.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(ie,kt)}let st=this.mergedConfig.infrastructure?.cache;if(st){let Pt=st.type||"redis";if(Pt==="redis"){this.generateNetworkInfrastructure(l,S);let ye=st.redis||{},{replicationGroup:kt,subnetGroup:ie,logicalId:Dt,subnetGroupId:wt}=Ys.createRedis({slug:l,environment:S,nodeType:ye.nodeType||st.nodeType||"cache.t3.micro",engineVersion:ye.engineVersion||"7.1",port:ye.port||6379,numCacheClusters:ye.numCacheNodes||2,automaticFailover:ye.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:ye.snapshotRetentionLimit||7,snapshotWindow:ye.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Dt,kt),ie&&wt)this.builder.addResource(wt,ie);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Dt,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[Dt,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(Pt==="memcached"){this.generateNetworkInfrastructure(l,S);let ye=st.elasticache||{},{cluster:kt,subnetGroup:ie,logicalId:Dt,subnetGroupId:wt}=Ys.createMemcached({slug:l,environment:S,nodeType:ye.nodeType||st.nodeType||"cache.t3.micro",engineVersion:ye.engineVersion||"1.6.22",numCacheNodes:ye.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Dt,kt),ie&&wt)this.builder.addResource(wt,ie);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Dt,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let cr=this.mergedConfig.infrastructure?.email;if(cr){let Pt=cr.domain||this.mergedConfig.infrastructure?.dns?.domain;if(Pt){let{emailIdentity:ye,logicalId:kt}=m.verifyDomain({domain:Pt,slug:l,environment:S,enableDkim:cr.enableDkim!==!1,dkimKeyLength:cr.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(kt,ye),cr.configurationSet!==!1){let{configurationSet:wt,logicalId:Xt}=m.createConfigurationSet({slug:l,environment:S});this.builder.addResource(Xt,wt)}let ie=cr.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(ie){if(cr.enableDkim!==!1)for(let Ir=1;Ir<=3;Ir++){let en=`DkimRecord${Ir}${Pt.replace(/\./g,"")}`;this.builder.addResource(en,{Type:"AWS::Route53::RecordSet",DependsOn:[kt],Properties:{HostedZoneId:ie,Name:{"Fn::GetAtt":[kt,`DkimDNSTokenName${Ir}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[kt,`DkimDNSTokenValue${Ir}`]}]}})}let{record:wt,logicalId:Xt}=m.createSpfRecord(Pt,ie);this.builder.addResource(Xt,wt);let{record:ar,logicalId:dr}=m.createDmarcRecord(Pt,ie,{policy:"none",reportingEmail:cr.dmarcReportingEmail||`dmarc-reports@${Pt}`});this.builder.addResource(dr,ar)}this.builder.addOutput("EmailDomain",{Value:Pt,Description:"SES verified email domain"});let Dt=cr.server;if(Dt?.enabled&&ie){let wt=this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1",Xt=`${l}-${S}-email`,{role:ar,policy:dr,roleLogicalId:Ir,policyLogicalId:en}=m.createEmailLambdaRole({slug:l,environment:S,s3BucketArn:`arn:aws:s3:::${Xt}`,sesIdentityArn:`arn:aws:ses:${wt}:*:identity/${Pt}`});this.builder.addResource(Ir,ar),this.builder.addResource(en,dr);let{function:yr,permission:Sn,logicalId:Pn,permissionLogicalId:Fn}=m.createInboundEmailLambda({slug:l,environment:S,roleArn:{"Fn::GetAtt":[Ir,"Arn"]},s3BucketName:Xt,organizedPrefix:"mailboxes/"});this.builder.addResource(Pn,yr),this.builder.addResource(Fn,Sn);let jn=m.createInboundEmailSetup({slug:l,environment:S,domain:Pt,s3BucketName:Xt,s3KeyPrefix:"inbox/",region:wt,hostedZoneId:ie,lambdaFunctionArn:{"Fn::GetAtt":[Pn,"Arn"]}});for(let[Hi,$n]of Object.entries(jn.resources)){if($n.Type==="AWS::SES::ReceiptRule")$n.DependsOn=[Fn,Pn];this.builder.addResource(Hi,$n)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:Pn},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:Xt,Description:"S3 bucket for email storage"});let Xi=this.serverEipLogicalIds.get("app");if(Xi&&ie){let $n=`${Dt?.subdomain||"mail"}.${Pt}`,Dn=$n.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Dn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:ie,Name:$n,Type:"A",TTL:"300",ResourceRecords:[{Ref:Xi}]}})}this.builder.addOutput("MailHost",{Value:`mail.${Pt}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let lr=this.mergedConfig.infrastructure?.search;if(lr){let Pt=lr.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(Pt)this.generateNetworkInfrastructure(l,S);let{domain:ye,logicalId:kt}=Qt.createDomain({slug:l,environment:S,engineVersion:lr.engineVersion||"OpenSearch_2.11",instanceType:lr.instanceType||"t3.small.search",instanceCount:lr.instanceCount||1,volumeSize:lr.volumeSize||10,volumeType:lr.volumeType||"gp3",dedicatedMaster:lr.dedicatedMaster||!1,dedicatedMasterType:lr.dedicatedMasterType,dedicatedMasterCount:lr.dedicatedMasterCount||3,multiAz:lr.multiAz||!1,encryption:lr.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:lr.advancedSecurity,autoTune:lr.autoTune!==!1,vpc:Pt});this.builder.addResource(kt,ye),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[kt,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[kt,"Arn"]},Description:"OpenSearch domain ARN"})}let fr=this.mergedConfig.infrastructure?.fileSystem;if(fr&&Object.keys(fr).length>0){this.generateNetworkInfrastructure(l,S);for(let[Pt,ye]of Object.entries(fr)){let{fileSystem:kt,logicalId:ie}=Ge.createFileSystem({slug:`${l}-${Pt}`,environment:S,encrypted:ye.encrypted!==!1,performanceMode:ye.performanceMode||"generalPurpose",throughputMode:ye.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(ie,kt);let{securityGroup:Dt,logicalId:wt}=Ge.createEfsSecurityGroup({slug:`${l}-${Pt}`,environment:S,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(wt,Dt);let{mountTargets:Xt,logicalIds:ar}=Ge.createMultiAzMountTargets(ie,{slug:`${l}-${Pt}`,environment:S,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:wt}});for(let dr=0;dr<Xt.length;dr++)this.builder.addResource(ar[dr],Xt[dr]);this.builder.addOutput(`${Pt}FileSystemId`,{Value:{Ref:ie},Description:`EFS file system ID for ${Pt}`})}}let It=this.mergedConfig.infrastructure?.ai;if(It){let Pt=It.service||"ecs",ye=It.models||["*"],kt=It.allowStreaming!==!1,ie;if(Pt==="ecs")ie=Te.enableBedrockForEcs({slug:l,environment:S,models:ye,allowStreaming:kt});else if(Pt==="ec2")ie=Te.enableBedrockForEc2({slug:l,environment:S,models:ye,allowStreaming:kt});else if(Pt==="lambda")ie=Te.enableBedrockForLambda({slug:l,environment:S,models:ye,allowStreaming:kt});else ie=Te.createBedrockRole(Pt,{slug:l,environment:S,models:ye,allowStreaming:kt});if(this.builder.addResource(ie.logicalId,ie.role),It.allowAsync){let{policy:Dt,logicalId:wt}=Te.createBedrockPolicy({slug:l,environment:S,models:ye,allowStreaming:kt,allowAsync:!0});this.builder.addResource(wt,Dt)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[ie.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(l,S){let b=this.mergedConfig.infrastructure?.realtime;if(!b)return;let P=b.name||`${l}-${S}-realtime`,v=b.scaling||{},it=b.storage||{type:"dynamodb"},Pe=v.handlerMemory||256,Ie=v.handlerTimeout||30,rt=`${l}${S}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),Rt=`${l}${S}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(it.type==="dynamodb"){let ar=it.dynamodb||{},dr=ar.billingMode||"PAY_PER_REQUEST";this.builder.addResource(rt,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${S}-realtime-connections`,BillingMode:dr,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"},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ar.readCapacity||5,WriteCapacityUnits:ar.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ar.readCapacity||5,WriteCapacityUnits:ar.writeCapacity||5}},...ar.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${l}-${S}-realtime-connections`},{Key:"Environment",Value:S}]}}),this.builder.addResource(Rt,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${S}-realtime-channels`,BillingMode:dr,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"},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ar.readCapacity||5,WriteCapacityUnits:ar.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ar.readCapacity||5,WriteCapacityUnits:ar.writeCapacity||5}},Tags:[{Key:"Name",Value:`${l}-${S}-realtime-channels`},{Key:"Environment",Value:S}]}})}let st=`${l}${S}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(st,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${S}-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":[rt,"Arn"]},{"Fn::Sub":`\${${rt}.Arn}/index/*`},{"Fn::GetAtt":[Rt,"Arn"]},{"Fn::Sub":`\${${Rt}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let cr=`${l}${S}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),lr=`${l}${S}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),fr=`${l}${S}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(cr,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[st,"Arn"]},MemorySize:Pe,Timeout:Ie,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:rt},CHANNELS_TABLE:{Ref:Rt},ENVIRONMENT:S}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[st,rt]}),this.builder.addResource(lr,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[st,"Arn"]},MemorySize:Pe,Timeout:Ie,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:rt},CHANNELS_TABLE:{Ref:Rt},ENVIRONMENT:S}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[st,rt,Rt]}),this.builder.addResource(fr,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[st,"Arn"]},MemorySize:Pe,Timeout:Ie,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:rt},CHANNELS_TABLE:{Ref:Rt},ENVIRONMENT:S}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[st,rt,Rt]});let It=`${l}${S}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(It,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:P,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:P,Environment:S}}});let Pt=`${cr}Permission`,ye=`${lr}Permission`,kt=`${fr}Permission`;this.builder.addResource(Pt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:cr},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${It}}/*/$connect`}}}),this.builder.addResource(ye,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:lr},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${It}}/*/$disconnect`}}}),this.builder.addResource(kt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:fr},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${It}}/*/$default`}}});let ie=`${It}ConnectInteg`,Dt=`${It}DisconnectInteg`,wt=`${It}MessageInteg`;this.builder.addResource(ie,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:It},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${cr}.Arn}/invocations`}}}),this.builder.addResource(Dt,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:It},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${lr}.Arn}/invocations`}}}),this.builder.addResource(wt,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:It},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${fr}.Arn}/invocations`}}}),this.builder.addResource(`${It}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:It},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${ie}}`}}}),this.builder.addResource(`${It}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:It},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${Dt}}`}}}),this.builder.addResource(`${It}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:It},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${wt}}`}}});let Xt=`${It}Stage`;if(this.builder.addResource(Xt,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:It},StageName:S,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:v.messagesPerSecond||1000,ThrottlingRateLimit:v.messagesPerSecond||1000}}}),b.monitoring?.enabled){let ar=b.monitoring,dr=ar.notificationTopicArn;if(!dr&&ar.notificationEmails?.length){let Ir=`${It}AlarmTopic`;this.builder.addResource(Ir,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),ar.notificationEmails.forEach((en,yr)=>{this.builder.addResource(`${Ir}Sub${yr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Ir},Protocol:"email",Endpoint:en}})}),dr={Ref:Ir}}if(ar.connectionThreshold)this.builder.addResource(`${It}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${ar.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:ar.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:It}}],...dr&&{AlarmActions:[dr]}}});if(ar.errorThreshold)this.builder.addResource(`${It}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${ar.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:ar.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:It}}],...dr&&{AlarmActions:[dr]}}})}this.builder.addOutput(`${It}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${It}}.execute-api.\${AWS::Region}.amazonaws.com/${S}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${It}Id`,{Description:"WebSocket API ID",Value:{Ref:It},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
|
|
13
|
+
`:lr,Rt=v.map(([,ar])=>ar.port).filter((ar)=>typeof ar==="number"&&![80,443].includes(ar)),Se=this.resolveApiOriginPort(),kt=`${l}${S}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),ie=`${l}-${S}-deploy`;this.builder.addResource(kt,{Type:"AWS::S3::Bucket",Properties:{BucketName:ie,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:S},{Key:"ManagedBy",Value:"ts-cloud"}]}});let It=o.createServerModeStack({slug:`${l}-app`,environment:S,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:st,keyName:P.allowSsh?`${l}-${S}`:void 0,domain:Pe,userData:Dt,volumeSize:P.disk?.size||20,imageId:P.image,allowedPorts:[...P.allowSsh?[22]:[],80,443,Se,...Rt]}),wt=It.resources[It.outputs.instanceLogicalId];if(wt?.Properties){let ar=wt.Properties.Tags||[];wt.Properties.Tags=[...ar,{Key:"Project",Value:l},{Key:"Environment",Value:S},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let Xt=It.resources[It.outputs.roleLogicalId];if(Xt?.Properties)Xt.Properties.Policies=Xt.Properties.Policies||[],Xt.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${ie}`,`arn:aws:s3:::${ie}/*`]}]}});for(let[ar,dr]of Object.entries(It.resources))this.builder.addResource(ar,dr);this.builder.addOutput("deployBucketName",{Value:{Ref:kt},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:It.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:It.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",It.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",It.outputs.instanceLogicalId)}generateJumpBox(l,S){let P=this.mergedConfig.infrastructure?.jumpBox;if(!P)return;let E=P===!0?{}:P;if(E.enabled===!1)return;this.generateNetworkInfrastructure(l,S);let v=E.size||"micro",Pe=o.InstanceSize.specs[v]?.instanceType||v||"t3.micro",Ie;if(E.mountEfs)Ie={fileSystemId:typeof E.mountEfs==="string"?E.mountEfs:{Ref:"FileSystem"},mountPath:E.mountPath||"/mnt/efs"};let rt;if(E.databaseTools)rt=o.JumpBox.withDatabaseTools({slug:l,environment:S,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:E.keyName||`${l}-${S}`,allowedCidrs:E.allowedCidrs});else if(Ie)rt=o.JumpBox.withEfsMount({slug:l,environment:S,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:E.keyName||`${l}-${S}`,fileSystemId:Ie.fileSystemId,mountPath:Ie.mountPath,allowedCidrs:E.allowedCidrs});else rt=o.createJumpBox({slug:l,environment:S,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:E.keyName||`${l}-${S}`,instanceType:Pe,allowedCidrs:E.allowedCidrs,mountEfs:Ie});for(let[Pt,st]of Object.entries(rt.resources))this.builder.addResource(Pt,st);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:rt.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(l,S){let P=this.mergedConfig.infrastructure?.ssl,E=this.mergedConfig.infrastructure?.dns,v=E?.domain,it=E?.hostedZoneId,Pe=[],Ie,rt;if(P?.certificateArn)rt=P.certificateArn;else if(P?.enabled&&v&&it){let Rt=P.domains||[v],Se=Rt[0],kt=Rt.slice(1).map((wt)=>{if(wt.includes(".")&&wt.endsWith(Se))return wt.replace(`.${Se}`,"");return wt}),{certificate:ie,logicalId:It}=I.createCertificate({domain:Se,subdomains:kt,slug:l,environment:S,validationMethod:"DNS",hostedZoneId:it});Ie=It,this.builder.addResource(It,ie)}if(this.mergedConfig.infrastructure?.storage){let Rt=Object.entries(this.mergedConfig.infrastructure.storage).some(([,ie])=>ie.website),Se;if(Rt&&(Ie||rt))Se=`${l}${S}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(Se,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${l}-${S}-s3-oac`,Description:`OAC for ${l} ${S} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let kt=Object.entries(this.mergedConfig.infrastructure.storage).map(([ie,It])=>({name:ie,config:It,mountPath:this.normalizeMountPath(It),rewriteStyle:It.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(l,S,ie)})).filter((ie)=>ie.name!=="public"&&ie.config.website&&ie.mountPath);for(let[ie,It]of Object.entries(this.mergedConfig.infrastructure.storage)){let wt=!!(It.website&&Se),Xt=this.storageBucketName(l,S,ie),{bucket:ar,logicalId:dr}=ve.createBucket({slug:l,name:ie,environment:S,bucketName:Xt,versioning:It.versioning,encryption:It.encryption,public:wt?!1:It.public});if(wt&&ar.Properties)ar.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(dr,ar),It.website){let tn=typeof It.website==="object"?It.website:{},yr=ve.enableWebsiteHosting(ar,tn.indexDocument||"index.html",tn.errorDocument);this.builder.addResource(dr,yr)}let Ir=this.normalizeMountPath(It);if(wt&&Se&&v&&!(Ir&&ie!=="public")){let tn=`${l}${S}${ie}CDN`.replace(/[^a-zA-Z0-9]/g,""),yr=[];if(It.aliases&&It.aliases.length>0)yr.push(...It.aliases);else if(ie==="public"){if(yr.push(v),P?.domains?.includes(`www.${v}`))yr.push(`www.${v}`)}else if(ie==="docs")yr.push(`docs.${v}`);else if(ie==="blog")yr.push(`blog.${v}`);let Cn=typeof It.website==="object"?It.website:{},Pn=It.spa===!0,Nn=Cn.errorDocument||(Pn?"index.html":"404.html"),Hi=[];if(Pn)Hi.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else Hi.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${Nn}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${Nn}`,ErrorCachingMinTTL:300});let Fn=rt&&yr.length>0?{AcmCertificateArn:rt,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:Ie&&yr.length>0?{AcmCertificateArn:{Ref:Ie},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Zi=`S3-${l}-${S}-${ie}`,Mn=this.mergedConfig.project.region||"us-east-1",zn;if(!Pn)zn=`${l}${S}${ie}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(zn,{Type:"AWS::CloudFront::Function",Properties:{Name:`${l}-${S}-${ie}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${l} ${S} ${ie} - 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 Oa=[{Id:Zi,DomainName:{"Fn::Sub":`\${${dr}}.s3.${Mn}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Se}}],ca=[],za=[];if(this.shouldRouteStorageBucketToCompute(ie,It)){this.appendComputeAppOrigin(Oa,ca,za,l,S,this.resolveComputeCachePathPatterns(It.computeRoutes));for(let an of kt){let la=`S3-${l}-${S}-${an.name}`,Ka=`${l}${S}${an.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ka,{Type:"AWS::CloudFront::Function",Properties:{Name:`${l}-${S}-${an.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${l} ${S} ${an.name} at ${an.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(an.mountPath,an.rewriteStyle)}}),Oa.push({Id:la,DomainName:{"Fn::Sub":`\${${an.logicalId}}.s3.${Mn}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Se}}),za.push(an.logicalId,Ka);for(let gc of[an.mountPath,`${an.mountPath}/*`])ca.push({PathPattern:gc,TargetOriginId:la,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":[Ka,"FunctionARN"]}}]})}}let Cs={Type:"AWS::CloudFront::Distribution",DependsOn:[dr,Se,...zn?[zn]:[],...za],Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${S} ${ie} site`,DefaultRootObject:"index.html",Origins:Oa,DefaultCacheBehavior:{TargetOriginId:Zi,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...zn?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[zn,"FunctionARN"]}}]}:{}},...ca.length>0?{CacheBehaviors:ca}:{},...yr.length>0?{Aliases:yr}:{},ViewerCertificate:Fn,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:Hi}}};if(Ie)Cs.DependsOn.push(Ie);this.builder.addResource(tn,Cs);let mc=`${dr}CloudFrontPolicy`;if(this.builder.addResource(mc,{Type:"AWS::S3::BucketPolicy",DependsOn:[dr,tn],Properties:{Bucket:{Ref:dr},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${dr}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${tn}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(ie,It))for(let an of kt){let la=`${an.logicalId}CloudFrontPolicy`;this.builder.addResource(la,{Type:"AWS::S3::BucketPolicy",DependsOn:[an.logicalId,tn],Properties:{Bucket:{Ref:an.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:::\${${an.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${tn}}`}}}}]}}})}if(yr.length>0)Pe.push({name:ie,bucketLogicalId:dr,distLogicalId:tn,oacLogicalId:Se,aliases:yr});this.builder.addOutput(`${ie}CloudFrontDomain`,{Value:{"Fn::GetAtt":[tn,"DomainName"]},Description:`CloudFront domain for ${ie}`}),this.builder.addOutput(`${ie}CloudFrontDistributionId`,{Value:{Ref:tn},Description:`CloudFront distribution ID for ${ie}`})}if(this.builder.addOutput(`${ie}BucketName`,{Value:{Ref:dr},Description:`S3 bucket name for ${ie}`}),ie==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:dr},Description:"Frontend S3 bucket name"});if(ie==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:dr},Description:"Documentation S3 bucket name"});if(ie==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:dr},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let Rt=this.mergedConfig.infrastructure.sftp,Se=yd.create({...Rt,storage:this.resolveSftpStorage(Rt,l,S)??Rt.storage,slug:l,environment:S});for(let[kt,ie]of Object.entries(Se.resources))this.builder.addResource(kt,ie);this.builder.addOutput("SftpServerId",{Value:{Ref:Se.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${Se.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:Se.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(it&&Pe.length>0)for(let{name:Rt,distLogicalId:Se,aliases:kt}of Pe)for(let ie of kt){let It=ie.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${It}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Se],Properties:{HostedZoneId:it,Name:ie,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[Se,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${It}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Se],Properties:{HostedZoneId:it,Name:ie,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[Se,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[Rt,Se]of Object.entries(this.mergedConfig.infrastructure.databases))if(Se.engine==="dynamodb"){let{table:kt,logicalId:ie}=Ut.createTable({slug:l,environment:S,tableName:`${l}-${S}-${Rt}`,partitionKey:Se.partitionKey||{name:"id",type:"S"},sortKey:Se.sortKey});this.builder.addResource(ie,kt)}else if(Se.engine==="postgres"){let{dbInstance:kt,logicalId:ie}=Ut.createPostgres({slug:l,environment:S,dbInstanceIdentifier:`${l}-${S}-${Rt}`,masterUsername:Se.username||"admin",masterUserPassword:Se.password||"changeme123",allocatedStorage:Se.storage||20,dbInstanceClass:Se.instanceClass||"db.t3.micro"});this.builder.addResource(ie,kt)}else if(Se.engine==="mysql"){let{dbInstance:kt,logicalId:ie}=Ut.createMysql({slug:l,environment:S,dbInstanceIdentifier:`${l}-${S}-${Rt}`,masterUsername:Se.username||"admin",masterUserPassword:Se.password||"changeme123",allocatedStorage:Se.storage||20,dbInstanceClass:Se.instanceClass||"db.t3.micro"});this.builder.addResource(ie,kt)}}if(this.mergedConfig.infrastructure?.cdn)for(let[Rt,Se]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!Se.origin)continue;let kt=typeof Se.customDomain==="string"?Se.customDomain:Se.customDomain?.domain||Se.domain,ie=typeof Se.customDomain==="object"?Se.customDomain?.certificateArn:Se.certificateArn,It=ie||rt,wt=`${l}${S}${Rt}CDN`.replace(/[^a-zA-Z0-9]/g,""),Xt=`S3-${l}-${S}-${Rt}-cdn`,ar=[{Id:Xt,DomainName:Se.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:Se.originShield?{Enabled:!0,OriginShieldRegion:Se.originShieldRegion||this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1}}],dr=[],Ir=[],tn=["GET","HEAD","OPTIONS"],yr=Xt,Cn;if(Se.failoverOrigin){xr(tn,`the default cache behavior of infrastructure.cdn.${Rt}`);let Fn=`${Xt}-failover`;ar.push({Id:Fn,DomainName:Se.failoverOrigin,OriginPath:"",...Ad(Se.failoverOrigin)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1}}),Cn=yi({primaryOriginId:Xt,secondaryOriginId:Fn,statusCodes:Se.failoverStatusCodes}),yr=Cn.Items[0].Id}else if(Se.failoverStatusCodes)throw Error(`infrastructure.cdn.${Rt}: failoverStatusCodes needs failoverOrigin to fail over to`);if(Se.routeCompute)this.appendComputeAppOrigin(ar,dr,Ir,l,S,this.resolveComputeCachePathPatterns(Se.computeRoutes));let Pn=It&&kt?{AcmCertificateArn:Ie&&!ie?{Ref:Ie}:It,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Nn=[...Ir];if(Ie&&!ie&&kt)Nn.push(Ie);let Hi={Type:"AWS::CloudFront::Distribution",...Nn.length>0?{DependsOn:Nn}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${S} ${Rt} CDN`,DefaultRootObject:"index.html",Origins:ar,...Cn?{OriginGroups:Cn}:{},DefaultCacheBehavior:{TargetOriginId:yr,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:tn,CachedMethods:["GET","HEAD","OPTIONS"],Compress:Se.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...dr.length>0?{CacheBehaviors:dr}:{},...kt&&It?{Aliases:[kt]}:{},ViewerCertificate:Pn,PriceClass:"PriceClass_100",HttpVersion:Se.http3?"http2and3":"http2"}}};if(this.builder.addResource(wt,Hi),it&&kt&&It){let Fn=kt.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Fn}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[wt,...Ie&&!ie?[Ie]:[]],Properties:{HostedZoneId:it,Name:kt,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[wt,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[Rt,Se]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(Se))continue;let{queue:kt,logicalId:ie}=M.createQueue({slug:l,environment:S,name:`${l}-${S}-${Rt}`,fifo:Se.fifo,visibilityTimeout:Se.visibilityTimeout,messageRetentionPeriod:Se.messageRetentionPeriod,delaySeconds:Se.delaySeconds,maxMessageSize:Se.maxMessageSize,receiveMessageWaitTime:Se.receiveMessageWaitTime,contentBasedDeduplication:Se.contentBasedDeduplication,encrypted:Se.encrypted,kmsKeyId:Se.kmsKeyId});this.builder.addResource(ie,kt);let It;if(Se.deadLetterQueue){let{deadLetterQueue:wt,updatedSourceQueue:Xt,deadLetterLogicalId:ar}=M.createDeadLetterQueue(ie,{slug:l,environment:S,maxReceiveCount:Se.maxReceiveCount});It=ar,this.builder.addResource(ar,wt);let Ir=this.builder.getResources()[ie];if(Ir?.Properties)Ir.Properties.RedrivePolicy=Xt.Properties?.RedrivePolicy}if(Se.trigger){let wt=Se.trigger,Xt=`${l}${S}${wt.functionName}`.replace(/[^a-zA-Z0-9]/g,""),ar={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[ie,"Arn"]},FunctionName:{Ref:Xt},BatchSize:wt.batchSize||10,MaximumBatchingWindowInSeconds:wt.batchWindow||0,Enabled:!0,...wt.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...wt.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:wt.maxConcurrency}},...wt.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(wt.filterPattern)}]}}},DependsOn:[ie,Xt]};this.builder.addResource(`${ie}Trigger`,ar)}if(Se.alarms?.enabled){let wt=Se.alarms,Xt=wt.notificationTopicArn;if(!Xt&&wt.notificationEmails?.length){let Ir=`${ie}AlarmTopic`;this.builder.addResource(Ir,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-${Rt}-alarms`,DisplayName:`${Rt} Queue Alarms`}}),wt.notificationEmails.forEach((tn,yr)=>{this.builder.addResource(`${Ir}Sub${yr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Ir},Protocol:"email",Endpoint:tn}})}),Xt={Ref:Ir}}let ar=wt.queueDepthThreshold||1000;this.builder.addResource(`${ie}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Rt}-queue-depth`,AlarmDescription:`Queue ${Rt} depth exceeds ${ar} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:ar,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ie,"QueueName"]}}],...Xt&&{AlarmActions:[Xt],OKActions:[Xt]}}});let dr=wt.messageAgeThreshold||3600;if(this.builder.addResource(`${ie}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Rt}-message-age`,AlarmDescription:`Queue ${Rt} oldest message exceeds ${dr} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:dr,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ie,"QueueName"]}}],...Xt&&{AlarmActions:[Xt],OKActions:[Xt]}}}),It&&wt.dlqAlarm!==!1)this.builder.addResource(`${It}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Rt}-dlq-messages`,AlarmDescription:`Dead letter queue for ${Rt} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[It,"QueueName"]}}],...Xt&&{AlarmActions:[Xt]}}})}if(Se.subscribe){let wt=Se.subscribe,Xt=wt.topicArn;if(!Xt&&wt.topicName)Xt={Ref:wt.topicName};if(Xt){this.builder.addResource(`${ie}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:ie}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[ie,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":Xt}}}]}}});let ar={TopicArn:Xt,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[ie,"Arn"]},RawMessageDelivery:wt.rawMessageDelivery||!1};if(wt.filterPolicy)ar.FilterPolicy=wt.filterPolicy,ar.FilterPolicyScope=wt.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${ie}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:ar,DependsOn:`${ie}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(l,S);else this.generateRealtimeResources(l,S);let Pt=this.mergedConfig.infrastructure?.redirects;if(Pt){let Rt=Pt.target||this.mergedConfig.infrastructure?.dns?.domain||"",Se=Pt.protocol||"https";if(Pt.domains?.length&&Rt)for(let kt of Pt.domains){let{bucket:ie,bucketPolicy:It,logicalId:wt,policyLogicalId:Xt}=pt.createDomainRedirectBucket({slug:l,environment:S,sourceDomain:kt,targetDomain:Rt,protocol:Se});this.builder.addResource(wt,ie),this.builder.addResource(Xt,It)}if(Pt.paths&&Object.keys(Pt.paths).length>0){let kt=pt.fromMapping(Pt.paths,{statusCode:Pt.statusCode||301}),{function:ie,logicalId:It}=pt.createPathRedirectFunction({slug:l,environment:S,rules:kt});this.builder.addResource(It,ie)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[Rt,Se]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:kt,logicalId:ie}=to.createAlarm({slug:l,environment:S,alarmName:`${l}-${S}-${Rt}`,metricName:Se.metricName||"Errors",namespace:Se.namespace||"AWS/Lambda",threshold:Se.threshold||1,comparisonOperator:Se.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(ie,kt)}let st=this.mergedConfig.infrastructure?.cache;if(st){let Rt=st.type||"redis";if(Rt==="redis"){this.generateNetworkInfrastructure(l,S);let Se=st.redis||{},{replicationGroup:kt,subnetGroup:ie,logicalId:It,subnetGroupId:wt}=eo.createRedis({slug:l,environment:S,nodeType:Se.nodeType||st.nodeType||"cache.t3.micro",engineVersion:Se.engineVersion||"7.1",port:Se.port||6379,numCacheClusters:Se.numCacheNodes||2,automaticFailover:Se.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:Se.snapshotRetentionLimit||7,snapshotWindow:Se.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(It,kt),ie&&wt)this.builder.addResource(wt,ie);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[It,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[It,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(Rt==="memcached"){this.generateNetworkInfrastructure(l,S);let Se=st.elasticache||{},{cluster:kt,subnetGroup:ie,logicalId:It,subnetGroupId:wt}=eo.createMemcached({slug:l,environment:S,nodeType:Se.nodeType||st.nodeType||"cache.t3.micro",engineVersion:Se.engineVersion||"1.6.22",numCacheNodes:Se.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(It,kt),ie&&wt)this.builder.addResource(wt,ie);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[It,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let cr=this.mergedConfig.infrastructure?.email;if(cr){let Rt=cr.domain||this.mergedConfig.infrastructure?.dns?.domain;if(Rt){let{emailIdentity:Se,logicalId:kt}=m.verifyDomain({domain:Rt,slug:l,environment:S,enableDkim:cr.enableDkim!==!1,dkimKeyLength:cr.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(kt,Se),cr.configurationSet!==!1){let{configurationSet:wt,logicalId:Xt}=m.createConfigurationSet({slug:l,environment:S});this.builder.addResource(Xt,wt)}let ie=cr.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(ie){if(cr.enableDkim!==!1)for(let Ir=1;Ir<=3;Ir++){let tn=`DkimRecord${Ir}${Rt.replace(/\./g,"")}`;this.builder.addResource(tn,{Type:"AWS::Route53::RecordSet",DependsOn:[kt],Properties:{HostedZoneId:ie,Name:{"Fn::GetAtt":[kt,`DkimDNSTokenName${Ir}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[kt,`DkimDNSTokenValue${Ir}`]}]}})}let{record:wt,logicalId:Xt}=m.createSpfRecord(Rt,ie);this.builder.addResource(Xt,wt);let{record:ar,logicalId:dr}=m.createDmarcRecord(Rt,ie,{policy:"none",reportingEmail:cr.dmarcReportingEmail||`dmarc-reports@${Rt}`});this.builder.addResource(dr,ar)}this.builder.addOutput("EmailDomain",{Value:Rt,Description:"SES verified email domain"});let It=cr.server;if(It?.enabled&&ie){let wt=this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1",Xt=`${l}-${S}-email`,{role:ar,policy:dr,roleLogicalId:Ir,policyLogicalId:tn}=m.createEmailLambdaRole({slug:l,environment:S,s3BucketArn:`arn:aws:s3:::${Xt}`,sesIdentityArn:`arn:aws:ses:${wt}:*:identity/${Rt}`});this.builder.addResource(Ir,ar),this.builder.addResource(tn,dr);let{function:yr,permission:Cn,logicalId:Pn,permissionLogicalId:Nn}=m.createInboundEmailLambda({slug:l,environment:S,roleArn:{"Fn::GetAtt":[Ir,"Arn"]},s3BucketName:Xt,organizedPrefix:"mailboxes/"});this.builder.addResource(Pn,yr),this.builder.addResource(Nn,Cn);let Hi=m.createInboundEmailSetup({slug:l,environment:S,domain:Rt,s3BucketName:Xt,s3KeyPrefix:"inbox/",region:wt,hostedZoneId:ie,lambdaFunctionArn:{"Fn::GetAtt":[Pn,"Arn"]}});for(let[Zi,Mn]of Object.entries(Hi.resources)){if(Mn.Type==="AWS::SES::ReceiptRule")Mn.DependsOn=[Nn,Pn];this.builder.addResource(Zi,Mn)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:Pn},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:Xt,Description:"S3 bucket for email storage"});let Fn=this.serverEipLogicalIds.get("app");if(Fn&&ie){let Mn=`${It?.subdomain||"mail"}.${Rt}`,zn=Mn.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${zn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:ie,Name:Mn,Type:"A",TTL:"300",ResourceRecords:[{Ref:Fn}]}})}this.builder.addOutput("MailHost",{Value:`mail.${Rt}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let lr=this.mergedConfig.infrastructure?.search;if(lr){let Rt=lr.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(Rt)this.generateNetworkInfrastructure(l,S);let{domain:Se,logicalId:kt}=Qt.createDomain({slug:l,environment:S,engineVersion:lr.engineVersion||"OpenSearch_2.11",instanceType:lr.instanceType||"t3.small.search",instanceCount:lr.instanceCount||1,volumeSize:lr.volumeSize||10,volumeType:lr.volumeType||"gp3",dedicatedMaster:lr.dedicatedMaster||!1,dedicatedMasterType:lr.dedicatedMasterType,dedicatedMasterCount:lr.dedicatedMasterCount||3,multiAz:lr.multiAz||!1,encryption:lr.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:lr.advancedSecurity,autoTune:lr.autoTune!==!1,vpc:Rt});this.builder.addResource(kt,Se),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[kt,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[kt,"Arn"]},Description:"OpenSearch domain ARN"})}let fr=this.mergedConfig.infrastructure?.fileSystem;if(fr&&Object.keys(fr).length>0){this.generateNetworkInfrastructure(l,S);for(let[Rt,Se]of Object.entries(fr)){let{fileSystem:kt,logicalId:ie}=Ge.createFileSystem({slug:`${l}-${Rt}`,environment:S,encrypted:Se.encrypted!==!1,performanceMode:Se.performanceMode||"generalPurpose",throughputMode:Se.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(ie,kt);let{securityGroup:It,logicalId:wt}=Ge.createEfsSecurityGroup({slug:`${l}-${Rt}`,environment:S,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(wt,It);let{mountTargets:Xt,logicalIds:ar}=Ge.createMultiAzMountTargets(ie,{slug:`${l}-${Rt}`,environment:S,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:wt}});for(let dr=0;dr<Xt.length;dr++)this.builder.addResource(ar[dr],Xt[dr]);this.builder.addOutput(`${Rt}FileSystemId`,{Value:{Ref:ie},Description:`EFS file system ID for ${Rt}`})}}let Dt=this.mergedConfig.infrastructure?.ai;if(Dt){let Rt=Dt.service||"ecs",Se=Dt.models||["*"],kt=Dt.allowStreaming!==!1,ie;if(Rt==="ecs")ie=Te.enableBedrockForEcs({slug:l,environment:S,models:Se,allowStreaming:kt});else if(Rt==="ec2")ie=Te.enableBedrockForEc2({slug:l,environment:S,models:Se,allowStreaming:kt});else if(Rt==="lambda")ie=Te.enableBedrockForLambda({slug:l,environment:S,models:Se,allowStreaming:kt});else ie=Te.createBedrockRole(Rt,{slug:l,environment:S,models:Se,allowStreaming:kt});if(this.builder.addResource(ie.logicalId,ie.role),Dt.allowAsync){let{policy:It,logicalId:wt}=Te.createBedrockPolicy({slug:l,environment:S,models:Se,allowStreaming:kt,allowAsync:!0});this.builder.addResource(wt,It)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[ie.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(l,S){let P=this.mergedConfig.infrastructure?.realtime;if(!P)return;let E=P.name||`${l}-${S}-realtime`,v=P.scaling||{},it=P.storage||{type:"dynamodb"},Pe=v.handlerMemory||256,Ie=v.handlerTimeout||30,rt=`${l}${S}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),Pt=`${l}${S}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(it.type==="dynamodb"){let ar=it.dynamodb||{},dr=ar.billingMode||"PAY_PER_REQUEST";this.builder.addResource(rt,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${S}-realtime-connections`,BillingMode:dr,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"},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ar.readCapacity||5,WriteCapacityUnits:ar.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ar.readCapacity||5,WriteCapacityUnits:ar.writeCapacity||5}},...ar.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${l}-${S}-realtime-connections`},{Key:"Environment",Value:S}]}}),this.builder.addResource(Pt,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${S}-realtime-channels`,BillingMode:dr,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"},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ar.readCapacity||5,WriteCapacityUnits:ar.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ar.readCapacity||5,WriteCapacityUnits:ar.writeCapacity||5}},Tags:[{Key:"Name",Value:`${l}-${S}-realtime-channels`},{Key:"Environment",Value:S}]}})}let st=`${l}${S}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(st,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${S}-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":[rt,"Arn"]},{"Fn::Sub":`\${${rt}.Arn}/index/*`},{"Fn::GetAtt":[Pt,"Arn"]},{"Fn::Sub":`\${${Pt}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let cr=`${l}${S}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),lr=`${l}${S}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),fr=`${l}${S}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(cr,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[st,"Arn"]},MemorySize:Pe,Timeout:Ie,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:rt},CHANNELS_TABLE:{Ref:Pt},ENVIRONMENT:S}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[st,rt]}),this.builder.addResource(lr,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[st,"Arn"]},MemorySize:Pe,Timeout:Ie,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:rt},CHANNELS_TABLE:{Ref:Pt},ENVIRONMENT:S}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[st,rt,Pt]}),this.builder.addResource(fr,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[st,"Arn"]},MemorySize:Pe,Timeout:Ie,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:rt},CHANNELS_TABLE:{Ref:Pt},ENVIRONMENT:S}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[st,rt,Pt]});let Dt=`${l}${S}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Dt,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:E,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:E,Environment:S}}});let Rt=`${cr}Permission`,Se=`${lr}Permission`,kt=`${fr}Permission`;this.builder.addResource(Rt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:cr},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Dt}}/*/$connect`}}}),this.builder.addResource(Se,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:lr},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Dt}}/*/$disconnect`}}}),this.builder.addResource(kt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:fr},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Dt}}/*/$default`}}});let ie=`${Dt}ConnectInteg`,It=`${Dt}DisconnectInteg`,wt=`${Dt}MessageInteg`;this.builder.addResource(ie,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Dt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${cr}.Arn}/invocations`}}}),this.builder.addResource(It,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Dt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${lr}.Arn}/invocations`}}}),this.builder.addResource(wt,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Dt},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${fr}.Arn}/invocations`}}}),this.builder.addResource(`${Dt}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Dt},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${ie}}`}}}),this.builder.addResource(`${Dt}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Dt},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${It}}`}}}),this.builder.addResource(`${Dt}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Dt},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${wt}}`}}});let Xt=`${Dt}Stage`;if(this.builder.addResource(Xt,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Dt},StageName:S,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:v.messagesPerSecond||1000,ThrottlingRateLimit:v.messagesPerSecond||1000}}}),P.monitoring?.enabled){let ar=P.monitoring,dr=ar.notificationTopicArn;if(!dr&&ar.notificationEmails?.length){let Ir=`${Dt}AlarmTopic`;this.builder.addResource(Ir,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),ar.notificationEmails.forEach((tn,yr)=>{this.builder.addResource(`${Ir}Sub${yr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Ir},Protocol:"email",Endpoint:tn}})}),dr={Ref:Ir}}if(ar.connectionThreshold)this.builder.addResource(`${Dt}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${ar.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:ar.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Dt}}],...dr&&{AlarmActions:[dr]}}});if(ar.errorThreshold)this.builder.addResource(`${Dt}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${ar.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:ar.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Dt}}],...dr&&{AlarmActions:[dr]}}})}this.builder.addOutput(`${Dt}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${Dt}}.execute-api.\${AWS::Region}.amazonaws.com/${S}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${Dt}Id`,{Description:"WebSocket API ID",Value:{Ref:Dt},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,S){let
|
|
173
|
+
`.trim()}generateRealtimeServerResources(l,S){let P=this.mergedConfig.infrastructure?.realtime;if(!P)return;let E=P.server||{},v=E.port||6001,it=E.instances||1,Pe=`${l}${S}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pe,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${l} realtime WebSocket server`,GroupName:`${l}-${S}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:v,ToPort:v,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}-${S}-realtime-sg`},{Key:"Environment",Value:S}]}});let Ie=`${l}${S}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),rt=`${l}${S}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),Pt=`${l}${S}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${S}-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(rt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${l}-${S}-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:"*"},...E.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let st=[{Name:"BROADCAST_HOST",Value:E.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(v)},{Name:"NODE_ENV",Value:S==="production"?"production":"development"}];if(E.redis?.enabled){if(E.redis.useElastiCache)st.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),st.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else st.push({Name:"REDIS_HOST",Value:E.redis.host||"localhost"}),st.push({Name:"REDIS_PORT",Value:String(E.redis.port||6379)});if(E.redis.keyPrefix)st.push({Name:"REDIS_KEY_PREFIX",Value:E.redis.keyPrefix})}this.builder.addResource(Ie,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${S}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[Pt,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[rt,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${l}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:v,Protocol:"tcp"}],Environment:st,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${l}-${S}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${v}${E.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${l}-${S}-realtime`},{Key:"Environment",Value:S}]},DependsOn:[Pt,rt]});let cr=`${l}${S}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(cr,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${l}-${S}-realtime`,RetentionInDays:30}});let lr=`${l}${S}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(lr,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:Ie},DesiredCount:it,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Pe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${l}-${S}-realtime`},{Key:"Environment",Value:S}]},DependsOn:[Ie,Pe,cr]}),E.autoScaling){let fr=E.autoScaling,Dt=`${l}${S}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Dt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:fr.max||10,MinCapacity:fr.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${l}-${S}-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:lr}),fr.targetCPU)this.builder.addResource(`${l}${S}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${S}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Dt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:fr.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(P.monitoring?.enabled){let fr=P.monitoring,Dt=fr.notificationTopicArn;if(!Dt&&fr.notificationEmails?.length){let Rt=`${l}${S}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Rt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),fr.notificationEmails.forEach((Se,kt)=>{this.builder.addResource(`${Rt}Sub${kt}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Rt},Protocol:"email",Endpoint:Se}})}),Dt={Ref:Rt}}this.builder.addResource(`${l}${S}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-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}-${S}-realtime`}],...Dt&&{AlarmActions:[Dt]}},DependsOn:lr}),this.builder.addResource(`${l}${S}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-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}-${S}-realtime`}],...Dt&&{AlarmActions:[Dt]}},DependsOn:lr})}this.builder.addOutput(`${l}${S}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${l}-${S}-realtime.\${AWS::Region}.elb.amazonaws.com:${v}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let l=this.mergedConfig.infrastructure?.realtime;if(!l||l.mode!=="server")return"";let S=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 @@ ${S.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 Hl(l){let S=[],P=[];if(!l.AWSTemplateFormatVersion)S.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(l.AWSTemplateFormatVersion!=="2010-09-09")P.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!l.Resources||Object.keys(l.Resources).length===0)S.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[E,v]of Object.entries(l.Resources))Gl(E,v,S,P);if(l.Resources){let E=jl(l.Resources);if(E.length>0)S.push({path:"Resources",message:`Circular dependencies detected: ${E.join(" -> ")}`,severity:"error"})}if(l.Parameters)for(let[E,v]of Object.entries(l.Parameters))zl(E,v,S,P);if(l.Outputs)for(let[E,v]of Object.entries(l.Outputs))Ul(E,v,S,P);return{valid:S.length===0,errors:S,warnings:P}}function Gl(l,S,P,E){if(!S.Type)P.push({path:`Resources.${l}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(l))E.push({path:`Resources.${l}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(S.Type&&!S.Type.startsWith("AWS::")&&!S.Type.startsWith("Custom::"))P.push({path:`Resources.${l}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(S.Properties){for(let[v,it]of Object.entries(S.Properties))if(it===void 0||it===null)E.push({path:`Resources.${l}.Properties.${v}`,message:"Property has undefined or null value",severity:"warning"})}if(S.DependsOn){if(typeof S.DependsOn==="string"){if(S.DependsOn===l)P.push({path:`Resources.${l}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(S.DependsOn)){if(S.DependsOn.includes(l))P.push({path:`Resources.${l}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function zl(l,S,P,E){if(!S.Type)P.push({path:`Parameters.${l}.Type`,message:"Parameter Type is required",severity:"error"});let v=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(S.Type&&!v.includes(S.Type)&&!S.Type.startsWith("AWS::"))E.push({path:`Parameters.${l}.Type`,message:`Uncommon parameter type: ${S.Type}`,severity:"warning"});if(S.NoEcho&&S.Default)E.push({path:`Parameters.${l}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function Ul(l,S,P,E){if(!S.Value)P.push({path:`Outputs.${l}.Value`,message:"Output Value is required",severity:"error"})}function jl(l){let S={};for(let[Pe,Ie]of Object.entries(l)){if(S[Pe]=[],Ie.DependsOn){if(typeof Ie.DependsOn==="string")S[Pe].push(Ie.DependsOn);else if(Array.isArray(Ie.DependsOn))S[Pe].push(...Ie.DependsOn)}let rt=Ya(Ie);S[Pe].push(...rt)}let P=new Set,E=new Set,v=[];function it(Pe,Ie){P.add(Pe),E.add(Pe),Ie.push(Pe);let rt=S[Pe]||[];for(let Pt of rt)if(!P.has(Pt)){if(it(Pt,Ie))return!0}else if(E.has(Pt)){let st=Ie.indexOf(Pt);return v.push(...Ie.slice(st),Pt),!0}return Ie.pop(),E.delete(Pe),!1}for(let Pe of Object.keys(S))if(!P.has(Pe)){if(it(Pe,[]))return v}return[]}function Ya(l,S=[]){if(typeof l!=="object"||l===null)return S;if(Array.isArray(l)){for(let P of l)Ya(P,S);return S}if(l.Ref&&typeof l.Ref==="string"&&!l.Ref.startsWith("AWS::"))S.push(l.Ref);if(l["Fn::GetAtt"]){let P=l["Fn::GetAtt"];if(Array.isArray(P)&&P.length>0)S.push(P[0])}for(let P of Object.values(l))Ya(P,S);return S}function ql(l){let S=[],P=[],E=new TextEncoder().encode(l).length,v=51200,it=460800;if(E>51200)if(E>460800)S.push({path:"template",message:`Template size (${E} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else P.push({path:"template",message:`Template size (${E} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:S.length===0,errors:S,warnings:P}}function Md(l){let S=[],P=[],E=l.Resources?Object.keys(l.Resources).length:0,v=l.Parameters?Object.keys(l.Parameters).length:0,it=l.Outputs?Object.keys(l.Outputs).length:0;if(E>500)S.push({path:"Resources",message:`Template has ${E} resources, exceeding the limit of 500`,severity:"error"});else if(E>200)P.push({path:"Resources",message:`Template has ${E} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(v>200)S.push({path:"Parameters",message:`Template has ${v} parameters, exceeding the limit of 200`,severity:"error"});if(it>200)S.push({path:"Outputs",message:`Template has ${it} outputs, exceeding the limit of 200`,severity:"error"});return{valid:S.length===0,errors:S,warnings:P}}function Hm(l){let{domains:S,email:P,staging:E=!1,challengeType:v="http-01",certPath:it="/etc/letsencrypt/live",autoRenew:Pe=!0}=l,Ie=S[0],rt=S.map((st)=>`-d ${st}`).join(" "),Pt=E?"--staging":"";if(v==="http-01")return tu({domains:S,email:P,staging:E,certPath:it,autoRenew:Pe,domainFlags:rt,stagingFlag:Pt,primaryDomain:Ie});else{let st=l.dnsProvider?.provider||(l.hostedZoneId?"route53":void 0);return ru({domains:S,email:P,staging:E,certPath:it,autoRenew:Pe,domainFlags:rt,stagingFlag:Pt,primaryDomain:Ie,hostedZoneId:l.hostedZoneId,dnsProvider:l.dnsProvider,dnsProviderType:st})}}function tu(l){let{email:S,certPath:P,autoRenew:E,domainFlags:v,stagingFlag:it,primaryDomain:Pe}=l;return`
|
|
223
223
|
# ==========================================
|
|
224
224
|
# Let's Encrypt Certificate Setup (HTTP-01)
|
|
225
225
|
# ==========================================
|
|
@@ -240,24 +240,24 @@ certbot certonly \\
|
|
|
240
240
|
${v}
|
|
241
241
|
|
|
242
242
|
# Check if certificate was obtained
|
|
243
|
-
if [ -f "${
|
|
243
|
+
if [ -f "${P}/${Pe}/fullchain.pem" ]; then
|
|
244
244
|
echo "Certificate obtained successfully!"
|
|
245
245
|
|
|
246
246
|
# Create symlinks for easier access
|
|
247
247
|
mkdir -p /etc/ssl/stacks
|
|
248
|
-
ln -sf ${
|
|
249
|
-
ln -sf ${
|
|
250
|
-
ln -sf ${
|
|
251
|
-
ln -sf ${
|
|
248
|
+
ln -sf ${P}/${Pe}/fullchain.pem /etc/ssl/stacks/fullchain.pem
|
|
249
|
+
ln -sf ${P}/${Pe}/privkey.pem /etc/ssl/stacks/privkey.pem
|
|
250
|
+
ln -sf ${P}/${Pe}/cert.pem /etc/ssl/stacks/cert.pem
|
|
251
|
+
ln -sf ${P}/${Pe}/chain.pem /etc/ssl/stacks/chain.pem
|
|
252
252
|
else
|
|
253
253
|
echo "Failed to obtain certificate!"
|
|
254
254
|
fi
|
|
255
255
|
|
|
256
|
-
${
|
|
256
|
+
${E?Xa(Pe):"# Auto-renewal disabled"}
|
|
257
257
|
|
|
258
258
|
# Restart the application
|
|
259
259
|
systemctl start stacks
|
|
260
|
-
`}function
|
|
260
|
+
`}function ru(l){let{email:S,certPath:P,autoRenew:E,domainFlags:v,stagingFlag:it,primaryDomain:Pe,hostedZoneId:Ie,dnsProvider:rt,dnsProviderType:Pt}=l;if(Pt==="route53"||Ie){if(!Ie)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
|
# ==========================================
|
|
@@ -275,21 +275,21 @@ certbot certonly \\
|
|
|
275
275
|
${v}
|
|
276
276
|
|
|
277
277
|
# Check if certificate was obtained
|
|
278
|
-
if [ -f "${
|
|
278
|
+
if [ -f "${P}/${Pe}/fullchain.pem" ]; then
|
|
279
279
|
echo "Certificate obtained successfully!"
|
|
280
280
|
|
|
281
281
|
# Create symlinks for easier access
|
|
282
282
|
mkdir -p /etc/ssl/stacks
|
|
283
|
-
ln -sf ${
|
|
284
|
-
ln -sf ${
|
|
285
|
-
ln -sf ${
|
|
286
|
-
ln -sf ${
|
|
283
|
+
ln -sf ${P}/${Pe}/fullchain.pem /etc/ssl/stacks/fullchain.pem
|
|
284
|
+
ln -sf ${P}/${Pe}/privkey.pem /etc/ssl/stacks/privkey.pem
|
|
285
|
+
ln -sf ${P}/${Pe}/cert.pem /etc/ssl/stacks/cert.pem
|
|
286
|
+
ln -sf ${P}/${Pe}/chain.pem /etc/ssl/stacks/chain.pem
|
|
287
287
|
else
|
|
288
288
|
echo "Failed to obtain certificate!"
|
|
289
289
|
fi
|
|
290
290
|
|
|
291
|
-
${
|
|
292
|
-
`}if(!rt)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let st=rt.provider.toUpperCase(),cr=
|
|
291
|
+
${E?Xa(Pe):"# Auto-renewal disabled"}
|
|
292
|
+
`}if(!rt)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let st=rt.provider.toUpperCase(),cr=iu(rt);return`
|
|
293
293
|
# ==========================================
|
|
294
294
|
# Let's Encrypt Certificate Setup (DNS-01 via ${st})
|
|
295
295
|
# ==========================================
|
|
@@ -312,7 +312,7 @@ DOMAIN="$CERTBOT_DOMAIN"
|
|
|
312
312
|
VALIDATION="$CERTBOT_VALIDATION"
|
|
313
313
|
RECORD_NAME="_acme-challenge.$DOMAIN"
|
|
314
314
|
|
|
315
|
-
${
|
|
315
|
+
${ou(rt)}
|
|
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
|
+
${su(rt)}
|
|
335
335
|
CLEANUPHOOK
|
|
336
336
|
|
|
337
337
|
chmod +x /etc/letsencrypt/hooks/cleanup-hook.sh
|
|
@@ -349,21 +349,21 @@ certbot certonly \\
|
|
|
349
349
|
${v}
|
|
350
350
|
|
|
351
351
|
# Check if certificate was obtained
|
|
352
|
-
if [ -f "${
|
|
352
|
+
if [ -f "${P}/${Pe}/fullchain.pem" ]; then
|
|
353
353
|
echo "Certificate obtained successfully!"
|
|
354
354
|
|
|
355
355
|
# Create symlinks for easier access
|
|
356
356
|
mkdir -p /etc/ssl/stacks
|
|
357
|
-
ln -sf ${
|
|
358
|
-
ln -sf ${
|
|
359
|
-
ln -sf ${
|
|
360
|
-
ln -sf ${
|
|
357
|
+
ln -sf ${P}/${Pe}/fullchain.pem /etc/ssl/stacks/fullchain.pem
|
|
358
|
+
ln -sf ${P}/${Pe}/privkey.pem /etc/ssl/stacks/privkey.pem
|
|
359
|
+
ln -sf ${P}/${Pe}/cert.pem /etc/ssl/stacks/cert.pem
|
|
360
|
+
ln -sf ${P}/${Pe}/chain.pem /etc/ssl/stacks/chain.pem
|
|
361
361
|
else
|
|
362
362
|
echo "Failed to obtain certificate!"
|
|
363
363
|
fi
|
|
364
364
|
|
|
365
|
-
${
|
|
366
|
-
`}function
|
|
365
|
+
${E?Xa(Pe):"# Auto-renewal disabled"}
|
|
366
|
+
`}function iu(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 ou(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 su(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 Xa(l){return`
|
|
474
474
|
# ==========================================
|
|
475
475
|
# Certificate Auto-Renewal Setup
|
|
476
476
|
# ==========================================
|
|
@@ -515,13 +515,13 @@ 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 Gm(l){let{httpPort:S=80,httpsPort:P=443,certPath:E="/etc/ssl/stacks",redirectHttp:v=!0}=l;return`
|
|
519
519
|
// HTTPS Server with Let's Encrypt certificates
|
|
520
520
|
import { readFileSync, existsSync } from 'node:fs'
|
|
521
521
|
|
|
522
|
-
const CERT_PATH = '${
|
|
522
|
+
const CERT_PATH = '${E}'
|
|
523
523
|
const HTTP_PORT = ${S}
|
|
524
|
-
const HTTPS_PORT = ${
|
|
524
|
+
const HTTPS_PORT = ${P}
|
|
525
525
|
|
|
526
526
|
// Check if certificates exist
|
|
527
527
|
const hasCerts = existsSync(\`\${CERT_PATH}/fullchain.pem\`) && existsSync(\`\${CERT_PATH}/privkey.pem\`)
|
|
@@ -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((it)=>!it.startsWith("-----")).join(""),S=Buffer.from(l,"base64"),b=S.length-65,P=S.subarray(b+1,b+33),v=S.subarray(b+33,b+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(P),y:this.base64UrlEncode(v)}}getJwkThumbprint(){let l=this.getJwk(),S=JSON.stringify({crv:l.crv,kty:l.kty,x:l.x,y:l.y}),b=nc("sha256").update(S).digest();return this.base64UrlEncode(b)}base64UrlEncode(l){return(typeof l==="string"?Buffer.from(l):l).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(l,S){let b=await this.getNonce(),P=this.getJwk(),v={alg:"ES256",nonce:b,url:l};if(this.accountUrl)v.kid=this.accountUrl;else v.jwk=P;let it=this.base64UrlEncode(JSON.stringify(v)),Pe=S===""?"":this.base64UrlEncode(JSON.stringify(S)),Ie=`${it}.${Pe}`,rt=mu("SHA256");rt.update(Ie);let Rt=rt.sign(this.accountKey),st=Rt.subarray(4,4+Rt[3]),cr=4+Rt[3]+2,lr=Rt.subarray(cr,cr+Rt[cr-1]),fr=Buffer.alloc(32),It=Buffer.alloc(32);st.copy(fr,32-st.length),lr.copy(It,32-lr.length);let Pt=Buffer.concat([fr,It]);return JSON.stringify({protected:it,payload:Pe,signature:this.base64UrlEncode(Pt)})}async acmeRequest(l,S){let b=await this.signPayload(l,S),P=await fetch(l,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:b}),v=P.headers.get("replay-nonce");if(v)this.nonce=v;let it,Pe=P.headers.get("content-type");if(Pe?.includes("application/json")||Pe?.includes("application/problem+json"))it=await P.json();else it=await P.text();if(!P.ok)throw Error(`ACME request failed: ${JSON.stringify(it)}`);return{body:it,headers:P.headers}}async registerAccount(){let l=await this.getDirectory(),{body:S,headers:b}=await this.acmeRequest(l.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),P=b.get("location");if(!P)throw Error("No account URL returned");return this.accountUrl=P,P}async createOrder(l){if(!this.accountUrl)await this.registerAccount();let S=await this.getDirectory(),{body:b,headers:P}=await this.acmeRequest(S.newOrder,{identifiers:l.map((it)=>({type:"dns",value:it}))}),v=P.get("location");if(!v)throw Error("No order URL returned");return{orderUrl:v,authorizations:b.authorizations,finalize:b.finalize}}async getAuthorization(l){let{body:S}=await this.acmeRequest(l,""),b=S.identifier.value,P=this.getJwkThumbprint(),v=S.challenges.filter((it)=>it.type==="http-01"||it.type==="dns-01").map((it)=>{let Pe=`${it.token}.${P}`;if(it.type==="http-01")return{type:"http-01",token:it.token,keyAuthorization:Pe,identifier:`/.well-known/acme-challenge/${it.token}`};else{let Ie=this.base64UrlEncode(nc("sha256").update(Pe).digest());return{type:"dns-01",token:it.token,keyAuthorization:Pe,identifier:`_acme-challenge.${b}`,dnsValue:Ie}}});return{domain:b,challenges:v}}async respondToChallenge(l){await this.acmeRequest(l,{})}async waitForAuthorization(l,S=30){for(let b=0;b<S;b++){let{body:P}=await this.acmeRequest(l,"");if(P.status==="valid")return;if(P.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(P)}`);await new Promise((v)=>setTimeout(v,2000))}throw Error("Authorization timed out")}generateCsr(l){let{privateKey:S}=oc("rsa",{modulusLength:2048}),b=S.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(l,S),privateKey:b}}createSimpleCsr(l,S){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(l,S){let{csr:b,privateKey:P}=this.generateCsr(S),{body:v}=await this.acmeRequest(l,{csr:this.base64UrlEncode(Buffer.from(b,"base64"))}),it=v.certificate;if(!it)throw Error("Certificate not immediately available - polling not implemented");let Ie=await(await fetch(it)).text(),rt=Ie.split(/(?=-----BEGIN CERTIFICATE-----)/g),Rt=rt[0],st=rt.slice(1).join("");return{certificate:Rt,privateKey:P,chain:st,fullchain:Ie,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var Tn=(l)=>l===void 0?void 0:l?"on":"off";function Ja(l){let S={ssl:l.ssl,always_use_https:Tn(l.alwaysUseHttps),automatic_https_rewrites:Tn(l.automaticHttpsRewrites),min_tls_version:l.minTlsVersion,tls_1_3:Tn(l.tls13),brotli:Tn(l.brotli),http3:Tn(l.http3),"0rtt":Tn(l.zeroRtt),early_hints:Tn(l.earlyHints),browser_cache_ttl:l.browserCacheTtl,always_online:Tn(l.alwaysOnline),websockets:Tn(l.websockets),email_obfuscation:Tn(l.emailObfuscation)};if(l.hsts)S.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 b of Object.keys(S))if(S[b]===void 0)delete S[b];return{...S,...l.raw??{}}}var Ji={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 gu}from"node:tls";async function Ya(l){let{address:S,serverName:b,port:P=443,timeoutMs:v=5000}=l;return new Promise((it)=>{let Pe=!1,Ie=(Rt)=>{if(Pe)return;Pe=!0;try{rt.destroy()}catch{}it(Rt)},rt=gu({host:S,port:P,servername:b,rejectUnauthorized:!1,timeout:v});rt.once("secureConnect",()=>{if(rt.authorized){Ie({reachable:!0,trusted:!0});return}Ie({reachable:!0,trusted:!1,reason:rt.authorizationError?String(rt.authorizationError):"origin certificate is not trusted for this hostname"})}),rt.once("timeout",()=>{Ie({reachable:!1,trusted:!1,reason:`no TLS handshake within ${v}ms`})}),rt.once("error",(Rt)=>{Ie({reachable:!1,trusted:!1,reason:Rt.message})})})}function hu(l,S){let b=S.replace(/\.$/,"").toLowerCase();return l.some((P)=>{let v=P.replace(/\.$/,"").toLowerCase();if(v===b)return!0;if(!v.startsWith("*."))return!1;let it=v.slice(2);if(!b.endsWith(`.${it}`))return!1;return!b.slice(0,b.length-it.length-1).includes(".")})}async function yu(l){let{provider:S,zone:b,hosts:P,ipv4:v,ipv6:it,proxied:Pe=!0,settings:Ie=Ji,cache:rt,originGuard:Rt,purge:st=!0,ttl:cr=300,skipOriginProbe:lr=!1,skipEdgeCertificateCheck:fr=!1}=l,It={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(P.length===0)return It;let Pt=[],ye=Pe&&!fr?await S.listEdgeCertificateHosts(b):null;for(let ie of P){let Dt=Pe;if(Dt&&ye&&!hu(ye,ie)){Dt=!1;let Xt=ye.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${ye.join(", ")})`;It.deferredProxy.push({host:ie,reason:Xt}),It.warnings.push(`${ie}: publishing DNS-only — ${Xt}. 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(Dt&&!lr){let Xt=await Ya({address:v,serverName:ie});if(!Xt.trusted){Dt=!1;let ar=Xt.reason||"origin is not serving a trusted certificate";It.deferredProxy.push({host:ie,reason:ar}),It.warnings.push(`${ie}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${ar}). 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(Dt)Pt.push(ie);let wt=[{type:"A",content:v}];if(it&&In(ie))wt.push({type:"AAAA",content:it});for(let{type:Xt,content:ar}of wt){let dr=await S.upsertRecord(b,{name:ie,type:Xt,content:ar,ttl:cr,proxied:Dt});if(dr.success)It.records.push({host:ie,type:Xt,content:ar,proxied:Dt});else It.warnings.push(`${ie} ${Xt} → ${ar} failed: ${dr.message||"unknown provider error"}`)}}if(Pt.length===0){if(Pe)It.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return It}try{let ie=Ja(Ie),Dt=await S.applyZoneSettings(b,ie);It.settingsChanged=Dt.changed;for(let wt of Dt.failed)It.warnings.push(`zone setting '${wt.id}' could not be applied: ${wt.error}`)}catch(ie){It.warnings.push(`zone settings could not be read: ${ie instanceof Error?ie.message:String(ie)}`)}let kt=Ma(Pt,rt);if(kt.length>0){let ie=await S.putManagedPhaseRules(b,"http_request_cache_settings",kt);if(ie.success)It.cacheRules=kt.length;else It.warnings.push(`cache rules could not be written: ${ie.message}`)}if(Rt){let ie=Fa(Pt,Rt.header,Rt.value);if(ie.length>0){let Dt=await S.putManagedPhaseRules(b,"http_request_late_transform",ie);if(Dt.success)It.originGuard=!0;else It.warnings.push(`origin guard header could not be written: ${Dt.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(st){if(It.purged=await S.purgeCache(b,{hosts:Pt}),!It.purged)It.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return It}var Cu=(l)=>process.env[l];function sc(l,S){let b=l.replace(/\.$/,"").toLowerCase();if(S){let P=S.replace(/\.$/,"").toLowerCase();if(b===P||b.endsWith(`.${P}`))return P}return b.split(".").slice(-2).join(".")}function Su(l,S={}){let b=S.env??Cu,P=l.infrastructure?.compute?.proxy?.cdn,v=[];if(!P||P.provider!=="cloudflare")return{plan:null,errors:v};if(P.originDomain)v.push(`compute.proxy.cdn.originDomain (${P.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 it=b("CLOUDFLARE_API_TOKEN");if(!it)return v.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:v};let Pe=l.sites??{},Ie=P.frontedHosts?.length?[...new Set(P.frontedHosts.map((lr)=>lr.toLowerCase()))]:vn(Pe,{autoWww:l.infrastructure?.compute?.proxy?.autoWww!==!1});if(Ie.length===0)return v.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:v};let rt=l.infrastructure?.dns?.domain,Rt=new Set(Ie.map((lr)=>sc(lr,rt)));if(Rt.size>1)return v.push(`Fronted hosts span more than one zone (${[...Rt].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:v};let st=P.cloudflare??{},cr=P.secret?{header:P.secretHeader??"X-Origin-Verify",value:P.secret}:void 0;return{plan:{zone:[...Rt][0],hosts:Ie,apiToken:it,zoneId:st.zoneId??b("CLOUDFLARE_ZONE_ID"),accountId:st.accountId??b("CLOUDFLARE_ACCOUNT_ID"),proxied:st.proxied!==!1,settings:st.settings??Ji,cache:st.cache,originGuard:cr,purge:st.purgeOnDeploy!==!1,skipOriginProbe:st.skipOriginProbe===!0},errors:v}}var Au=26214400;var bu=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class cc{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,S,b){return Oa(l,`/accounts/${this.accountId}${S}`,`Bearer ${this.apiToken}`,b)}async getProject(l){try{return await this.request("GET",`/pages/projects/${l}`)}catch(S){if(S instanceof Error&&/\b8000007\b|not found/i.test(S.message))return null;throw S}}async ensureProject(l,S="main"){let b=await this.getProject(l);if(b)return b;return this.request("POST","/pages/projects",{name:l,production_branch:S})}async uploadToken(l){return(await this.request("GET",`/pages/projects/${l}/upload-token`)).jwt}async missingHashes(l,S){let b=await Oa("POST","/pages/assets/check-missing",`Bearer ${l}`,{hashes:S});return new Set(b)}async upsertHashes(l,S){await Oa("POST","/pages/assets/upsert-hashes",`Bearer ${l}`,{hashes:S})}async uploadBatch(l,S){let b=S.map((P)=>({key:P.hash,value:P.base64,metadata:{contentType:Pu(P.extension)},base64:!0}));await Oa("POST","/pages/assets/upload",`Bearer ${l}`,b)}async createDeployment(l,S,b){let P={};for(let it of S)P[it.path]=it.hash;let v=new FormData;if(v.append("manifest",JSON.stringify(P)),b)v.append("branch",b);return this.request("POST",`/pages/projects/${l}/deployments`,v)}async deployDirectory(l){let S=await dc(l.directory);if(S.length===0)throw Error(`No files to deploy in ${l.directory}`);let b=await this.uploadToken(l.project),P=await this.missingHashes(b,S.map((rt)=>rt.hash)),v=S.filter((rt)=>P.has(rt.hash)),it=[];for(let rt=0;rt<v.length;rt+=100)it.push(v.slice(rt,rt+100));let Pe=0;for(let rt=0;rt<it.length;rt+=4){let Rt=it.slice(rt,rt+4);await Promise.all(Rt.map((st)=>this.uploadBatch(b,st))),Pe+=Rt.reduce((st,cr)=>st+cr.length,0),l.onProgress?.(Pe,v.length)}return await this.upsertHashes(b,S.map((rt)=>rt.hash)),{deployment:await this.createDeployment(l.project,S,l.branch),total:S.length,uploaded:v.length,uploadedBytes:v.reduce((rt,Rt)=>rt+Rt.size,0)}}async listCustomDomains(l){return(await this.request("GET",`/pages/projects/${l}/domains`)).map((b)=>b.name)}async attachCustomDomain(l,S){if((await this.listCustomDomains(l)).includes(S))return!1;return await this.request("POST",`/pages/projects/${l}/domains`,{name:S}),!0}}function Ru(l,S){return{type:"CNAME",name:l,value:S.endsWith(".pages.dev")?S:`${S}.pages.dev`,ttl:1,proxied:!0}}async function lc(l,S){let{blake3:b}=await import("./chunk-pwpd6jt2.js").then((m)=>uh(m.default,1));return(await b(l+S)).slice(0,32)}async function dc(l){let{readdir:S}=await import("node:fs/promises"),{join:b,relative:P,sep:v}=await import("node:path"),it=[];async function Pe(Ie){let rt=await S(Ie,{withFileTypes:!0});for(let Rt of rt){let st=b(Ie,Rt.name);if(Rt.isDirectory()){await Pe(st);continue}if(!Rt.isFile())continue;let cr=`/${P(l,st).split(v).join("/")}`;if(bu.has(cr))continue;let lr=await Bun.file(st).bytes();if(lr.byteLength>26214400)throw Error(`${cr} is ${lr.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let fr=Buffer.from(lr).toString("base64"),It=Rt.name.lastIndexOf("."),Pt=It>0?Rt.name.slice(It+1):"";it.push({path:cr,hash:await lc(fr,Pt),base64:fr,extension:Pt,size:lr.byteLength})}}return await Pe(l),it.sort((Ie,rt)=>Ie.path.localeCompare(rt.path)),it}function Pu(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 Oa(l,S,b,P){let v={Authorization:b},it;if(P instanceof FormData)it=P;else if(P!==void 0)v["Content-Type"]="application/json",it=JSON.stringify(P);let Pe=await fetch(`https://api.cloudflare.com/client/v4${S}`,{method:l,headers:v,body:it}),Ie=await Pe.text(),rt;try{rt=JSON.parse(Ie)}catch{throw Error(`Cloudflare Pages API returned ${Pe.status} with a non-JSON body: ${Ie.slice(0,200)}`)}if(!rt.success){let Rt=(rt.errors??[]).map((st)=>`${st.code}: ${st.message}`).join(", ");throw Error(`Cloudflare Pages API error (${Pe.status}): ${Rt||Ie.slice(0,200)}`)}return rt.result}export{gg as ABTestManager,ae as ACMClient,or as ACMDnsValidator,ac as ACME_DIRECTORIES,Te as AI,jd as API_IDEMPOTENCY_TTL_MS,qd as API_TOKEN_DEFAULT_TTL_MS,Vd as API_TOKEN_MAX_TTL_MS,Bi as API_VERSION,de as AUTHORIZATION_CAPABILITIES,Ud as AUTH_ACTION_TOKEN_TTL_MS,Qd as AUTH_MFA_CHALLENGE_TTL_MS,Hd as AUTH_OIDC_TRANSACTION_TTL_MS,je as AUTH_SESSION_ABSOLUTE_TTL_MS,Fd as AUTH_SESSION_IDLE_TTL_MS,Mf as AWSAPIError,n as AWSClient,h as AWSCloudFormationClient,A as AWSCloudFrontClient,dg as AWSConfigManager,Vy as AWS_PSEUDO_PARAMETERS,we as AWS_REGIONS,fu as AcmeClient,Nr as AlertEvaluator,di as AlertStore,Us as AnomalyConfigStore,hd as ApiGateway,i as ApiServiceError,_a as ApplicationAutoScalingClient,eo as Arn,D as AssetHasher,U as Auth,Ri as AuthenticationStore,mi as AutomationApiService,Di as AutomationIdentityStore,Ho as AwsAuroraDataAdapter,zo as AwsAuroraTransport,ua as AwsDatabaseBackupSource,ur as AwsDriver,Go as AwsElastiCacheDataAdapter,Ko as AwsElastiCacheTransport,um as AwsIamCapabilityScanner,fa as AwsInfrastructureBackupSource,Qo as AwsRdsDataAdapter,jo as AwsRdsTransport,vm as AwsRegionalDriver,ya as AwsSecretsManagerConfigurationBackend,Pp as AwsSpendTransport,Ia as AwsSsmConfigurationBackend,Gi as BackupCoordinator,ag as BackupManager,da as BackupStore,Vg as BatchProcessingManager,ln as BedrockClient,dn as BedrockRuntimeClient,Zd as BitbucketSourceAdapter,pg as BlueGreenManager,Fg as BounceComplaintHandler,Rg as BuildOptimizationManager,Cl as BunDockerRuntime,zl as BunDockerVolumeRuntime,jl as BunFilesystemArchiveRuntime,ve as CDN,ao as CHAIN_HEADER,rs as CLOUDFLARE_MANAGED_RULE_PREFIX,US as COMMON_CROSS_ACCOUNT_ROLES,Fe as CONTROL_PLANE_SCHEMA_VERSION,Ys as Cache,no as CanaryManager,vg as CertificateManager,zh as CloudBlockVolumeDriver,Ss as CloudDriverFactory,Ve as CloudError,$p as CloudFormationBuilder,h as CloudFormationClient,A as CloudFrontClient,lg as CloudTrailManager,me as CloudWatchLogsClient,cc as CloudflarePagesProvider,fe as CloudflareProvider,Yf as CommandHistory,H as Communication,Tr as ComposeApplicationService,Ot as ComposeApplicationStore,Ct as ComprehendClient,o as Compute,Np as ComputeSpendTransport,ro as ConfigurationError,Ca as ConfigurationService,Aa as ConfigurationStore,an as ConnectClient,Vo as ContainerDataAdapter,Dg as ContainerRegistryManager,ha as ControlPlaneBackupSource,sa as ControlPlaneCleanupDriver,ri as ControlPlaneStore,$s as CounterTracker,Gt as CredentialError,tg as CrossRegionReferenceManager,Ef as DASHBOARD_ENTRY,vf as DASHBOARD_PORT_BASE,Tf as DASHBOARD_PORT_SPAN,bf as DASHBOARD_STATE_DIR,ho as DEFAULT_ATTACK_MODE_HOURS,rd as DEFAULT_DDOS_THRESHOLDS,$c as DEFAULT_METER_MAPPINGS,Oc as DEFAULT_PRICE_BOOK,Ci as DEFAULT_RECURSION_LIMITS,bn as DEFAULT_RPX_CERTS_DIR,q as DEFAULT_SERVICE_LIMITS,_p as DEFAULT_STATE_DIR,su as DEFAULT_STATIC_ASSET_EXTENSIONS,af as DEFAULT_TELEMETRY_POLICY,gp as DEFAULT_THRESHOLDS,Hh as DEPLOYMENT_QUEUE_KINDS,oo as DEPTH_HEADER,Dr as DETECTABLE_SIGNALS,fl as DIAGNOSTIC_PRESETS,qg as DLQMonitoringManager,L as DNS,$g as DNSSECManager,Li as DataServiceLifecycle,Uo as DataServiceStore,Ut as Database,Cg as DatabaseUserManager,ee as DebugLogger,yf as DependencyGraph,Q as Deployment,$f as DeploymentError,cg as DisasterRecoveryManager,yn as DnsProviderFactory,zt as DockerDataTransport,_o as DockerDiscoveryAdapter,vr as DockerNamedVolumeDriver,ma as DockerVolumeBackupSource,c as DurableOperationQueue,Ns as DurableQueueWorker,ke as DynamoDBClient,Ar as EC2Client,Be as ECRClient,Xe as ECSClient,rr as EFSClient,Na as ELBv2Client,Wh as ENFORCEMENT_ACTIONS,ai as ENFORCEMENT_DESCRIPTIONS,R as ENFORCEMENT_SEVERITY,Qu as ENVIRONMENT_LABEL,ml as EcsRuntimeAdapter,mo as EdgeRateLimiter,Ze as ElastiCacheClient,m as Email,tA as EmailAdvanced,Ug as EmailAnalyticsManager,mn as EmailClient,rA as EmailHandlers,Hg as EmailTemplateManager,Wo as EncryptedDataSecretStore,Ff as ErrorCodes,er as EventBridgeClient,Cm as EventBridgeJobAdapter,Sa as ExternalConfigurationBackend,Gg as FIFOQueueManager,Cp as FOCUS_VERSION,Gp as FileCache,Ge as FileSystem,pa as FilesystemBackupSource,Xo as FleetService,Jo as FleetStore,e as Fn,el as GiteaSourceAdapter,Xd as GithubSourceAdapter,Yd as GitlabSourceAdapter,rg as GlobalResourceManager,xe as GoDaddyProvider,ug as GuardDutyManager,ot as HOST_SITES_DIR,Hf as HashCache,Zg as HealthCheckManager,Qe as HealthCheckRunner,gr as HetznerClient,Se as HetznerDriver,he as IAMClient,Ga as IPV6_EXCLUDED_HOST_LABELS,wg as ImageScanningManager,Fl as InfrastructureGenerator,vc as InvalidOperationTransitionError,ut as JobLoader,bm as JobProviderReconciler,Fo as JobService,$o as JobStore,Zt as KendraClient,CA as LARAVEL_SERVERLESS_BUILD_STEPS,C as LambdaClient,Bg as LambdaConcurrencyManager,Og as LambdaDLQManager,xg as LambdaDestinationsManager,Ng as LambdaLayersManager,hl as LambdaRuntimeAdapter,_g as LambdaVPCManager,kg as LambdaVersionsManager,tn as LocalEncryptedConfigurationBackend,ga as LogicalDatabaseBackupSource,Ag as LogsManager,aA as MANAGED_NODE_VERSIONS,gc as MANAGEMENT_DASHBOARD_SITE,Mp as MANAGEMENT_DASHBOARD_SITE_PREFIX,Ti as MAX_CONTROL_HOURS,Tc as MAX_CONTROL_PLANE_ERROR_BYTES,cp as MAX_CONTROL_PLANE_JSON_BYTES,_s as METERS,Kh as METER_KEYS,Jh as MICRO_CENTS,mp as MIN_PROJECTION_CONFIDENCE,du as MTA_STS_PORT,ia as MaintenanceService,na as MaintenanceStore,Z as Messaging,fg as MetricsManager,yg as MigrationManager,Kp as MockCloudFormation,Jp as MockDynamoDB,Wp as MockS3,Zs as Monitoring,sg as MultiAccountManager,eg as MultiRegionManager,jf as MultiStepProgress,f as Network,em as NetworkSecurityManager,li as NotificationRouter,ka as OpenSearchClient,at as OptimisticConcurrencyError,og as OrganizationManager,Au as PAGES_MAX_FILE_BYTES,bA as PHP_DEFAULT_EXCLUDES,cA as PHP_LAYER_EXTENSIONS,Uu as PROJECT_LABEL,tt as PROXIABLE_RECORD_TYPES,E as ParameterStore,Sg as PerformanceManager,Y as Permissions,Ba as PersonalizeClient,qe as Phone,nA as PhoneAdvanced,If as PhoneHandlers,Zo as PlacementService,Yo as PlacementStore,un as PollyClient,se as PorkbunProvider,qr as PreDeployScanner,Xp as PreviewEnvironmentManager,Er as PreviewEnvironmentService,Ue as PreviewEnvironmentStore,Yp as PreviewNotificationService,Vf as ProgressBar,mg as ProgressiveDeploymentManager,fo as ProtectionControlStore,_y as Pseudo,M as Queue,ni as QueueCancellationError,jg as QueueManagementManager,By as QueuePresets,Ps as QueueTimeoutError,kd as RATE_LIMIT_KEY_SEPARATOR,j as RDSClient,eA as RECOMMENDED_ACCOUNT_STRUCTURES,FS as RECOMMENDED_SCPS,am as RELEASE_QUEUE_KINDS,Wf as REPL,Xf as REPLCommandBuilder,Jf as REPLContext,Hu as ROLE_LABEL,Gf as RateLimiter,xy as RealtimePresets,bp as RecordingSpendTransport,lo as RecursionGuard,pt as Redirects,ng as RegionPairManager,ta as RegionService,ea as RegionStore,He as Registry,bt as RekognitionClient,gt as ReleaseService,To as ReleaseStore,Em as RemoteBuildService,Ig as ReplicaManager,tm as ResourceManagementManager,X as RetryableOperationError,y as Route53Client,Pa as Route53DomainsClient,z as Route53Provider,Mg as Route53ResolverManager,Lg as Route53RoutingManager,pe as RuntimeOperationService,Lo as RuntimeStreamRegistry,la as S3BackupDestinationAdapter,a as S3Client,G as S3Error,nl as SECRET_PATTERNS,Ip as SENSITIVITY_THRESHOLDS,et as SESClient,F as SMS,Ye as SNSClient,Dp as SPEND_CYCLE_SECONDS,Jc as SPEND_GATE_SETTING,uf as SPEND_LEASE_SETTING,ne as SQSClient,Ce as SSH_BOOTSTRAP_VERSION,Bn as SSH_PREFLIGHT_SCRIPT,be as SSMClient,Op as STATE_DIR_ENV_VAR,Ji as STATIC_SITE_ZONE_SETTINGS,ge as STSClient,pn as SchedulerClient,Qt as Search,Vr as SecretFindingScanner,Ai as Secrets,Eg as SecretsManager,V as SecretsManagerClient,bg as SecretsRotationManager,I as Security,Lr as SecurityHubManager,Gr as SecurityPostureStore,mt as SecurityScannerRunner,Tg as SecurityScanningManager,Qg as SenderReputationManager,Sm as ServerCronJobAdapter,qo as ServerDataAdapter,xs as ServerPathVolumeDriver,Pg as ServiceMeshManager,md as Sftp,Hs as SignalSource,iA as SmsAdvanced,vt as SmsClient,Sf as SmsHandlers,$a as SmsVoiceClient,wo as SourceConnectionStore,Vt as SourceProviderError,Xc as SpendCapError,Pr as SpendGate,wp as SpendLoopLease,zs as SpendNotificationRouter,Rp as SpendRunner,$t as SpendService,si as SpendStore,zf as Spinner,hr as SshDriver,Kr as SshFleetDriver,ig as StackDependencyManager,qy as StacksIntegration,Xg as StaticSiteManager,Ee as Storage,Yg as StorageAdvancedManager,gn as SupportClient,$r as SyntheticsManager,bl as SystemFleetSshTransport,mr as SystemSshTransport,Oo as SystemdDiscoveryAdapter,co as TRACE_HEADER,Kf as TaskList,lt as TelemetryStore,pd as TemplateBuilder,qp as TemplateCache,Et as TextractClient,cn as TranscribeClient,Yt as TranslateClient,Rm as TransportDisasterRecoveryDriver,wm as TransportPlatformMaintenanceDriver,$i as TransportRemoteBuildDriver,Bo as TrivyImageScanner,vo as TsCloudApiError,zd as TsCloudClient,lf as URGENT_SPEND_EVENTS,hp as USER_VISIBLE_ACTIONS,ra as UnavailableRegionalDriver,oe as UnifiedDnsValidator,ws as UnsupportedSchemaVersionError,Qp as ValidationError,tr as VoiceClient,Bs as VolumeService,_t as VolumeStore,Cf as Workflow,hg as XRayManager,mC as abTestManager,Kd as activateImmutableRelease,lu as addDns01ChallengeRecord,Jr as addSiteToCloudConfig,ft as ageSeconds,Fc as aggregateDeltas,sp as allocateSitePorts,Hy as analyzeStackDiff,ci as anomalyOptionsForSignal,Ao as applyControlsToDdos,Ld as applyControlsToRateLimits,as as applyDeclaredZoneSettings,xr as applyMitigationFactor,Eh as applyPlan,us as applyZoneMigration,Sd as artifactKey,Pi as assertReleaseStrategy,of as assertSpendAllows,Dh as attachConflicts,Ph as attachIsViable,Rh as attachPreconditions,cl as attachProvenanceToRelease,xo as attachSbomToRelease,ol as attachVulnerabilitySummary,sm as authEncryptionKeyFile,w as authorizeOrganization,ym as authorizeRuntimePath,hS as autocomplete,cC as awsConfigManager,ql as backupCredentialStatus,oC as backupManager,_I as batch,zC as batchProcessingManager,bo as beginOidcAuthorization,pC as blueGreenManager,QC as bounceComplaintHandler,ct as budgetWindow,wa as buildAndPushServerlessImage,JC as buildBunRuntimeLayerZip,Oh as buildCertificatePackScript,Bh as buildCertificateStateScript,Lh as buildCertificateUnpackScript,fd as buildCloudFormationTemplate,ic as buildCloudInitFirstBoot,Pc as buildComposeLogsCommand,Cy as buildComposeRuntimeCommand,by as buildComposeScaleCommand,Nc as buildComposeShellCommand,rp as buildDrainSourceScript,mh as buildDrainedSiteScanScript,Wt as buildFunctionEnv,tp as buildHealthGateScript,zn as buildHostCleanupScript,ei as buildHostSitePortsScript,ud as buildMailEnv,bs as buildManagementDashboardArtifact,Ou as buildMediaCdnPlan,cu as buildMtaStsPolicy,Wm as buildMtaStsServer,WC as buildNodeRuntimeLayerZip,PC as buildOptimizationManager,Fa as buildOriginGuardRule,Ku as buildPauseWorkersScript,eb as buildPhpRuntimeLayerZip,Yu as buildRestoreScript,K as buildRpxConfig,_e as buildRpxFragmentRefreshScript,Th as buildSetHostnameScript,qn as buildSiteDeployScript,Xu as buildSnapshotScript,np as buildSourceStateScript,wn as buildSshArgs,Nn as buildSshBootstrapScript,Ma as buildStaticSiteCacheRules,Vn as buildStaticSiteDeployScript,Zu as buildTargetStateScript,Wu as buildWorkersStateScript,ll as bytes,gC as canaryManager,Wr as canonicalJson,ht as capabilities,Kt as capacity,GI as categorizeChanges,wC as certificateManager,_h as certificatesMatch,EI as checkIAMPermissions,mA as checkInvocation,TI as checkServiceQuotas,qf as chunk,Vm as cleanupDns01Challenge,Dy as clearSigningKeyCache,Do as cloneSourceBinding,jI as cloudConfigSchema,Nu as cloudDrivers,dC as cloudTrailManager,dc as collectAssets,po as collectPhpAppEntries,ou as collectServerDnsDomains,dp as completeComposeVolumeDeletion,Eo as completeOidcAuthorization,dI as composePresets,Ds as composeProjectName,bd as composeServerlessAppTemplate,gf as compositeSpendTransport,St as compressBackup,vA as config,Il as connectionGuidance,NC as containerRegistryManager,Uh as controlPlaneDatabaseFile,bc as controlPlaneMigrations,Xy as createApiBackendPreset,ko as createApiV1Handler,xA as createAsgBuildDriver,Vl as createBackupQueueHandlers,IA as createCliHandler,k as createCloudDriver,tc as createCloudFrontPolicy,yI as createCredentialProvider,aI as createDashboardSite,rI as createDataPipelinePreset,Sl as createDataServiceQueueHandlers,kc as createDeploymentQueueHandlers,T as createDnsProvider,BA as createEcsBuildDriver,Yc as createEnforcementHandlers,Hp as createError,Ad as createExistingStaticFullStackPreset,El as createFleetQueueHandlers,Jy as createFullStackAppPreset,ms as createGoDaddyValidator,ZC as createHandlers,AA as createHttpHandler,Zy as createJamstackPreset,yl as createJobQueueHandlers,sI as createLaravelPreset,nI as createMLApiPreset,Nl as createMaintenanceQueueHandlers,Iu as createMediaAccessToken,eI as createMicroservicesPreset,YI as createMockAWS,zy as createNodeJsServerPreset,Ky as createNodeJsServerlessPreset,es as createObjectStorageClient,gs as createPorkbunValidator,lI as createPreset,hf as createPresignedUrl,Ey as createPresignedUrlAsync,yA as createQueueHandler,tI as createRealtimeAppPreset,Tl as createRegionQueueHandlers,al as createReleaseProvenance,Jd as createReleaseQueueHandlers,NA as createRemoteBuildQueueHandlers,hs as createRoute53Validator,Am as createRuntimeAdapters,II as createS3Client,kA as createServerBuildDriver,oI as createServerlessLaravelPreset,Wy as createServerlessNodePreset,iu as createSmsInfrastructure,Ke as createSourceAdapter,jy as createStaticSitePreset,iI as createTraditionalWebAppPreset,Bc as createVolumeQueueHandlers,Yy as createWordPressPreset,Si as createZip,ES as crossRegionReferenceManager,rn as dashboardActions,Cs as dashboardCredentialsFile,zr as dataServiceCapabilities,EC as databaseUserManager,Md as decodeBase32,Ne as decompressBackup,$m as decryptBackup,yo as defaultConfig,zp as defaultLocalConfig,xd as defaultRateLimitRules,sr as delegateZone,ss as delegateZoneFromConfig,va as deleteStaticSite,hc as deployAllComputeSites,aa as deployServerlessApp,Ql as deploySite,Es as deploySiteRelease,zi as deployStaticSite,Ta as deployStaticSiteFull,nn as deployStaticSiteWithExternalDns,sn as deployStaticSiteWithExternalDnsFull,dd as deploymentCoexistenceError,wf as deriveManagementDashboardPort,os as describeDelegation,Od as describePosture,cs as describeZoneSettings,Im as desiredJobProviderState,yp as detectAnomalies,Lp as detectDeploymentTargets,Ua as detectDnsProvider,zc as detectLatestAnomaly,CI as detectMisconfigurations,Bp as detectServiceRegion,Rc as diffCompose,UI as diffTemplates,Ro as discoverGitRefs,Co as discoverOidcProvider,ul as discoverRuntimeInventory,jC as dlqMonitoringManager,Qa as dnsProviders,FC as dnssecManager,mm as dockerWorkloads,Mi as documentDigest,aC as drManager,Le as driverStatePath,pl as ecsWorkloads,xt as effectiveCapabilities,HC as emailAnalyticsManager,qC as emailTemplateManager,wi as encodeBase32,Lm as encryptBackup,dl as ensureDefaultSecurityPolicies,Un as ensureFirewall,Kn as ensureManagementDashboard,Qn as ensureServer,Mn as ensureSshKey,J as escapeSecLang,Qc as evaluateBudget,_n as evaluatePreflight,js as evaluateTelemetryAlertRules,Al as eventBridgeScheduleInput,fA as eventToRequest,rf as ewma,wc as exportCompose,ds as exportRoute53Zone,Up as extendPreset,VC as fifoQueueManager,xI as findChangedFiles,up as findMapping,lp as findPriceEntry,qS as formatAccountStructure,Nh as formatAttachPlan,aS as formatBytes,kr as formatCents,Gy as formatDiff,fh as formatDrainedSiteRefusal,cS as formatDuration,AS as formatFlagSuggestions,SS as formatHistory,CS as formatHistoryStats,Sh as formatInventory,lS as formatKeyValue,dS as formatList,bh as formatPlan,Ln as formatPreflightFindings,oS as formatProgressBar,Zf as formatRegion,OS as formatRegionList,lm as formatScanResults,uS as formatSuggestion,iS as formatTable,Rr as formatTimeToExhaustion,sS as formatTree,kf as fromEC2Metadata,Bf as fromECSMetadata,Pf as fromEnvironment,Nf as fromSharedCredentials,xf as fromWebIdentity,vd as functionFingerprint,vn as gatewayHostnames,Ed as generateAppImageDockerfile,iC as generateApprovalConfig,sA as generateBootstrap,tS as generateCleanupWorkflow,rS as generateCostReportWorkflow,HS as generateCrossAccountRoleCF,il as generateCycloneDxSbom,tC as generateDeploymentConfig,JS as generateDeploymentPipeline,VS as generateDeploymentWorkflow,Ea as generateExternalDnsStaticSiteTemplate,_m as generateHttpsServerCode,sl as generateImageSbom,Mm as generateLetsEncryptUserData,t as generateLogicalId,eC as generateManualPipeline,WS as generateMatrixWorkflow,rC as generateMultiEnvConfig,XS as generateMultiEnvPipeline,jS as generateMultiEnvWorkflow,zS as generatePRPreviewWorkflow,sC as generateParallelConfig,SA as generatePhpFpmConfig,lA as generatePhpLayerDockerfile,YS as generatePreviewPipeline,eS as generatePreviewWorkflow,r as generateResourceName,nC as generateScheduledConfig,ZS as generateScheduledPipeline,KS as generateScheduledWorkflow,ji as generateStaticSiteTemplate,N as generateUbuntuAppCloudInit,Lf as getAccountId,RS as getAllRegions,BS as getClosestRegion,yS as getCommandUsage,Qh as getComposeTemplate,rm as getConfig,gS as getContextualHelp,to as getCredentials,qI as getDeploymentStrategy,VI as getDiffStats,QI as getDiffSummary,Uf as getErrorDetails,Id as getLocalConfig,JI as getLocalCredentials,WI as getLocalEndpoint,XI as getLocalEnvVars,wI as getQuotaUsageSummary,QS as getRecommendedStructure,Ii as getRegion,LS as getRegionStats,PS as getRegionsByCompliance,DS as getRegionsByLocation,NS as getRegionsByPricingTier,Qf as getRequiredPermissions,Py as getSigningKeyCacheSize,nu as getSmsInfrastructureStatus,Oy as getTimestamp,go as globMatches,vs as globToRegex,vS as globalResourceManager,oi as governingLimitCents,lC as guardDutyManager,Ks as handleSpendRequest,En as hasAutoWwwVariant,Ht as hasManagementDashboardSite,Cc as hasProxyUpstream,PI as hashBuffer,NI as hashDirectory,Vp as hashFile,kI as hashManifest,jp as hashString,nb as healthCheckManager,In as hostAcceptsIpv6,hn as hostCondition,Io as hotp,wr as hourBucket,tf as hourBucketsBetween,DC as imageScanningManager,Qi as infraEnvFromOutputs,wd as inspectInvocation,pA as installRecursionFetch,Wi as invalidateCache,Wg as invocationContext,pS as isLikelyTypo,Cn as isLocalDatabase,KI as isLocalDevelopment,_r as isManagementDashboardSiteName,nr as isNameserverRegistrar,Ny as isNodeCryptoAvailable,jc as isOperationAllowed,Vs as isQuietHours,Jn as isSafePattern,ad as isStateDirConfigured,cd as isStatePath,Br as isValidCidr,kS as isValidRegion,ii as isValidTimeZone,ky as isWebCryptoAvailable,ir as isZoneHost,jr as jobProviderCapability,Zi as keyMatchesFilters,_C as lambdaConcurrencyManager,$C as lambdaDLQManager,OC as lambdaDestinationsManager,BC as lambdaLayersManager,LC as lambdaVPCManager,xC as lambdaVersionsManager,gl as lambdaWorkloads,Pd as laravelServerlessEnvDefaults,br as listComposeTemplates,ki as listSourceReferences,$d as loadCloudConfig,Mt as loadTelemetryPolicy,yC as logsManager,Kc as lookbackHoursForSignal,Af as mailEnabled,ld as mailFirewallPorts,Tm as maintenanceWindowOpen,ff as makeAWSRequest,Ty as makeAWSRequestAsync,vy as makeAWSRequestOnce,Fp as managementDashboardSiteName,wl as manifestDigest,Fr as matchTotpCounter,Eu as mediaObjectHeaders,Fs as median,fp as medianAbsoluteDeviation,Hc as mergeDecisions,Or as mergeInfrastructure,Zh as mergePriceBooks,Mc as meterTelemetry,AC as metricsManager,Zl as migrateObjectStorage,SC as migrationManager,$S as multiAccountManager,bS as multiRegionManager,Hm as needsRenewal,ib as networkSecurityManager,At as nextScheduleRuns,Ae as normalizePublicIpv6,Re as normalizeRuntimeStatus,We as normalizeScheduleExpression,cm as normalizeSourceEvent,Oe as normalizeSshPublicKey,Ep as normalizeTelemetryPolicy,Zn as occupiedHostPorts,No as openApiDocument,Gs as optionsForSignal,MS as organizationManager,Nd as packagePhpApp,Mr as packageServerlessApp,lc as pagesAssetHash,Ru as pagesDnsRecord,yd as parallel,OI as parallelMap,LI as parallelWithRetry,xh as parseCertificateState,Td as parseChain,Cr as parseCompose,Iy as parseComposeCatalog,gm as parseDockerInspect,Kl as parseDotenv,hh as parseDrainedSites,ti as parseHostSiteFragments,Ry as parseJSONResponse,xn as parsePreflightFacts,ip as parseSourceDrained,hm as parseSystemdRecords,ep as parseTargetReady,Sc as parseUpstreamPort,Ju as parseWorkersPaused,wy as parseXMLResponse,pi as pathTemplate,yc as pendingSteps,Ms as percentOfLimit,bC as performanceManager,zg as phpLayerBuildStage,dA as phpLayerPackages,bi as phpRuntimeLayerAssets,Sy as planComposeTemplateUpgrade,Gc as planEnforcement,ju as planIsDestructive,kp as planMitigation,vh as planServerRename,$h as planSiteMove,ls as planZoneMigration,Tt as policyTag,On as preflightFailed,ZI as previewManager,nS as previewNotifications,yt as previewSchedule,ef as previousBudgetWindow,Os as priceUsage,Xh as priceUsageLines,yh as probeHostRoutes,Ya as probeOriginTls,FI as processInChunks,tl as processSourceWebhook,_i as productionChangeReview,hC as progressiveDeploymentManager,Uc as projectSpend,Rd as propagationHeaders,Ra as providerEndpoint,Rl as publicKeyFingerprint,fn as qualifyName,KC as queueManagementManager,BI as quickHash,Bd as rateLimitHeaders,vi as rateLimitKey,$e as readDriverState,Ih as reconcile,au as reconcileAddressRecords,yu as reconcileCloudflareCdn,is as reconcileDeclaredRecords,PA as reconcileJobObservation,Hr as reconcileSourceWebhook,xi as recordDashboardHostPosture,wA as recordPreDeploySecretScan,RA as recordSkippedSecretScan,Dd as recursionBlockedResponse,De as redactRuntimeConfig,td as redactTelemetryText,ui as redactTelemetryValue,Yr as redeployServerlessApp,TS as regionPairManager,Qr as releaseStrategyCapabilities,om as releaseTrafficPlan,Wn as reloadRpxGateway,Yi as remapKey,uu as removeDns01ChallengeRecord,Xr as removeSiteFromCloudConfig,rl as removeSourceWebhook,Ha as removeStaleServerAddressRecords,Dc as renderComposeTemplate,hi as renderDdosInstallScript,sd as renderNftablesRuleset,Oi as renderServerCron,id as renderSysctlFile,Ac as renderWafConfig,Xn as renderWafInstallScript,fc as renewRpxCertificates,CC as replicaManager,mf as requestHash,HI as requiresReplacement,XC as resetRecursionRuntime,YC as resolveApp,p as resolveAppDatabase,wh as resolveAttachTarget,ze as resolveAuthEncryptionKey,le as resolveCloudProvider,Su as resolveCloudflareCdnPlan,_f as resolveCredentials,Vi as resolveDashboardAction,mc as resolveDashboardAuth,Rf as resolveDashboardDomain,Df as resolveDashboardDomains,ns as resolveDeclaredRecords,Qy as resolveDeployBucketName,O as resolveDeploymentMode,Gn as resolveExecStart,Xa as resolveHetznerApiToken,fi as resolveMailService,cI as resolveManagementDashboardSite,yi as resolveManagementDashboardSites,Da as resolveObjectStorage,Ch as resolvePlan,g as resolveProjectStackName,Sr as resolveProxyUpstreams,Cd as resolveQueueNames,Gh as resolveQueuedDeploymentCommand,qt as resolveQueues,uA as resolveRecursionConfig,Of as resolveRegion,re as resolveRuntimeInventory,Ft as resolveServerlessAppStackName,gd as resolveServerlessArtifactBucketName,Xs as resolveServerlessAssetBucketName,so as resolveServerlessRuntime,Fy as resolveSiteBucketName,Ts as resolveSiteDeployTarget,u as resolveSiteKind,My as resolveSiteResourceName,$y as resolveSiteStackName,kn as resolveSshSettings,d as resolveStatePath,Uy as resolveStorageBucketName,Nt as resolveUiSource,sc as resolveZoneApex,sb as resourceManagementManager,Jg as responseToResult,Ap as robustZScore,Bt as roleCapabilities,Wd as rollbackImmutableRelease,Zr as rollbackServerlessApp,Yh as roundCents,UC as route53ResolverManager,MC as route53RoutingManager,Sp as routeMatches,Gu as routesFromFragments,Ei as ruleMatches,oA as runBuildHooks,qc as runEnforcement,uo as runPhpBuildHooks,Je as runRemoteCommand,ue as runtimeId,An as sameNameservers,qi as sanitizeCloudConfig,s as sanitizeControlPlaneValue,Ly as sanitizeName,Gd as sanitizeOidcReturnPath,Zc as saveTelemetryPolicy,dm as scanForSecrets,Ec as scopeContains,dt as scopeKey,za as scpUpload,mS as searchCommands,Rs as searchControlPlane,TC as secretsManager,vC as secretsRotationManager,DA as secureContainerRelease,uC as securityHubManager,RC as securityScanningManager,te as securityScope,Ur as sendAuthenticationEmail,GC as senderReputationManager,$I as sequence,Wl as serializeDotenv,Hn as serverPublicIpv4,kC as serviceMeshManager,$l as setAttachToInCloudConfig,Jt as setMaintenance,Fi as setSitePropertyInCloudConfig,od as setStateDir,Bm as setupDns01Challenge,La as setupSmsInfrastructure,io as sha256,gA as sharedRecursionGuard,Kg as sharedRuntimeLoop,ap as shipsARelease,Du as signCloudFrontCookies,$u as signCloudFrontUrl,x as signRequest,xp as signRequestAsync,Qs as signalDefinition,B as siteInstallBase,Yn as siteMoveArchivePath,kh as siteMoveCertArchivePath,Ic as siteUnitGlob,Tp as spendNotificationText,Ws as spendOpenApiPaths,pr as sshExec,ce as sshExecOrThrow,wS as stackDependencyManager,ba as startLocalDashboardServer,pf as startSpendLoop,Js as stateDir,_ as statePath,tb as staticSiteManager,rb as storageAdvancedManager,nf as streamFocusJsonl,Vc as strongestActiveAction,Zp as suggestCommand,fS as suggestFlags,vI as suggestIAMPolicy,RI as suggestQuotaIncrease,_S as suggestRegionPairs,xS as suggestRegions,Ni as syncSourceRepositories,xc as synchronizeComposeVolumes,Jl as synchronizeConfiguredConfiguration,Mo as synchronizeConfiguredJobs,IC as syntheticsManager,nd as sysctlHardening,fm as systemdWorkloads,df as telemetryBucketLabel,gi as telemetryCursor,ed as telemetryEstimatedMonthlyCost,cf as telemetryPercentile,vp as telemetryPolicyKey,DI as templateCache,qu as tenantsOf,Po as testSourceConnection,_c as tieredMicroCents,Ja as toCloudflareZoneSettings,qs as toFocusJsonl,Wc as toFocusRecords,Ah as toInventoryServer,nm as totp,So as totpUri,Vu as unaccountedSites,pm as unsupportedCapabilities,qh as unsupportedVolumeCapabilities,Pl as updateCompatibility,kl as updateSiteInCloudConfig,Ki as uploadStaticFiles,pp as usageDeltaKey,Lt as utcInstantOfLocal,GS as validateAccountStructure,zI as validateAgainstSchema,jh as validateAttachment,Om as validateBackupDestination,IS as validateCommand,SI as validateConfiguration,bI as validateCredentials,op as validateDeploymentConfig,Vh as validateMountPath,Yl as validateResourceLimits,zu as validateServerName,Ml as validateTemplate,Ul as validateTemplateSize,qa as verifyAddressRecord,TA as verifyArtifactSignature,wu as verifyMediaAccessToken,im as verifyTotp,Dl as verifyUpdateSignature,ps as verifyZoneParity,ks as volumeCapabilities,Fu as wafEventTelemetry,Ka as waitForCloudInit,Rn as waitForSsh,jt as webhookEndpoint,hI as withCDN,mI as withCache,gI as withDatabase,hA as withInvocation,uI as withMonitoring,fI as withQueue,pI as withSecurity,MI as withTimeout,W as wrapCloudInitUserData,nt as writeDriverState,fC as xrayManager,vl as zeroCapacity,sf as zeroFill,Lc as zoneOffsetMs,Ls as zonedParts};
|
|
604
|
+
`}async function mu(l,S,P){let E=`_acme-challenge.${S}`;if(await hu(l,S,E,P))return;let v=await l.createRecord(S,{name:E,type:"TXT",content:P,ttl:60});if(!v.success)throw Error(`Failed to create DNS challenge record: ${v.message}`)}async function fu(l,S,P){let E=await l.deleteRecord(S,{name:`_acme-challenge.${S}`,type:"TXT",content:P});if(!E.success)console.warn(`Failed to delete DNS challenge record: ${E.message}`)}async function hu(l,S,P,E){try{let v=await l.listRecords(S,"TXT"),it=P.replace(/\.$/,"").toLowerCase();return(v.records??[]).some((Pe)=>Pe.name.replace(/\.$/,"").toLowerCase()===it&&Pe.content.replace(/^"|"$/g,"")===E)}catch{return!1}}function ic(l){let{hostedZoneId:S,dnsProvider:P,region:E="us-east-1"}=l;if(P)return T(P);if(S)return new z(E,S);throw Error("Either dnsProvider or hostedZoneId must be provided")}async function Um(l){await mu(ic(l),l.domain,l.challengeValue)}async function Km(l){await fu(ic(l),l.domain,l.challengeValue)}function Zm(l){try{let{execSync:S}=Me("node:child_process"),P=S(`openssl x509 -checkend 2592000 -noout -in ${l}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as ac,createSign as yu,generateKeyPairSync as sc}from"node:crypto";var cc={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class Cu{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(l){this.directoryUrl=l.staging?cc.staging:cc.production,this.email=l.email,this.accountKey=l.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:l}=sc("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 E=this.nonce;return this.nonce=null,E}let l=await this.getDirectory(),P=(await fetch(l.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!P)throw Error("Failed to get nonce from ACME server");return P}getJwk(){let l=this.accountKey.split(`
|
|
605
|
+
`).filter((it)=>!it.startsWith("-----")).join(""),S=Buffer.from(l,"base64"),P=S.length-65,E=S.subarray(P+1,P+33),v=S.subarray(P+33,P+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(E),y:this.base64UrlEncode(v)}}getJwkThumbprint(){let l=this.getJwk(),S=JSON.stringify({crv:l.crv,kty:l.kty,x:l.x,y:l.y}),P=ac("sha256").update(S).digest();return this.base64UrlEncode(P)}base64UrlEncode(l){return(typeof l==="string"?Buffer.from(l):l).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(l,S){let P=await this.getNonce(),E=this.getJwk(),v={alg:"ES256",nonce:P,url:l};if(this.accountUrl)v.kid=this.accountUrl;else v.jwk=E;let it=this.base64UrlEncode(JSON.stringify(v)),Pe=S===""?"":this.base64UrlEncode(JSON.stringify(S)),Ie=`${it}.${Pe}`,rt=yu("SHA256");rt.update(Ie);let Pt=rt.sign(this.accountKey),st=Pt.subarray(4,4+Pt[3]),cr=4+Pt[3]+2,lr=Pt.subarray(cr,cr+Pt[cr-1]),fr=Buffer.alloc(32),Dt=Buffer.alloc(32);st.copy(fr,32-st.length),lr.copy(Dt,32-lr.length);let Rt=Buffer.concat([fr,Dt]);return JSON.stringify({protected:it,payload:Pe,signature:this.base64UrlEncode(Rt)})}async acmeRequest(l,S){let P=await this.signPayload(l,S),E=await fetch(l,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:P}),v=E.headers.get("replay-nonce");if(v)this.nonce=v;let it,Pe=E.headers.get("content-type");if(Pe?.includes("application/json")||Pe?.includes("application/problem+json"))it=await E.json();else it=await E.text();if(!E.ok)throw Error(`ACME request failed: ${JSON.stringify(it)}`);return{body:it,headers:E.headers}}async registerAccount(){let l=await this.getDirectory(),{body:S,headers:P}=await this.acmeRequest(l.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),E=P.get("location");if(!E)throw Error("No account URL returned");return this.accountUrl=E,E}async createOrder(l){if(!this.accountUrl)await this.registerAccount();let S=await this.getDirectory(),{body:P,headers:E}=await this.acmeRequest(S.newOrder,{identifiers:l.map((it)=>({type:"dns",value:it}))}),v=E.get("location");if(!v)throw Error("No order URL returned");return{orderUrl:v,authorizations:P.authorizations,finalize:P.finalize}}async getAuthorization(l){let{body:S}=await this.acmeRequest(l,""),P=S.identifier.value,E=this.getJwkThumbprint(),v=S.challenges.filter((it)=>it.type==="http-01"||it.type==="dns-01").map((it)=>{let Pe=`${it.token}.${E}`;if(it.type==="http-01")return{type:"http-01",token:it.token,keyAuthorization:Pe,identifier:`/.well-known/acme-challenge/${it.token}`};else{let Ie=this.base64UrlEncode(ac("sha256").update(Pe).digest());return{type:"dns-01",token:it.token,keyAuthorization:Pe,identifier:`_acme-challenge.${P}`,dnsValue:Ie}}});return{domain:P,challenges:v}}async respondToChallenge(l){await this.acmeRequest(l,{})}async waitForAuthorization(l,S=30){for(let P=0;P<S;P++){let{body:E}=await this.acmeRequest(l,"");if(E.status==="valid")return;if(E.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(E)}`);await new Promise((v)=>setTimeout(v,2000))}throw Error("Authorization timed out")}generateCsr(l){let{privateKey:S}=sc("rsa",{modulusLength:2048}),P=S.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(l,S),privateKey:P}}createSimpleCsr(l,S){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(l,S){let{csr:P,privateKey:E}=this.generateCsr(S),{body:v}=await this.acmeRequest(l,{csr:this.base64UrlEncode(Buffer.from(P,"base64"))}),it=v.certificate;if(!it)throw Error("Certificate not immediately available - polling not implemented");let Ie=await(await fetch(it)).text(),rt=Ie.split(/(?=-----BEGIN CERTIFICATE-----)/g),Pt=rt[0],st=rt.slice(1).join("");return{certificate:Pt,privateKey:E,chain:st,fullchain:Ie,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var wn=(l)=>l===void 0?void 0:l?"on":"off";function ns(l){let S={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)S.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 P of Object.keys(S))if(S[P]===void 0)delete S[P];return{...S,...l.raw??{}}}var Yi={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 Su}from"node:tls";async function ys(l){let{address:S,serverName:P,port:E=443,timeoutMs:v=5000}=l;return new Promise((it)=>{let Pe=!1,Ie=(Pt)=>{if(Pe)return;Pe=!0;try{rt.destroy()}catch{}it(Pt)},rt=Su({host:S,port:E,servername:P,rejectUnauthorized:!1,timeout:v});rt.once("secureConnect",()=>{if(rt.authorized){Ie({reachable:!0,trusted:!0});return}Ie({reachable:!0,trusted:!1,reason:rt.authorizationError?String(rt.authorizationError):"origin certificate is not trusted for this hostname"})}),rt.once("timeout",()=>{Ie({reachable:!1,trusted:!1,reason:`no TLS handshake within ${v}ms`})}),rt.once("error",(Pt)=>{Ie({reachable:!1,trusted:!1,reason:Pt.message})})})}function Au(l,S){let P=S.replace(/\.$/,"").toLowerCase();return l.some((E)=>{let v=E.replace(/\.$/,"").toLowerCase();if(v===P)return!0;if(!v.startsWith("*."))return!1;let it=v.slice(2);if(!P.endsWith(`.${it}`))return!1;return!P.slice(0,P.length-it.length-1).includes(".")})}async function bu(l){let{provider:S,zone:P,hosts:E,ipv4:v,ipv6:it,proxied:Pe=!0,settings:Ie=Yi,cache:rt,originGuard:Pt,purge:st=!0,ttl:cr=300,skipOriginProbe:lr=!1,skipEdgeCertificateCheck:fr=!1}=l,Dt={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(E.length===0)return Dt;let Rt=[],Se=Pe&&!fr?await S.listEdgeCertificateHosts(P):null;for(let ie of E){let It=Pe;if(It&&Se&&!Au(Se,ie)){It=!1;let Xt=Se.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${Se.join(", ")})`;Dt.deferredProxy.push({host:ie,reason:Xt}),Dt.warnings.push(`${ie}: publishing DNS-only — ${Xt}. 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(It&&!lr){let Xt=await ys({address:v,serverName:ie});if(!Xt.trusted){It=!1;let ar=Xt.reason||"origin is not serving a trusted certificate";Dt.deferredProxy.push({host:ie,reason:ar}),Dt.warnings.push(`${ie}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${ar}). 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(It)Rt.push(ie);let wt=[{type:"A",content:v}];if(it&&Sn(ie))wt.push({type:"AAAA",content:it});for(let{type:Xt,content:ar}of wt){let dr=await S.upsertRecord(P,{name:ie,type:Xt,content:ar,ttl:cr,proxied:It});if(dr.success)Dt.records.push({host:ie,type:Xt,content:ar,proxied:It});else Dt.warnings.push(`${ie} ${Xt} → ${ar} failed: ${dr.message||"unknown provider error"}`)}}if(Rt.length===0){if(Pe)Dt.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return Dt}try{let ie=ns(Ie),It=await S.applyZoneSettings(P,ie);Dt.settingsChanged=It.changed;for(let wt of It.failed)Dt.warnings.push(`zone setting '${wt.id}' could not be applied: ${wt.error}`)}catch(ie){Dt.warnings.push(`zone settings could not be read: ${ie instanceof Error?ie.message:String(ie)}`)}let kt=Ua(Rt,rt);if(kt.length>0){let ie=await S.putManagedPhaseRules(P,"http_request_cache_settings",kt);if(ie.success)Dt.cacheRules=kt.length;else Dt.warnings.push(`cache rules could not be written: ${ie.message}`)}if(Pt){let ie=Qa(Rt,Pt.header,Pt.value);if(ie.length>0){let It=await S.putManagedPhaseRules(P,"http_request_late_transform",ie);if(It.success)Dt.originGuard=!0;else Dt.warnings.push(`origin guard header could not be written: ${It.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(st){if(Dt.purged=await S.purgeCache(P,{hosts:Rt}),!Dt.purged)Dt.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Dt}var Ru=(l)=>process.env[l];function lc(l,S){let P=l.replace(/\.$/,"").toLowerCase();if(S){let E=S.replace(/\.$/,"").toLowerCase();if(P===E||P.endsWith(`.${E}`))return E}return P.split(".").slice(-2).join(".")}function Pu(l,S={}){let P=S.env??Ru,E=l.infrastructure?.compute?.proxy?.cdn,v=[];if(!E||E.provider!=="cloudflare")return{plan:null,errors:v};if(E.originDomain)v.push(`compute.proxy.cdn.originDomain (${E.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 it=P("CLOUDFLARE_API_TOKEN");if(!it)return v.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:v};let Pe=l.sites??{},Ie=E.frontedHosts?.length?[...new Set(E.frontedHosts.map((lr)=>lr.toLowerCase()))]:Tn(Pe,{autoWww:l.infrastructure?.compute?.proxy?.autoWww!==!1});if(Ie.length===0)return v.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:v};let rt=l.infrastructure?.dns?.domain,Pt=new Set(Ie.map((lr)=>lc(lr,rt)));if(Pt.size>1)return v.push(`Fronted hosts span more than one zone (${[...Pt].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:v};let st=E.cloudflare??{},cr=E.secret?{header:E.secretHeader??"X-Origin-Verify",value:E.secret}:void 0;return{plan:{zone:[...Pt][0],hosts:Ie,apiToken:it,zoneId:st.zoneId??P("CLOUDFLARE_ZONE_ID"),accountId:st.accountId??P("CLOUDFLARE_ACCOUNT_ID"),proxied:st.proxied!==!1,settings:st.settings??Yi,cache:st.cache,originGuard:cr,purge:st.purgeOnDeploy!==!1,skipOriginProbe:st.skipOriginProbe===!0},errors:v}}var Tu=26214400;var $u=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class dc{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,S,P){return $a(l,`/accounts/${this.accountId}${S}`,`Bearer ${this.apiToken}`,P)}async getProject(l){try{return await this.request("GET",`/pages/projects/${l}`)}catch(S){if(S instanceof Error&&/\b8000007\b|not found/i.test(S.message))return null;throw S}}async ensureProject(l,S="main"){let P=await this.getProject(l);if(P)return P;return this.request("POST","/pages/projects",{name:l,production_branch:S})}async uploadToken(l){return(await this.request("GET",`/pages/projects/${l}/upload-token`)).jwt}async missingHashes(l,S){let P=await $a("POST","/pages/assets/check-missing",`Bearer ${l}`,{hashes:S});return new Set(P)}async upsertHashes(l,S){await $a("POST","/pages/assets/upsert-hashes",`Bearer ${l}`,{hashes:S})}async uploadBatch(l,S){let P=S.map((E)=>({key:E.hash,value:E.base64,metadata:{contentType:Du(E.extension)},base64:!0}));await $a("POST","/pages/assets/upload",`Bearer ${l}`,P)}async createDeployment(l,S,P){let E={};for(let it of S)E[it.path]=it.hash;let v=new FormData;if(v.append("manifest",JSON.stringify(E)),P)v.append("branch",P);return this.request("POST",`/pages/projects/${l}/deployments`,v)}async deployDirectory(l){let S=await pc(l.directory);if(S.length===0)throw Error(`No files to deploy in ${l.directory}`);let P=await this.uploadToken(l.project),E=await this.missingHashes(P,S.map((rt)=>rt.hash)),v=S.filter((rt)=>E.has(rt.hash)),it=[];for(let rt=0;rt<v.length;rt+=100)it.push(v.slice(rt,rt+100));let Pe=0;for(let rt=0;rt<it.length;rt+=4){let Pt=it.slice(rt,rt+4);await Promise.all(Pt.map((st)=>this.uploadBatch(P,st))),Pe+=Pt.reduce((st,cr)=>st+cr.length,0),l.onProgress?.(Pe,v.length)}return await this.upsertHashes(P,S.map((rt)=>rt.hash)),{deployment:await this.createDeployment(l.project,S,l.branch),total:S.length,uploaded:v.length,uploadedBytes:v.reduce((rt,Pt)=>rt+Pt.size,0)}}async listCustomDomains(l){return(await this.request("GET",`/pages/projects/${l}/domains`)).map((P)=>P.name)}async attachCustomDomain(l,S){if((await this.listCustomDomains(l)).includes(S))return!1;return await this.request("POST",`/pages/projects/${l}/domains`,{name:S}),!0}}function Iu(l,S){return{type:"CNAME",name:l,value:S.endsWith(".pages.dev")?S:`${S}.pages.dev`,ttl:1,proxied:!0}}async function uc(l,S){let{blake3:P}=await import("./chunk-gn42mekr.js").then((m)=>yh(m.default,1));return(await P(l+S)).slice(0,32)}async function pc(l){let{readdir:S}=await import("node:fs/promises"),{join:P,relative:E,sep:v}=await import("node:path"),it=[];async function Pe(Ie){let rt=await S(Ie,{withFileTypes:!0});for(let Pt of rt){let st=P(Ie,Pt.name);if(Pt.isDirectory()){await Pe(st);continue}if(!Pt.isFile())continue;let cr=`/${E(l,st).split(v).join("/")}`;if($u.has(cr))continue;let lr=await Bun.file(st).bytes();if(lr.byteLength>26214400)throw Error(`${cr} is ${lr.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let fr=Buffer.from(lr).toString("base64"),Dt=Pt.name.lastIndexOf("."),Rt=Dt>0?Pt.name.slice(Dt+1):"";it.push({path:cr,hash:await uc(fr,Rt),base64:fr,extension:Rt,size:lr.byteLength})}}return await Pe(l),it.sort((Ie,rt)=>Ie.path.localeCompare(rt.path)),it}function Du(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 $a(l,S,P,E){let v={Authorization:P},it;if(E instanceof FormData)it=E;else if(E!==void 0)v["Content-Type"]="application/json",it=JSON.stringify(E);let Pe=await fetch(`https://api.cloudflare.com/client/v4${S}`,{method:l,headers:v,body:it}),Ie=await Pe.text(),rt;try{rt=JSON.parse(Ie)}catch{throw Error(`Cloudflare Pages API returned ${Pe.status} with a non-JSON body: ${Ie.slice(0,200)}`)}if(!rt.success){let Pt=(rt.errors??[]).map((st)=>`${st.code}: ${st.message}`).join(", ");throw Error(`Cloudflare Pages API error (${Pe.status}): ${Pt||Ie.slice(0,200)}`)}return rt.result}export{bg as ABTestManager,ae as ACMClient,or as ACMDnsValidator,cc as ACME_DIRECTORIES,Te as AI,Jd as API_IDEMPOTENCY_TTL_MS,Kd as API_TOKEN_DEFAULT_TTL_MS,Wd as API_TOKEN_MAX_TTL_MS,xi as API_VERSION,de as AUTHORIZATION_CAPABILITIES,qd as AUTH_ACTION_TOKEN_TTL_MS,Vd as AUTH_MFA_CHALLENGE_TTL_MS,jd as AUTH_OIDC_TRANSACTION_TTL_MS,je as AUTH_SESSION_ABSOLUTE_TTL_MS,Gd as AUTH_SESSION_IDLE_TTL_MS,jf as AWSAPIError,n as AWSClient,h as AWSCloudFormationClient,A as AWSCloudFrontClient,Ig as AWSConfigManager,eI as AWS_PSEUDO_PARAMETERS,we as AWS_REGIONS,Cu as AcmeClient,Nr as AlertEvaluator,li as AlertStore,Hs as AnomalyConfigStore,Id as ApiGateway,i as ApiServiceError,La as ApplicationAutoScalingClient,ro as Arn,D as AssetHasher,U as Auth,Pi as AuthenticationStore,hi as AutomationApiService,Ni as AutomationIdentityStore,qo as AwsAuroraDataAdapter,Wo as AwsAuroraTransport,ga as AwsDatabaseBackupSource,ur as AwsDriver,Vo as AwsElastiCacheDataAdapter,Jo as AwsElastiCacheTransport,Cm as AwsIamCapabilityScanner,ya as AwsInfrastructureBackupSource,Go as AwsRdsDataAdapter,Ko as AwsRdsTransport,xm as AwsRegionalDriver,Sa as AwsSecretsManagerConfigurationBackend,Lp as AwsSpendTransport,Ca as AwsSsmConfigurationBackend,Vi as BackupCoordinator,Ag as BackupManager,ua as BackupStore,tm as BatchProcessingManager,un as BedrockClient,ln as BedrockRuntimeClient,nl as BitbucketSourceAdapter,Eg as BlueGreenManager,Wg as BounceComplaintHandler,$g as BuildOptimizationManager,Tl as BunDockerRuntime,Xl as BunDockerVolumeRuntime,Jl as BunFilesystemArchiveRuntime,ue as CDN,lo as CHAIN_HEADER,is as CLOUDFLARE_MANAGED_RULE_PREFIX,fd as CLOUDFRONT_FAILOVER_STATUS_CODES,WS as COMMON_CROSS_ACCOUNT_ROLES,Fe as CONTROL_PLANE_SCHEMA_VERSION,eo as Cache,so as CanaryManager,xg as CertificateManager,ef as CloudBlockVolumeDriver,Es as CloudDriverFactory,Ve as CloudError,zp as CloudFormationBuilder,h as CloudFormationClient,A as CloudFrontClient,Sg as CloudTrailManager,he as CloudWatchLogsClient,dc as CloudflarePagesProvider,Ae as CloudflareProvider,oA as CommandHistory,H as Communication,Tr as ComposeApplicationService,Ot as ComposeApplicationStore,Ct as ComprehendClient,o as Compute,$p as ComputeSpendTransport,io as ConfigurationError,ba as ConfigurationService,Ia as ConfigurationStore,cn as ConnectClient,zo as ContainerDataAdapter,Mg as ContainerRegistryManager,Aa as ControlPlaneBackupSource,aa as ControlPlaneCleanupDriver,ni as ControlPlaneStore,Fs as CounterTracker,Gt as CredentialError,ug as CrossRegionReferenceManager,kf as DASHBOARD_ENTRY,Bf as DASHBOARD_PORT_BASE,_f as DASHBOARD_PORT_SPAN,Nf as DASHBOARD_STATE_DIR,Ao as DEFAULT_ATTACK_MODE_HOURS,id as DEFAULT_DDOS_THRESHOLDS,qp as DEFAULT_FAILOVER_STATUS_CODES,Fc as DEFAULT_METER_MAPPINGS,$c as DEFAULT_PRICE_BOOK,bi as DEFAULT_RECURSION_LIMITS,bn as DEFAULT_RPX_CERTS_DIR,q as DEFAULT_SERVICE_LIMITS,Qp as DEFAULT_STATE_DIR,du as DEFAULT_STATIC_ASSET_EXTENSIONS,mf as DEFAULT_TELEMETRY_POLICY,Sp as DEFAULT_THRESHOLDS,Wh as DEPLOYMENT_QUEUE_KINDS,co as DEPTH_HEADER,Dr as DETECTABLE_SIGNALS,Sl as DIAGNOSTIC_PRESETS,em as DLQMonitoringManager,L as DNS,zg as DNSSECManager,Mi as DataServiceLifecycle,Ho as DataServiceStore,Ut as Database,kg as DatabaseUserManager,ee as DebugLogger,Tf as DependencyGraph,Q as Deployment,Vf as DeploymentError,yg as DisasterRecoveryManager,In as DnsProviderFactory,zt as DockerDataTransport,Lo as DockerDiscoveryAdapter,vr as DockerNamedVolumeDriver,fa as DockerVolumeBackupSource,c as DurableOperationQueue,Bs as DurableQueueWorker,ke as DynamoDBClient,Ar as EC2Client,Be as ECRClient,Xe as ECSClient,rr as EFSClient,Ba as ELBv2Client,rf as ENFORCEMENT_ACTIONS,ci as ENFORCEMENT_DESCRIPTIONS,R as ENFORCEMENT_SEVERITY,Ku as ENVIRONMENT_LABEL,yl as EcsRuntimeAdapter,fo as EdgeRateLimiter,Ze as ElastiCacheClient,m as Email,dA as EmailAdvanced,Jg as EmailAnalyticsManager,hn as EmailClient,lA as EmailHandlers,Yg as EmailTemplateManager,Xo as EncryptedDataSecretStore,zf as ErrorCodes,er as EventBridgeClient,km as EventBridgeJobAdapter,Ea as ExternalConfigurationBackend,Zg as FIFOQueueManager,Dp as FOCUS_VERSION,Zp as FileCache,Ge as FileSystem,ma as FilesystemBackupSource,Zo as FleetService,Yo as FleetStore,e as Fn,il as GiteaSourceAdapter,tl as GithubSourceAdapter,rl as GitlabSourceAdapter,pg as GlobalResourceManager,_e as GoDaddyProvider,Cg as GuardDutyManager,ot as HOST_SITES_DIR,Jf as HashCache,dm as HealthCheckManager,Qe as HealthCheckRunner,gr as HetznerClient,Ce as HetznerDriver,fe as IAMClient,Va as IPV6_EXCLUDED_HOST_LABELS,Lg as ImageScanningManager,Ml as InfrastructureGenerator,wc as InvalidOperationTransitionError,ut as JobLoader,Bm as JobProviderReconciler,Qo as JobService,Fo as JobStore,Zt as KendraClient,PA as LARAVEL_SERVERLESS_BUILD_STEPS,C as LambdaClient,Hg as LambdaConcurrencyManager,Vg as LambdaDLQManager,Gg as LambdaDestinationsManager,Ug as LambdaLayersManager,Il as LambdaRuntimeAdapter,qg as LambdaVPCManager,Qg as LambdaVersionsManager,rn as LocalEncryptedConfigurationBackend,ha as LogicalDatabaseBackupSource,Rg as LogsManager,hA as MANAGED_NODE_VERSIONS,hc as MANAGEMENT_DASHBOARD_SITE,Kp as MANAGEMENT_DASHBOARD_SITE_PREFIX,Ri as MAX_CONTROL_HOURS,Rc as MAX_CONTROL_PLANE_ERROR_BYTES,hp as MAX_CONTROL_PLANE_JSON_BYTES,Ls as METERS,tf as METER_KEYS,nf as MICRO_CENTS,Cp as MIN_PROJECTION_CONFIDENCE,gu as MTA_STS_PORT,oa as MaintenanceService,sa as MaintenanceStore,Z as Messaging,wg as MetricsManager,Dg as MigrationManager,ig as MockCloudFormation,og as MockDynamoDB,sg as MockS3,to as Monitoring,hg as MultiAccountManager,lg as MultiRegionManager,eA as MultiStepProgress,f as Network,lm as NetworkSecurityManager,ui as NotificationRouter,Vp as ORIGIN_GROUP_ALLOWED_METHODS,Yy as ORIGIN_GROUP_ID_SUFFIX,_a as OpenSearchClient,at as OptimisticConcurrencyError,fg as OrganizationManager,Tu as PAGES_MAX_FILE_BYTES,NA as PHP_DEFAULT_EXCLUDES,fA as PHP_LAYER_EXTENSIONS,zu as PROJECT_LABEL,tt as PROXIABLE_RECORD_TYPES,b as ParameterStore,Ng as PerformanceManager,Y as Permissions,xa as PersonalizeClient,qe as Phone,uA as PhoneAdvanced,Rf as PhoneHandlers,ta as PlacementService,ea as PlacementStore,pn as PollyClient,se as PorkbunProvider,Vr as PreDeployScanner,ag as PreviewEnvironmentManager,br as PreviewEnvironmentService,Ue as PreviewEnvironmentStore,cg as PreviewNotificationService,Zf as ProgressBar,vg as ProgressiveDeploymentManager,yo as ProtectionControlStore,Hy as Pseudo,M as Queue,ii as QueueCancellationError,rm as QueueManagementManager,Uy as QueuePresets,ks as QueueTimeoutError,Od as RATE_LIMIT_KEY_SEPARATOR,j as RDSClient,cA as RECOMMENDED_ACCOUNT_STRUCTURES,KS as RECOMMENDED_SCPS,Am as RELEASE_QUEUE_KINDS,nA as REPL,sA as REPLCommandBuilder,iA as REPLContext,Wu as ROLE_LABEL,Xf as RateLimiter,Qy as RealtimePresets,Pp as RecordingSpendTransport,po as RecursionGuard,pt as Redirects,gg as RegionPairManager,na as RegionService,ra as RegionStore,He as Registry,Et as RekognitionClient,gt as ReleaseService,Ro as ReleaseStore,_m as RemoteBuildService,Pg as ReplicaManager,um as ResourceManagementManager,X as RetryableOperationError,y as Route53Client,ka as Route53DomainsClient,z as Route53Provider,Kg as Route53ResolverManager,jg as Route53RoutingManager,ge as RuntimeOperationService,Mo as RuntimeStreamRegistry,pa as S3BackupDestinationAdapter,a as S3Client,G as S3Error,al as SECRET_PATTERNS,wp as SENSITIVITY_THRESHOLDS,et as SESClient,F as SMS,Ye as SNSClient,Op as SPEND_CYCLE_SECONDS,Yc as SPEND_GATE_SETTING,yf as SPEND_LEASE_SETTING,ne as SQSClient,Ee as SSH_BOOTSTRAP_VERSION,_n as SSH_PREFLIGHT_SCRIPT,be as SSMClient,Hp as STATE_DIR_ENV_VAR,Yi as STATIC_SITE_ZONE_SETTINGS,me as STSClient,gn as SchedulerClient,Qt as Search,jr as SecretFindingScanner,Ii as Secrets,_g as SecretsManager,V as SecretsManagerClient,Bg as SecretsRotationManager,I as Security,$r as SecurityHubManager,qr as SecurityPostureStore,mt as SecurityScannerRunner,Og as SecurityScanningManager,Xg as SenderReputationManager,Nm as ServerCronJobAdapter,jo as ServerDataAdapter,Os as ServerPathVolumeDriver,Fg as ServiceMeshManager,yd as Sftp,qs as SignalSource,pA as SmsAdvanced,vt as SmsClient,Df as SmsHandlers,Fa as SmsVoiceClient,Do as SourceConnectionStore,Vt as SourceProviderError,Zc as SpendCapError,Pr as SpendGate,_p as SpendLoopLease,Ws as SpendNotificationRouter,xp as SpendRunner,$t as SpendService,oi as SpendStore,tA as Spinner,hr as SshDriver,Wr as SshFleetDriver,mg as StackDependencyManager,Zy as StacksIntegration,am as StaticSiteManager,ve as Storage,cm as StorageAdvancedManager,mn as SupportClient,Mr as SyntheticsManager,wl as SystemFleetSshTransport,mr as SystemSshTransport,$o as SystemdDiscoveryAdapter,uo as TRACE_HEADER,rA as TaskList,lt as TelemetryStore,md as TemplateBuilder,eg as TemplateCache,bt as TextractClient,dn as TranscribeClient,Yt as TranslateClient,$m as TransportDisasterRecoveryDriver,Lm as TransportPlatformMaintenanceDriver,Fi as TransportRemoteBuildDriver,xo as TrivyImageScanner,wo as TsCloudApiError,Xd as TsCloudClient,Af as URGENT_SPEND_EVENTS,Ep as USER_VISIBLE_ACTIONS,ia as UnavailableRegionalDriver,oe as UnifiedDnsValidator,Ds as UnsupportedSchemaVersionError,Xp as ValidationError,tr as VoiceClient,xs as VolumeService,xt as VolumeStore,Pf as Workflow,Tg as XRayManager,bC as abTestManager,Yd as activateImmutableRelease,mu as addDns01ChallengeRecord,Xr as addSiteToCloudConfig,ft as ageSeconds,Qc as aggregateDeltas,pp as allocateSitePorts,Jy as analyzeStackDiff,di as anomalyOptionsForSignal,Io as applyControlsToDdos,Ud as applyControlsToRateLimits,ds as applyDeclaredZoneSettings,_r as applyMitigationFactor,Nh as applyPlan,gs as applyZoneMigration,vd as artifactKey,xr as assertOriginGroupMethods,ki as assertReleaseStrategy,gf as assertSpendAllows,Oh as attachConflicts,Lh as attachIsViable,xh as attachPreconditions,pl as attachProvenanceToRelease,Oo as attachSbomToRelease,ll as attachVulnerabilitySummary,hm as authEncryptionKeyFile,w as authorizeOrganization,Dm as authorizeRuntimePath,vS as autocomplete,AC as awsConfigManager,Kl as backupCredentialStatus,hC as backupManager,GI as batch,rE as batchProcessingManager,vo as beginOidcAuthorization,CC as blueGreenManager,JC as bounceComplaintHandler,ct as budgetWindow,Da as buildAndPushServerlessImage,sE as buildBunRuntimeLayerZip,Hh as buildCertificatePackScript,Fh as buildCertificateStateScript,Gh as buildCertificateUnpackScript,Sd as buildCloudFormationTemplate,oc as buildCloudInitFirstBoot,kc as buildComposeLogsCommand,Py as buildComposeRuntimeCommand,Ny as buildComposeScaleCommand,Bc as buildComposeShellCommand,dp as buildDrainSourceScript,Ch as buildDrainedSiteScanScript,Wt as buildFunctionEnv,cp as buildHealthGateScript,Kn as buildHostCleanupScript,ti as buildHostSitePortsScript,gd as buildMailEnv,vs as buildManagementDashboardArtifact,Lu as buildMediaCdnPlan,pu as buildMtaStsPolicy,sh as buildMtaStsServer,iE as buildNodeRuntimeLayerZip,MC as buildOptimizationManager,jp as buildOriginGroup,yi as buildOriginGroups,Qa as buildOriginGuardRule,tp as buildPauseWorkersScript,dE as buildPhpRuntimeLayerZip,sp as buildRestoreScript,K as buildRpxConfig,xe as buildRpxFragmentRefreshScript,Bh as buildSetHostnameScript,Vn as buildSiteDeployScript,ip as buildSnapshotScript,lp as buildSourceStateScript,Rn as buildSshArgs,kn as buildSshBootstrapScript,Ua as buildStaticSiteCacheRules,jn as buildStaticSiteDeployScript,op as buildTargetStateScript,rp as buildWorkersStateScript,ml as bytes,EC as canaryManager,Jr as canonicalJson,ht as capabilities,Kt as capacity,YI as categorizeChanges,OC as certificateManager,Qh as certificatesMatch,BI as checkIAMPermissions,EA as checkInvocation,xI as checkServiceQuotas,Yf as chunk,Km as cleanupDns01Challenge,Ly as clearSigningKeyCache,No as cloneSourceBinding,tS as cloudConfigSchema,xu as cloudDrivers,yC as cloudTrailManager,pc as collectAssets,mo as collectPhpAppEntries,lu as collectServerDnsDomains,fp as completeComposeVolumeDeletion,To as completeOidcAuthorization,II as composePresets,Ns as composeProjectName,wd as composeServerlessAppTemplate,Sf as compositeSpendTransport,St as compressBackup,BA as config,bl as connectionGuidance,FC as containerRegistryManager,zh as controlPlaneDatabaseFile,vc as controlPlaneMigrations,oI as createApiBackendPreset,_o as createApiV1Handler,QA as createAsgBuildDriver,Wl as createBackupQueueHandlers,RA as createCliHandler,k as createCloudDriver,nc as createCloudFrontPolicy,RI as createCredentialProvider,fI as createDashboardSite,uI as createDataPipelinePreset,vl as createDataServiceQueueHandlers,_c as createDeploymentQueueHandlers,T as createDnsProvider,UA as createEcsBuildDriver,ed as createEnforcementHandlers,Yp as createError,Cd as createExistingStaticFullStackPreset,Rl as createFleetQueueHandlers,sI as createFullStackAppPreset,fs as createGoDaddyValidator,cE as createHandlers,TA as createHttpHandler,cI as createJamstackPreset,El as createJobQueueHandlers,mI as createLaravelPreset,pI as createMLApiPreset,xl as createMaintenanceQueueHandlers,vu as createMediaAccessToken,dI as createMicroservicesPreset,aS as createMockAWS,rI as createNodeJsServerPreset,nI as createNodeJsServerlessPreset,rs as createObjectStorageClient,hs as createPorkbunValidator,SI as createPreset,Ef as createPresignedUrl,ky as createPresignedUrlAsync,wA as createQueueHandler,lI as createRealtimeAppPreset,Pl as createRegionQueueHandlers,ul as createReleaseProvenance,el as createReleaseQueueHandlers,MA as createRemoteBuildQueueHandlers,As as createRoute53Validator,Rm as createRuntimeAdapters,DI as createS3Client,FA as createServerBuildDriver,hI as createServerlessLaravelPreset,iI as createServerlessNodePreset,cu as createSmsInfrastructure,Ke as createSourceAdapter,tI as createStaticSitePreset,gI as createTraditionalWebAppPreset,xc as createVolumeQueueHandlers,aI as createWordPressPreset,Ei as createZip,BS as crossRegionReferenceManager,nn as dashboardActions,bs as dashboardCredentialsFile,Kr as dataServiceCapabilities,BC as databaseUserManager,Hd as decodeBase32,Ne as decompressBackup,zm as decryptBackup,So as defaultConfig,ng as defaultLocalConfig,$d as defaultRateLimitRules,sr as delegateZone,as as delegateZoneFromConfig,wa as deleteStaticSite,Ac as deployAllComputeSites,da as deployServerlessApp,Vl as deploySite,Ts as deploySiteRelease,Wi as deployStaticSite,Ra as deployStaticSiteFull,sn as deployStaticSiteWithExternalDns,on as deployStaticSiteWithExternalDnsFull,ud as deploymentCoexistenceError,xf as deriveManagementDashboardPort,cs as describeDelegation,Fd as describePosture,ls as describeZoneSettings,Pm as desiredJobProviderState,Tp as detectAnomalies,Gp as detectDeploymentTargets,Ha as detectDnsProvider,Wc as detectLatestAnomaly,NI as detectMisconfigurations,Fp as detectServiceRegion,Pc as diffCompose,WI as diffTemplates,Po as discoverGitRefs,bo as discoverOidcProvider,hl as discoverRuntimeInventory,tE as dlqMonitoringManager,Ga as dnsProviders,KC as dnssecManager,vm as dockerWorkloads,Ui as documentDigest,fC as drManager,Le as driverStatePath,fl as ecsWorkloads,_t as effectiveCapabilities,XC as emailAnalyticsManager,ZC as emailTemplateManager,Di as encodeBase32,jm as encryptBackup,gl as ensureDefaultSecurityPolicies,Qn as ensureFirewall,Wn as ensureManagementDashboard,Hn as ensureServer,Un as ensureSshKey,J as escapeSecLang,Gc as evaluateBudget,On as evaluatePreflight,Ks as evaluateTelemetryAlertRules,Cl as eventBridgeScheduleInput,vA as eventToRequest,lf as ewma,Dc as exportCompose,us as exportRoute53Zone,Jp as extendPreset,eE as fifoQueueManager,HI as findChangedFiles,yp as findMapping,Ap as findPriceEntry,ZS as formatAccountStructure,$h as formatAttachPlan,fS as formatBytes,kr as formatCents,Xy as formatDiff,bh as formatDrainedSiteRefusal,AS as formatDuration,wS as formatFlagSuggestions,PS as formatHistory,NS as formatHistoryStats,Rh as formatInventory,IS as formatKeyValue,yS as formatList,Ph as formatPlan,$n as formatPreflightFindings,hS as formatProgressBar,aA as formatRegion,qS as formatRegionList,Sm as formatScanResults,SS as formatSuggestion,gS as formatTable,Rr as formatTimeToExhaustion,mS as formatTree,Ff as fromEC2Metadata,Uf as fromECSMetadata,$f as fromEnvironment,Mf as fromSharedCredentials,Qf as fromWebIdentity,Dd as functionFingerprint,Tn as gatewayHostnames,Rd as generateAppImageDockerfile,gC as generateApprovalConfig,gA as generateBootstrap,lS as generateCleanupWorkflow,uS as generateCostReportWorkflow,XS as generateCrossAccountRoleCF,cl as generateCycloneDxSbom,lC as generateDeploymentConfig,sC as generateDeploymentPipeline,eC as generateDeploymentWorkflow,Ta as generateExternalDnsStaticSiteTemplate,Gm as generateHttpsServerCode,dl as generateImageSbom,Hm as generateLetsEncryptUserData,t as generateLogicalId,dC as generateManualPipeline,iC as generateMatrixWorkflow,uC as generateMultiEnvConfig,oC as generateMultiEnvPipeline,tC as generateMultiEnvWorkflow,rC as generatePRPreviewWorkflow,mC as generateParallelConfig,DA as generatePhpFpmConfig,yA as generatePhpLayerDockerfile,aC as generatePreviewPipeline,dS as generatePreviewWorkflow,r as generateResourceName,pC as generateScheduledConfig,cC as generateScheduledPipeline,nC as generateScheduledWorkflow,Ki as generateStaticSiteTemplate,N as generateUbuntuAppCloudInit,qf as getAccountId,LS as getAllRegions,QS as getClosestRegion,RS as getCommandUsage,Kh as getComposeTemplate,pm as getConfig,ES as getContextualHelp,no as getCredentials,ZI as getDeploymentStrategy,eS as getDiffStats,JI as getDiffSummary,Kf as getErrorDetails,bd as getLocalConfig,sS as getLocalCredentials,iS as getLocalEndpoint,oS as getLocalEnvVars,OI as getQuotaUsageSummary,JS as getRecommendedStructure,Ci as getRegion,VS as getRegionStats,MS as getRegionsByCompliance,$S as getRegionsByLocation,FS as getRegionsByPricingTier,Wf as getRequiredPermissions,$y as getSigningKeyCacheSize,au as getSmsInfrastructureStatus,Gy as getTimestamp,ho as globMatches,ws as globToRegex,_S as globalResourceManager,ai as governingLimitCents,IC as guardDutyManager,Js as handleSpendRequest,vn as hasAutoWwwVariant,Ht as hasManagementDashboardSite,bc as hasProxyUpstream,MI as hashBuffer,FI as hashDirectory,tg as hashFile,UI as hashManifest,rg as hashString,pE as healthCheckManager,Sn as hostAcceptsIpv6,fn as hostCondition,Co as hotp,wr as hourBucket,df as hourBucketsBetween,$C as imageScanningManager,Gi as infraEnvFromOutputs,Nd as inspectInvocation,SA as installRecursionFetch,Xi as invalidateCache,sm as invocationContext,CS as isLikelyTypo,En as isLocalDatabase,nS as isLocalDevelopment,Or as isManagementDashboardSiteName,nr as isNameserverRegistrar,My as isNodeCryptoAvailable,Kc as isOperationAllowed,zs as isQuietHours,Ad as isS3RestEndpoint,Xn as isSafePattern,dd as isStateDirConfigured,ld as isStatePath,Br as isValidCidr,US as isValidRegion,si as isValidTimeZone,Fy as isWebCryptoAvailable,ir as isZoneHost,zr as jobProviderCapability,ts as keyMatchesFilters,GC as lambdaConcurrencyManager,jC as lambdaDLQManager,qC as lambdaDestinationsManager,QC as lambdaLayersManager,VC as lambdaVPCManager,HC as lambdaVersionsManager,Al as lambdaWorkloads,_d as laravelServerlessEnvDefaults,Er as listComposeTemplates,_i as listSourceReferences,Qd as loadCloudConfig,Mt as loadTelemetryPolicy,RC as logsManager,Jc as lookbackHoursForSignal,vf as mailEnabled,pd as mailFirewallPorts,Om as maintenanceWindowOpen,bf as makeAWSRequest,_y as makeAWSRequestAsync,By as makeAWSRequestOnce,Wp as managementDashboardSiteName,Nl as manifestDigest,Ur as matchTotpCounter,ku as mediaObjectHeaders,Qs as median,bp as medianAbsoluteDeviation,qc as mergeDecisions,Lr as mergeInfrastructure,af as mergePriceBooks,Uc as meterTelemetry,wC as metricsManager,nu as migrateObjectStorage,PC as migrationManager,jS as multiAccountManager,kS as multiRegionManager,Zm as needsRenewal,gE as networkSecurityManager,At as nextScheduleRuns,ye as normalizePublicIpv6,Re as normalizeRuntimeStatus,We as normalizeScheduleExpression,ym as normalizeSourceEvent,Oe as normalizeSshPublicKey,Np as normalizeTelemetryPolicy,ei as occupiedHostPorts,Bo as openApiDocument,Vs as optionsForSignal,zS as organizationManager,xd as packagePhpApp,Fr as packageServerlessApp,uc as pagesAssetHash,Iu as pagesDnsRecord,Ed as parallel,qI as parallelMap,VI as parallelWithRetry,Uh as parseCertificateState,Pd as parseChain,Cr as parseCompose,Ry as parseComposeCatalog,bm as parseDockerInspect,Yl as parseDotenv,Eh as parseDrainedSites,ri as parseHostSiteFragments,Oy as parseJSONResponse,xn as parsePreflightFacts,up as parseSourceDrained,Tm as parseSystemdRecords,ap as parseTargetReady,Ec as parseUpstreamPort,np as parseWorkersPaused,xy as parseXMLResponse,gi as pathTemplate,Sc as pendingSteps,Us as percentOfLimit,kC as performanceManager,nm as phpLayerBuildStage,AA as phpLayerPackages,vi as phpRuntimeLayerAssets,Dy as planComposeTemplateUpgrade,Vc as planEnforcement,Zu as planIsDestructive,Mp as planMitigation,kh as planServerRename,qh as planSiteMove,ps as planZoneMigration,Tt as policyTag,Ln as preflightFailed,cS as previewManager,pS as previewNotifications,yt as previewSchedule,cf as previousBudgetWindow,$s as priceUsage,sf as priceUsageLines,Th as probeHostRoutes,ys as probeOriginTls,KI as processInChunks,sl as processSourceWebhook,Li as productionChangeReview,vC as progressiveDeploymentManager,Hc as projectSpend,kd as propagationHeaders,Pa as providerEndpoint,kl as publicKeyFingerprint,An as qualifyName,nE as queueManagementManager,QI as quickHash,Ld as rateLimitHeaders,wi as rateLimitKey,$e as readDriverState,wh as reconcile,uu as reconcileAddressRecords,bu as reconcileCloudflareCdn,os as reconcileDeclaredRecords,$A as reconcileJobObservation,Gr as reconcileSourceWebhook,Oi as recordDashboardHostPosture,xA as recordPreDeploySecretScan,OA as recordSkippedSecretScan,Bd as recursionBlockedResponse,De as redactRuntimeConfig,nd as redactTelemetryText,pi as redactTelemetryValue,Zr as redeployServerlessApp,xS as regionPairManager,Hr as releaseStrategyCapabilities,fm as releaseTrafficPlan,Jn as reloadRpxGateway,es as remapKey,fu as removeDns01ChallengeRecord,Yr as removeSiteFromCloudConfig,ol as removeSourceWebhook,qa as removeStaleServerAddressRecords,Nc as renderComposeTemplate,fi as renderDdosInstallScript,ad as renderNftablesRuleset,$i as renderServerCron,od as renderSysctlFile,Ic as renderWafConfig,Yn as renderWafInstallScript,yc as renewRpxCertificates,NC as replicaManager,Cf as requestHash,XI as requiresReplacement,oE as resetRecursionRuntime,aE as resolveApp,p as resolveAppDatabase,_h as resolveAttachTarget,ze as resolveAuthEncryptionKey,le as resolveCloudProvider,Pu as resolveCloudflareCdnPlan,Hf as resolveCredentials,zi as resolveDashboardAction,fc as resolveDashboardAuth,Of as resolveDashboardDomain,Lf as resolveDashboardDomains,ss as resolveDeclaredRecords,Wy as resolveDeployBucketName,O as resolveDeploymentMode,qn as resolveExecStart,wf as resolveFailoverStatusCodes,Za as resolveHetznerApiToken,Ai as resolveMailService,yI as resolveManagementDashboardSite,Si as resolveManagementDashboardSites,Na as resolveObjectStorage,Dh as resolvePlan,g as resolveProjectStackName,Sr as resolveProxyUpstreams,Td as resolveQueueNames,Jh as resolveQueuedDeploymentCommand,qt as resolveQueues,IA as resolveRecursionConfig,Gf as resolveRegion,re as resolveRuntimeInventory,Ft as resolveServerlessAppStackName,hd as resolveServerlessArtifactBucketName,Zs as resolveServerlessAssetBucketName,ao as resolveServerlessRuntime,zy as resolveSiteBucketName,Rs as resolveSiteDeployTarget,u as resolveSiteKind,jy as resolveSiteResourceName,Vy as resolveSiteStackName,Bn as resolveSshSettings,d as resolveStatePath,Ky as resolveStorageBucketName,Nt as resolveUiSource,lc as resolveZoneApex,mE as resourceManagementManager,om as responseToResult,vp as robustZScore,Bt as roleCapabilities,Zd as rollbackImmutableRelease,en as rollbackServerlessApp,of as roundCents,WC as route53ResolverManager,zC as route53RoutingManager,Rp as routeMatches,Ju as routesFromFragments,Ti as ruleMatches,mA as runBuildHooks,jc as runEnforcement,go as runPhpBuildHooks,Je as runRemoteCommand,pe as runtimeId,yn as sameNameservers,ji as sanitizeCloudConfig,s as sanitizeControlPlaneValue,qy as sanitizeName,zd as sanitizeOidcReturnPath,td as saveTelemetryPolicy,Im as scanForSecrets,Tc as scopeContains,dt as scopeKey,Wa as scpUpload,bS as searchCommands,Ps as searchControlPlane,xC as secretsManager,_C as secretsRotationManager,LA as secureContainerRelease,SC as securityHubManager,LC as securityScanningManager,te as securityScope,Qr as sendAuthenticationEmail,YC as senderReputationManager,jI as sequence,Zl as serializeDotenv,Gn as serverPublicIpv4,UC as serviceMeshManager,Ql as setAttachToInCloudConfig,Jt as setMaintenance,Qi as setSitePropertyInCloudConfig,cd as setStateDir,Um as setupDns01Challenge,Ma as setupSmsInfrastructure,oo as sha256,CA as sharedRecursionGuard,im as sharedRuntimeLoop,mp as shipsARelease,Ou as signCloudFrontCookies,Eu as signCloudFrontUrl,_ as signRequest,Up as signRequestAsync,Gs as signalDefinition,B as siteInstallBase,Zn as siteMoveArchivePath,Mh as siteMoveCertArchivePath,Cc as siteUnitGlob,Bp as spendNotificationText,Xs as spendOpenApiPaths,pr as sshExec,ce as sshExecOrThrow,OS as stackDependencyManager,va as startLocalDashboardServer,If as startSpendLoop,Ys as stateDir,x as statePath,lE as staticSiteManager,uE as storageAdvancedManager,uf as streamFocusJsonl,zc as strongestActiveAction,dg as suggestCommand,TS as suggestFlags,_I as suggestIAMPolicy,LI as suggestQuotaIncrease,GS as suggestRegionPairs,HS as suggestRegions,Bi as syncSourceRepositories,Oc as synchronizeComposeVolumes,eu as synchronizeConfiguredConfiguration,Uo as synchronizeConfiguredJobs,DC as syntheticsManager,sd as sysctlHardening,wm as systemdWorkloads,ff as telemetryBucketLabel,mi as telemetryCursor,rd as telemetryEstimatedMonthlyCost,hf as telemetryPercentile,kp as telemetryPolicyKey,$I as templateCache,Xu as tenantsOf,ko as testSourceConnection,Lc as tieredMicroCents,ns as toCloudflareZoneSettings,js as toFocusJsonl,Xc as toFocusRecords,vh as toInventoryServer,gm as totp,Eo as totpUri,Yu as unaccountedSites,Em as unsupportedCapabilities,Xh as unsupportedVolumeCapabilities,_l as updateCompatibility,Ol as updateSiteInCloudConfig,Ji as uploadStaticFiles,Ip as usageDeltaKey,Lt as utcInstantOfLocal,YS as validateAccountStructure,rS as validateAgainstSchema,Zh as validateAttachment,Vm as validateBackupDestination,DS as validateCommand,PI as validateConfiguration,kI as validateCredentials,gp as validateDeploymentConfig,Yh as validateMountPath,Md as validateResourceLimits,ep as validateServerName,Hl as validateTemplate,ql as validateTemplateSize,ja as verifyAddressRecord,_A as verifyArtifactSignature,Nu as verifyMediaAccessToken,mm as verifyTotp,Bl as verifyUpdateSignature,ms as verifyZoneParity,_s as volumeCapabilities,ju as wafEventTelemetry,Ja as waitForCloudInit,Dn as waitForSsh,jt as webhookEndpoint,TI as withCDN,vI as withCache,bI as withDatabase,bA as withInvocation,CI as withMonitoring,wI as withQueue,EI as withSecurity,zI as withTimeout,W as wrapCloudInitUserData,nt as writeDriverState,TC as xrayManager,Dl as zeroCapacity,pf as zeroFill,Mc as zoneOffsetMs,Ms as zonedParts};
|