@stacksjs/ts-cloud 0.12.15 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aws/index.js +1 -1
- package/dist/bin/{chunk-9e22a51n.js → chunk-22c3pk8s.js} +78 -78
- package/dist/bin/chunk-2synp9gh.js +1 -0
- package/dist/bin/{chunk-ejqhbj1h.js → chunk-2v0qm547.js} +1 -1
- package/dist/bin/chunk-4qzpqmhe.js +1 -0
- package/dist/bin/chunk-5n3ejway.js +1 -0
- package/dist/bin/{chunk-ynr22ma8.js → chunk-7jwxgxxf.js} +1 -1
- package/dist/bin/{chunk-gd4w6bht.js → chunk-8bbw6qc2.js} +1 -1
- package/dist/bin/{chunk-7a7n6p2m.js → chunk-9jmnmhpy.js} +1 -1
- package/dist/bin/{chunk-pt2bz3kr.js → chunk-9qndhwbe.js} +1 -1
- package/dist/bin/chunk-9yra64dd.js +1 -0
- package/dist/bin/{chunk-ng0949x3.js → chunk-b48j6k55.js} +1 -1
- package/dist/bin/{chunk-r1w08y38.js → chunk-bdgkeqv6.js} +1 -1
- package/dist/bin/chunk-c82rh7qe.js +1 -0
- package/dist/bin/{chunk-zzsdhhmb.js → chunk-d4bb9qg9.js} +1 -1
- package/dist/bin/{chunk-pcyywgx7.js → chunk-d6kqbp8q.js} +1 -1
- package/dist/bin/{chunk-swete552.js → chunk-dk38j1qr.js} +9 -9
- package/dist/bin/{chunk-x42gb7pq.js → chunk-e1cxh9rj.js} +2 -2
- package/dist/bin/{chunk-9k60q9qz.js → chunk-edaq5jef.js} +3 -3
- package/dist/bin/chunk-fbe5kk6w.js +1 -0
- package/dist/bin/{chunk-n7eq4t9a.js → chunk-fbycbnvj.js} +4 -4
- package/dist/bin/chunk-fj89173b.js +1 -0
- package/dist/bin/{chunk-8tbj9h2a.js → chunk-gxwsq3k0.js} +40 -40
- package/dist/bin/{chunk-kc2e193t.js → chunk-hwp5xp1c.js} +63 -63
- package/dist/bin/chunk-j3w462ep.js +1 -0
- package/dist/bin/chunk-k2zzny51.js +1 -0
- package/dist/bin/{chunk-80zkjpfz.js → chunk-k3er0h4j.js} +1 -1
- package/dist/bin/chunk-kjatss6s.js +1 -0
- package/dist/bin/{chunk-w5hzt11d.js → chunk-kxa4t4wh.js} +2 -2
- package/dist/bin/{chunk-raj6j2j5.js → chunk-m5sjzxm3.js} +1 -1
- package/dist/bin/{chunk-dhxwmkhz.js → chunk-mcqkjhgp.js} +1 -1
- package/dist/bin/{chunk-77qpn2m8.js → chunk-n56c0j1e.js} +4 -4
- package/dist/bin/chunk-ntahmgqg.js +1 -0
- package/dist/bin/{chunk-57w9nsjk.js → chunk-p197a99s.js} +1 -1
- package/dist/bin/{chunk-vymg9ywg.js → chunk-pd8v6bpd.js} +1 -1
- package/dist/bin/{chunk-yhxpmk29.js → chunk-pthfzst7.js} +1 -1
- package/dist/bin/{chunk-5tsxt28g.js → chunk-ptt8me4h.js} +2 -2
- package/dist/bin/{chunk-7xvm2ygt.js → chunk-qmqmnxmm.js} +3 -3
- package/dist/bin/{chunk-r1vtnn8w.js → chunk-rzt92fwv.js} +3 -3
- package/dist/bin/chunk-t1eft7s7.js +1 -0
- package/dist/bin/{chunk-49sthm4q.js → chunk-t7seq21w.js} +1 -1
- package/dist/bin/chunk-t8n2961n.js +1 -0
- package/dist/bin/{chunk-vesvsvdy.js → chunk-vwzgtsn9.js} +1 -1
- package/dist/bin/{chunk-s1j941z1.js → chunk-w0g72e50.js} +1 -1
- package/dist/bin/chunk-wb8y7zey.js +1 -0
- package/dist/bin/{chunk-n8cwx54p.js → chunk-x4gsw45d.js} +5 -5
- package/dist/bin/{chunk-yx1qgp1q.js → chunk-xs62dg7t.js} +2 -2
- package/dist/bin/chunk-xtp2zf3j.js +1 -0
- package/dist/bin/chunk-xvn07b0e.js +1 -0
- package/dist/bin/{chunk-sdwr2tnp.js → chunk-xw9vcdwt.js} +1 -1
- package/dist/bin/{chunk-4zbnwt9b.js → chunk-y1r1evt0.js} +1 -1
- package/dist/bin/{chunk-c51xp8f7.js → chunk-zs8bfer0.js} +1 -1
- package/dist/bin/cli.js +98 -98
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/chunk-05qawkra.js +1 -0
- package/dist/{chunk-jb8em9ba.js → chunk-0g2jkhy5.js} +1 -1
- package/dist/chunk-1jx53q5e.js +1 -0
- package/dist/{chunk-30h9rgfn.js → chunk-2s65yj3g.js} +4 -4
- package/dist/{chunk-x07tpsv0.js → chunk-3k60wm30.js} +5 -5
- package/dist/chunk-3qtce4mm.js +1 -0
- package/dist/chunk-3tt5em2c.js +1 -0
- package/dist/{chunk-hw3p6pth.js → chunk-42kv07cs.js} +1 -1
- package/dist/{chunk-wjgnfg6q.js → chunk-65ajja2a.js} +1 -1
- package/dist/{chunk-yq3pdbz7.js → chunk-6gtqjsg9.js} +3 -3
- package/dist/{chunk-6g81m01r.js → chunk-8s9m8pyb.js} +1 -1
- package/dist/{chunk-gd9g0v9w.js → chunk-asmv4fw1.js} +19 -19
- package/dist/{chunk-83p688yv.js → chunk-ds92qg3g.js} +4 -4
- package/dist/{chunk-6nvn041c.js → chunk-dzqz1sm0.js} +3 -3
- package/dist/{chunk-88nxsyry.js → chunk-hyj2ymp1.js} +6 -6
- package/dist/chunk-j4ed179k.js +2 -0
- package/dist/{chunk-g9mnmddy.js → chunk-m5r0dt28.js} +2 -2
- package/dist/{chunk-zftpjxkr.js → chunk-mcfdtg5w.js} +1 -1
- package/dist/{chunk-cy6qh4ea.js → chunk-ngdhqwf3.js} +3 -3
- package/dist/{chunk-6znnde1s.js → chunk-nhtz2k8d.js} +5 -5
- package/dist/{chunk-rbem58rx.js → chunk-nw0tvrrr.js} +1 -1
- package/dist/{chunk-hnkw6pde.js → chunk-p9fqsz06.js} +2 -2
- package/dist/{chunk-qzwack6w.js → chunk-r4dpn715.js} +7 -7
- package/dist/{chunk-678rwkz8.js → chunk-vk513ge7.js} +89 -89
- package/dist/{chunk-w495x89g.js → chunk-w5fmaaxa.js} +4 -4
- package/dist/chunk-wr7tn9j5.js +1 -0
- package/dist/{chunk-a6k322xc.js → chunk-xqx5szta.js} +30 -30
- package/dist/{chunk-jvqcw0b4.js → chunk-y13zcbnp.js} +101 -101
- package/dist/{chunk-2knc1zyy.js → chunk-ycs26jsj.js} +124 -124
- package/dist/{chunk-r5emv4x8.js → chunk-z7v4evbh.js} +2 -2
- package/dist/deploy/index.js +1 -1
- package/dist/dns/delegate-from-config.d.ts +50 -0
- package/dist/dns/delegate-from-config.test.d.ts +1 -0
- package/dist/dns/delegation.d.ts +110 -0
- package/dist/dns/delegation.test.d.ts +1 -0
- package/dist/dns/index.d.ts +4 -0
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/rpx-gateway.d.ts +17 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +49 -49
- 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 +5 -5
- 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 +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +5 -5
- package/dist/ui/infrastructure/topology.html +6 -6
- package/dist/ui/integrations.html +1 -1
- package/dist/ui/operations/alerts.html +5 -5
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +6 -6
- package/dist/ui/operations/maintenance.html +5 -5
- package/dist/ui/operations/observability.html +6 -6
- package/dist/ui/operations/previews.html +6 -6
- package/dist/ui/operations/queue.html +6 -6
- package/dist/ui/operations/regions.html +5 -5
- package/dist/ui/operations/releases.html +6 -6
- package/dist/ui/operations/spend.html +6 -6
- package/dist/ui/operations/workloads.html +6 -6
- package/dist/ui/security.html +2 -2
- package/dist/ui/server/actions.html +5 -5
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +6 -6
- package/dist/ui/server/database.html +5 -5
- package/dist/ui/server/deployments.html +5 -5
- package/dist/ui/server/diagnostics.html +2 -2
- package/dist/ui/server/firewall.html +6 -6
- package/dist/ui/server/fleet.html +6 -6
- package/dist/ui/server/logs.html +6 -6
- package/dist/ui/server/metrics.html +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 +2 -2
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +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 +6 -6
- package/dist/ui-src/src/charts.ts +1 -1
- package/dist/ui-src/src/topology.ts +1 -1
- package/package.json +3 -3
- package/dist/bin/chunk-1s4dny8d.js +0 -1
- package/dist/bin/chunk-4w80w3sm.js +0 -1
- package/dist/bin/chunk-4yntpqbe.js +0 -1
- package/dist/bin/chunk-7x0hrna6.js +0 -1
- package/dist/bin/chunk-971tfc6m.js +0 -1
- package/dist/bin/chunk-dpw8x3sr.js +0 -1
- package/dist/bin/chunk-h785hw6a.js +0 -1
- package/dist/bin/chunk-jyggrdh2.js +0 -1
- package/dist/bin/chunk-q524s7cx.js +0 -1
- package/dist/bin/chunk-q9gpw6wv.js +0 -1
- package/dist/bin/chunk-r6cvc2pr.js +0 -1
- package/dist/bin/chunk-rh2sqtew.js +0 -1
- package/dist/bin/chunk-tkzpbb7n.js +0 -1
- package/dist/bin/chunk-v78r5tx0.js +0 -1
- package/dist/bin/chunk-v7f4c62s.js +0 -1
- package/dist/bin/chunk-vx649y7t.js +0 -1
- package/dist/chunk-6t9tjvpy.js +0 -2
- package/dist/chunk-9w32efae.js +0 -1
- package/dist/chunk-atny1wp9.js +0 -1
- package/dist/chunk-fdexq9e1.js +0 -1
- package/dist/chunk-hn2v0b0d.js +0 -1
- package/dist/chunk-v46b25w9.js +0 -1
- /package/dist/bin/{chunk-bckm6fre.js → chunk-pdw0qjq1.js} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import{Sp,x,Cp,rf,uy,nf,py,gy,my,hy,fy,Ay,yy,Iy,Sy,Cy,bp,Ep,Wc,Jc,Qs,_,d,Xc,vp,O,Yc,p,sf,ui,Zc,ed,ce,td,by,r,t,Ey,vy,g,Ty,wy,Ry,Dy,Py,Mt,rd,Hs,of,Ny,ky,Se,Fe,Ce,L,I,o,A,Ue,m,af,Qe,M,ct,By,cf,F,nd,be,Ft,Gs,X,id,Y,df,qs,U,Q,D,pi,E,Ut,dt,H,e,Vs,xy,Tp,sd,_y,Oy,Ly,$y,od,My,Fy,Uy,Qy,Hy,Gy,qy,Vy,jy,zy,Ky,Wy,lf,uf,pf,gf,mf,hf,ff,Qt,wp,Rp,Nr,gi,Jy,Dp,Xy,Yy,kr,Zy,eI,tI,rI,nI,iI,Af,yf,If,Sf,Cf,js,sI,bf,Ef,vf,G,oI,He,zs,Ht,Tf,Pp,wf,Rf,Df,Np,Z,aI,cI,dI,lI,Pf,uI,q,pI,gI,mI,kp,Bp,hI,xp,_p,fI,yI,II,SI,CI,Nf,ad,bI,EI,vI,TI,wI,kf,Bf,RI,DI,PI,NI,kI,BI,xI,_I,OI,Op,cd,LI,$I,MI,FI,Lp,$p,Mp,UI,Fp,QI,HI,GI,qI,Up,VI,jI,zI,KI,WI,JI,XI,YI,xf,_f,Of,Lf,Qp,ZI,eS,tS,rS,nS,iS,sS,oS,aS,$f,Mf,Ff,Uf,cS,dS,Hp,lS,Gp,qp,Vp,jp,uS,pS,gS,mS,Ee,mi,hS,fS,AS,yS,IS,SS,CS,bS,Qf,ES,vS,zp,Kp,TS,wS,Hf,RS,DS,PS,NS,kS,BS,xS,_S,OS,LS,$S,MS,FS,US,QS,HS,GS,qS,VS,jS,zS,Wp,KS,Jp,WS,Xp,JS,Yp,XS,Zp,YS,Br,ZS,eg,eC,Ks,tC,tg,rC,rg,nC,ng,iC,ig,sC,sg,oC,xr,aC,og,cC,ag,dC,cg,lC,dg,uC,lg,pC,ug,gC,pg,mC,gg,hC,mg,fC,hg,AC,fg,yC,Ag,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,Gf,qf,Vf,jf,kg,xC,Bg,_C,xg,OC,_g,LC,hi,zf,Kf,Ws,dd,_r,Wf,Js,Gt,ld,ud,Jf,Xf,Og,Yf,pd,Lg,$C,MC,Xs,Ys,Zs,gd,fi,md,hd,eo,fd,Ad,$g,Zf,eA,tA,FC,rA,nA,UC,iA,Mg,sA,oA,aA,QC,cA,Ai,yd,dA,HC,lA,to,ro,Id,Fg,GC,Ug,qC,Qg,VC,Hg,jC,Gg,zC}from"./chunk-jvqcw0b4.js";import{co,qg,wd,pA,Ci,Rd,lo,Vg,jg,Or,uo,Dd,Ge,Pd,Nd,kd,bi,Lr,zg,qe,Bd,po,go,mo,xd,_d,Od,Ei,ho,Ld,$r,vi,fo,lt,Kg,$d,Md,Wg,Fd,Ao,qt,Ud,Qd,Hd,Gd,Ve,Jg,qd,Vt,yo,Io,So,Ti,wi,Mr,Vd,Ri,Co,bo,Fr,jd,Ur,Xg,Yg,ut,Qr,Eo,Zg,zd,Kd,vo,Wd,Jd,Xd,gA,ee,Yd,mA,hA,Di,Pi,fA,de,em,pt,ve,Te,gt,Zd,el,tl,rl,tm,rm,To,nm,im,wo,nl,il,sm,te,om,sl,le,Ro,je,mt,ht,Hr,Ni,ol,AA,Do,am,cm,dm,lm,Po,No,al,Gr,ko,cl,ki,dl,Bo,xo,_o,Oo,Lo,$o,Mo,Fo,ll,jt,Uo,ul,qr,pl,Qo,Ho,gl,zt,Go,qo,um,yA,Bi,IA,SA,CA,Vo,jo,ml,pm,zo,Vr,hl,xi,fl,Al,yl,Ko,gm,Wo,Il,mm,Jo,hm,jr,zr,Sl,_i,wl,Nl,Li,Kt,Yo,Kr,Wr,Wt,ze,Em,ea,vm,Tm,xl,ta,Mi,_l,ra,At,Re,Ol,na,ia,Ll,sa,oa,aa,ca,$l,Ml,Xr,da,la,ua,pa,Fl,Fi,Yr,Ui,ga}from"./chunk-2knc1zyy.js";import{B,fr,lc,fs,u,Ku,Wu}from"./chunk-g9mnmddy.js";import{nt,dc,Kn,Wn,Jn,zu}from"./chunk-83p688yv.js";import{rh,nh,ih,Du,Pu,Nu,sh,ku,Bu,oh,ah,xu,ch,dh,ac,_u,lh,uh,Ou,ph,gh,mh,hh,fh,Ah,yh,zn,cc,Lu,$u,Mu,Fu,Uu,Qu,Hu,Gu,qu,Vu,ju,Ih,Sh,Ch,bh,Eh,vh,Th}from"./chunk-gd9g0v9w.js";import{Le,uc,ae,kt,pc,w,Bt,it,gc,As,Dh,Ju,mc,s,Xn,ys,Ar,hc,fc,yr,Ph,Ac,ay,cy,Is,dy,ly,yc,Ic,Yn,Ss,J,c,Cs,$e,Ir,Nh,kh,Sc,xt,Bh,bs,xh,_h,Es,Cc,Sr,vs,Oh,bc,Xu,_t,Cr,Lh,Ts,$h,R,Mh,Ec,Yu,ws,Fh,Uh,Qh,vc,Zn,Rs,Tc,Ot,st,Hh,br,Gh,wc,Zu,ep,Ds,Rc,Dc,ot,tp,ei,Pc,Ps,Er,rp,ti,Nc,kc,ri,np,Bc,xc,_c,Oc,Ns,ip,sp,qh,op,Lc,ni,ap,cp,ks,vr,Bs,xs,_s,$c,dp,Mc,Os,Vh,Lt,jh,Fc,Tr,Uc,zh,Qc,lp,ii,wr,Ls,si,Me,Kh,up,pp,$t,Hc,Gc,qc,oi,ai,ci,Wh,Jh,at,$s,Xh,Rr,gp,Ms,Yh,mp,hp,fp,Zh,Ap,yp,ef,i,tf,di,Fs,Us}from"./chunk-a6k322xc.js";import{n}from"./chunk-30h9rgfn.js";import{a}from"./chunk-yq3pdbz7.js";import{ue,zi,Ki,Hl,ya,Ia,Wi,Sa,Ke,V,We,re,C,pe,rn,Ca,De,ba,nn,sn,on,yt,It,St,an,Xt,Ea,Yt,Zt,Je,cn,Ta,Ct,er,dn,Ra,jl,zl,Da,tr}from"./chunk-88nxsyry.js";import{un,Ne,bt,Xi,Et,vt,pn,Yi,Zi,me,es,ts,rs,ns,ie,is,ss,os,T,Pa,gn,Na,se,rr}from"./chunk-6t9tjvpy.js";import{ge,Xe,ln}from"./chunk-cy6qh4ea.js";import{j}from"./chunk-zftpjxkr.js";import{Kl,ka,he,Ba,mn,Wl,xa,Jl,Xl,$m,fn,cs,An,yn,In,z,ke,N,ar,Cn,cr,oe,La,bn,$a,dr,Ua,Be,K,xe,_e,et,Ae,lr,ye,Tn,wn,Rn,Dn,Pn,Nn,kn,ur,k,us,yu,za,xn,_n,On,Ln,$n,Mn,Un,Hn,rc,ps,nc,Pt,Gn,gs,ms,ic,qn,sc}from"./chunk-678rwkz8.js";import{Sd,no,yi,Ii,io,Cd,bd,Si,so,oo,vd,Td,ao}from"./chunk-hw3p6pth.js";import{ma,Zr,en,Qi,Hi,Gi,qi,ha,fa}from"./chunk-x07tpsv0.js";import{Aa}from"./chunk-w495x89g.js";import{y}from"./chunk-6g81m01r.js";import{Pe}from"./chunk-r5emv4x8.js";import{h}from"./chunk-wjgnfg6q.js";import{W,Vn,hs,oc,jn,Ru}from"./chunk-6znnde1s.js";import{gr,Ie}from"./chunk-6nvn041c.js";import{f}from"./chunk-jb8em9ba.js";import{Zm,Oe}from"./chunk-hnkw6pde.js";import{Vc,Dr,jc,zc,Kc,li,Ip,Pr}from"./chunk-qzwack6w.js";import{createHmac as qa,createSign as Dl,timingSafeEqual as El}from"node:crypto";function Oi(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 Za(l){return Buffer.from(l).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function vl(l){return Buffer.from(l).toString("base64url")}function Ja(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 Ya(l,S){let b=Dl("RSA-SHA1");return b.update(l),b.end(),Za(b.sign(S))}function Xa(l){Ja(l.resource,!0);let b={DateLessThan:{"AWS:EpochTime":Oi(l.expiresAt)}};if(l.activeAt!==void 0)b.DateGreaterThan={"AWS:EpochTime":Oi(l.activeAt)};if(l.ipAddress)b.IpAddress={"AWS:SourceIp":l.ipAddress};return JSON.stringify({Statement:[{Resource:l.resource,Condition:b}]})}function Cu(l,S,b){Ja(l);let P=Oi(S),v=l.includes("?")?"&":"?",tt=Xa({resource:l,expiresAt:S}),we=Ya(tt,b.privateKey);return`${l}${v}Expires=${P}&Signature=${encodeURIComponent(we)}&Key-Pair-Id=${encodeURIComponent(b.keyPairId)}`}function Su(l,S){let b=Xa(l);return{"CloudFront-Key-Pair-Id":S.keyPairId,"CloudFront-Policy":Za(Buffer.from(b)),"CloudFront-Signature":Ya(b,S.privateKey)}}function Au(l){if(!l.resource||/[\r\n]/.test(l.resource))throw TypeError("Media resource is invalid");let S=vl(Buffer.from(JSON.stringify({resource:l.resource,expiresAt:Oi(l.expiresAt),...l.keyId?{keyId:l.keyId}:{},...l.audience?{audience:l.audience}:{}}))),b=qa("sha256",l.secret).update(S).digest("base64url");return`${S}.${b}`}function bu(l,S){let[b,P,v]=l.split(".");if(!b||!P||v)return null;let tt=qa("sha256",S.secret).update(b).digest(),we;try{we=Buffer.from(P,"base64url")}catch{return null}if(tt.length!==we.length||!El(tt,we))return null;try{let fe=JSON.parse(Buffer.from(b,"base64url").toString("utf8")),Ye=Oi(S.now??Date.now());if(!fe.resource||!Number.isSafeInteger(fe.expiresAt)||fe.expiresAt<=Ye)return null;if(S.resource&&fe.resource!==S.resource)return null;if(S.audience&&fe.audience!==S.audience)return null;return fe}catch{return null}}function Tu(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 Iu(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 kl{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;constructor(l){this.config=l.config,this.environment=l.environment,this.builder=new td(`${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,tt){let we=this.serverEipLogicalIds.get("app"),fe=this.serverEipLogicalIds.get("appInstance");if(!we)return;let Ye=`EC2-${P}-${v}-api`,ft=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",rt=ft==="us-east-1"?".compute-1.amazonaws.com":`.${ft}.compute.amazonaws.com`,or={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:we}]}]},rt]]},Jt=this.resolveApiOriginPort();if(l.push({Id:Ye,DomainName:or,CustomOriginConfig:{HTTPPort:Jt,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),b.push(we),fe)b.push(fe);for(let pr of tt)S.push(this.createComputeCacheBehavior(pr,Ye))}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 tt=b.get(v.domain)??[];tt.push({port:v.port,path:v.path}),b.set(v.domain,tt)}let P=[];for(let[v,tt]of b){let fe=[...tt].sort((Ye,ft)=>{let rt=!Ye.path||Ye.path==="/",or=!ft.path||ft.path==="/";if(rt&&!or)return 1;if(!rt&&or)return-1;return(ft.path?.length??0)-(Ye.path?.length??0)}).map((Ye)=>{let ft=!Ye.path||Ye.path==="/",rt=`reverse_proxy localhost:${Ye.port}`;return ft?` handle {
|
|
2
|
-
${
|
|
3
|
-
}`:` handle ${
|
|
4
|
-
${
|
|
1
|
+
import{wp,x,Rp,df,Ay,lf,yy,Iy,Sy,Cy,by,Ey,vy,Ty,wy,Ry,Dp,Pp,td,rd,zs,_,d,nd,Np,O,id,p,uf,hi,sd,od,de,ad,Dy,r,t,Py,Ny,g,ky,By,xy,_y,Oy,Ft,cd,Ks,pf,Ly,$y,Ce,He,be,L,I,o,A,Ge,m,gf,qe,M,ut,My,mf,F,dd,Ee,Ut,Ws,X,ld,Y,hf,Js,U,Q,D,fi,E,Qt,pt,H,e,Xs,Fy,kp,ud,Uy,Qy,Hy,Gy,pd,qy,Vy,jy,zy,Ky,Wy,Jy,Xy,Yy,Zy,eI,tI,ff,Af,yf,If,Sf,Cf,bf,Ht,Bp,xp,_r,Ai,rI,_p,nI,iI,Or,sI,oI,aI,cI,dI,lI,Ef,vf,Tf,wf,Rf,Ys,uI,Df,Pf,Nf,G,pI,Ve,Zs,Gt,kf,Op,Bf,xf,_f,Lp,Z,gI,mI,hI,fI,Of,yI,q,II,SI,CI,$p,Mp,bI,Fp,Up,EI,vI,TI,wI,RI,Lf,gd,DI,PI,NI,kI,BI,$f,Mf,xI,_I,OI,LI,$I,MI,FI,UI,QI,Qp,md,HI,GI,qI,VI,Hp,Gp,qp,jI,Vp,zI,KI,WI,JI,jp,XI,YI,ZI,eS,tS,rS,nS,iS,Ff,Uf,Qf,Hf,zp,sS,oS,aS,cS,dS,lS,uS,pS,gS,Gf,qf,Vf,jf,mS,hS,Kp,fS,Wp,Jp,Xp,Yp,AS,yS,IS,SS,ve,yi,CS,bS,ES,vS,TS,wS,RS,DS,zf,PS,NS,Zp,eg,kS,BS,Kf,xS,_S,OS,LS,$S,MS,FS,US,QS,HS,GS,qS,VS,jS,zS,KS,WS,JS,XS,YS,ZS,tg,eC,rg,tC,ng,rC,ig,nC,sg,iC,Lr,sC,og,oC,eo,aC,ag,cC,cg,dC,dg,lC,lg,uC,ug,pC,$r,gC,pg,mC,gg,hC,mg,fC,hg,AC,fg,yC,Ag,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,Wf,Jf,Xf,Yf,$g,FC,Mg,UC,Fg,QC,Ug,HC,Ii,Zf,eA,to,hd,Mr,tA,ro,qt,fd,Ad,rA,nA,Qg,iA,yd,Hg,GC,qC,no,io,so,Id,Si,Sd,Cd,oo,bd,Ed,Gg,sA,oA,aA,VC,cA,dA,jC,lA,qg,uA,pA,gA,zC,mA,Ci,vd,hA,KC,fA,ao,co,Td,Vg,WC,jg,JC,zg,XC,Kg,YC,Wg,ZC}from"./chunk-y13zcbnp.js";import{ho,Jg,Bd,yA,Ti,xd,fo,Xg,Yg,Fr,Ao,_d,je,Od,Ld,$d,wi,Ur,Zg,ze,Md,yo,Io,So,Fd,Ud,Qd,Ri,Co,Hd,Qr,Di,bo,gt,em,Gd,qd,tm,Vd,Eo,Vt,jd,zd,Kd,Wd,Ke,rm,Jd,jt,vo,To,wo,Pi,Ni,Hr,Xd,ki,Ro,Do,Gr,Yd,qr,nm,im,mt,Vr,Po,sm,Zd,el,No,tl,rl,nl,IA,ee,il,SA,CA,Bi,xi,bA,le,om,ht,Te,we,ft,sl,ol,al,cl,am,cm,ko,dm,lm,Bo,dl,ll,um,te,pm,ul,ue,xo,We,At,yt,jr,_i,pl,EA,_o,gm,mm,hm,fm,Oo,Lo,gl,zr,$o,ml,Oi,hl,Mo,Fo,Uo,Qo,Ho,Go,qo,Vo,fl,zt,jo,Al,Kr,yl,zo,Ko,Il,Kt,Wo,Jo,Am,vA,Li,TA,wA,RA,Xo,Yo,Sl,ym,Zo,Wr,Cl,$i,bl,El,vl,ea,Im,ta,Tl,Sm,ra,Cm,Jr,Xr,wl,Mi,Bl,Ll,Ui,Wt,ia,Yr,Zr,Jt,Je,Pm,oa,Nm,km,Fl,aa,Hi,Ul,ca,St,De,Ql,da,la,Hl,ua,pa,ga,ma,Gl,ql,tn,ha,fa,Aa,ya,Vl,Gi,rn,qi,Ia}from"./chunk-ycs26jsj.js";import{B,Sr,fc,bs,u,ep,tp}from"./chunk-m5r0dt28.js";import{ot,hc,Yn,Zn,ei,Zu}from"./chunk-ds92qg3g.js";import{ch,dh,lh,_u,Ou,Lu,uh,$u,Mu,ph,gh,Fu,mh,hh,gc,Uu,fh,Ah,Qu,yh,Ih,Sh,Ch,bh,Eh,vh,Xn,mc,Hu,Gu,qu,Vu,ju,zu,Ku,Wu,Ju,Xu,Yu,Th,wh,Rh,Dh,Ph,Nh,kh}from"./chunk-asmv4fw1.js";import{Fe,Ac,ce,Bt,yc,w,xt,at,Ic,Es,_h,rp,Sc,s,ti,vs,Cr,Cc,bc,br,Oh,Ec,gy,my,Ts,hy,fy,vc,Tc,ri,ws,J,c,Rs,Ue,Er,Lh,$h,wc,_t,Mh,Ds,Fh,Uh,Ps,Rc,vr,Ns,Qh,Dc,np,Ot,Tr,Hh,ks,Gh,R,qh,Pc,ip,Bs,Vh,jh,zh,Nc,ni,xs,kc,Lt,ct,Kh,wr,Wh,Bc,sp,op,_s,xc,_c,dt,ap,ii,Oc,Os,Rr,cp,si,Lc,$c,oi,dp,Mc,Fc,Uc,Qc,Ls,lp,up,Jh,pp,Hc,ai,gp,mp,$s,Dr,Ms,Fs,Us,Gc,hp,qc,Qs,Xh,$t,Yh,Vc,Pr,jc,Zh,zc,fp,ci,Nr,Hs,di,Qe,ef,Ap,yp,Mt,Kc,Wc,Jc,li,ui,pi,tf,rf,lt,Gs,nf,kr,Ip,qs,sf,Sp,Cp,bp,of,Ep,vp,af,i,cf,gi,Vs,js}from"./chunk-xqx5szta.js";import{n}from"./chunk-2s65yj3g.js";import{a}from"./chunk-6gtqjsg9.js";import{pe,Xi,Yi,Kl,va,Ta,Zi,wa,Xe,V,Ye,re,C,ge,an,Ra,Pe,Da,cn,dn,ln,Ct,bt,Et,un,Yt,Pa,Zt,er,Ze,pn,ka,vt,tr,gn,xa,Yl,Zl,_a,rr}from"./chunk-hyj2ymp1.js";import{tt,ie,ke,ts,Be,Tt,hn,rs,ns,nr,ir,fn,sr,is,ss,he,os,as,cs,ds,se,ls,us,ps,T,Oa,An,La,oe,or}from"./chunk-j4ed179k.js";import{me,et,mn}from"./chunk-ngdhqwf3.js";import{j}from"./chunk-mcfdtg5w.js";import{eu,$a,fe,Ma,yn,tu,Fa,ru,nu,Gm,Sn,ms,Cn,bn,En,z,_e,N,ur,Tn,pr,ae,Ha,wn,Ga,gr,ja,Oe,K,Le,$e,nt,ye,mr,Ie,Pn,Nn,kn,Bn,xn,_n,On,hr,k,As,vu,Za,$n,Mn,Un,Qn,Hn,Gn,qn,jn,cc,ys,dc,Nt,zn,Is,Ss,lc,Kn,uc}from"./chunk-vk513ge7.js";import{wd,lo,bi,Ei,uo,Rd,Dd,vi,po,go,Nd,kd,mo}from"./chunk-42kv07cs.js";import{Sa,nn,sn,Vi,ji,zi,Ki,Ca,ba}from"./chunk-3k60wm30.js";import{Ea}from"./chunk-w5fmaaxa.js";import{y}from"./chunk-8s9m8pyb.js";import{Ne}from"./chunk-z7v4evbh.js";import{h}from"./chunk-65ajja2a.js";import{W,Wn,Cs,pc,Jn,xu}from"./chunk-nhtz2k8d.js";import{Ar,Se}from"./chunk-dzqz1sm0.js";import{f}from"./chunk-0g2jkhy5.js";import{sh,Me}from"./chunk-p9fqsz06.js";import{Xc,Br,Yc,Zc,ed,mi,Tp,xr}from"./chunk-r4dpn715.js";import{createHmac as fs,createSign as Nl,timingSafeEqual as kl}from"node:crypto";function Wi(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 gs(l){return Buffer.from(l).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function xl(l){return Buffer.from(l).toString("base64url")}function hs(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=Nl("RSA-SHA1");return b.update(l),b.end(),gs(b.sign(S))}function tc(l){hs(l.resource,!0);let b={DateLessThan:{"AWS:EpochTime":Wi(l.expiresAt)}};if(l.activeAt!==void 0)b.DateGreaterThan={"AWS:EpochTime":Wi(l.activeAt)};if(l.ipAddress)b.IpAddress={"AWS:SourceIp":l.ipAddress};return JSON.stringify({Statement:[{Resource:l.resource,Condition:b}]})}function Pu(l,S,b){hs(l);let P=Wi(S),v=l.includes("?")?"&":"?",it=tc({resource:l,expiresAt:S}),Re=ec(it,b.privateKey);return`${l}${v}Expires=${P}&Signature=${encodeURIComponent(Re)}&Key-Pair-Id=${encodeURIComponent(b.keyPairId)}`}function Tu(l,S){let b=tc(l);return{"CloudFront-Key-Pair-Id":S.keyPairId,"CloudFront-Policy":gs(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=xl(Buffer.from(JSON.stringify({resource:l.resource,expiresAt:Wi(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 Du(l,S){let[b,P,v]=l.split(".");if(!b||!P||v)return null;let it=fs("sha256",S.secret).update(b).digest(),Re;try{Re=Buffer.from(P,"base64url")}catch{return null}if(it.length!==Re.length||!kl(it,Re))return null;try{let Ae=JSON.parse(Buffer.from(b,"base64url").toString("utf8")),rt=Wi(S.now??Date.now());if(!Ae.resource||!Number.isSafeInteger(Ae.expiresAt)||Ae.expiresAt<=rt)return null;if(S.resource&&Ae.resource!==S.resource)return null;if(S.audience&&Ae.audience!==S.audience)return null;return Ae}catch{return null}}function wu(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 Eu(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 _l{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;constructor(l){this.config=l.config,this.environment=l.environment,this.builder=new ad(`${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 Re=this.serverEipLogicalIds.get("app"),Ae=this.serverEipLogicalIds.get("appInstance");if(!Re)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`,lr={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:Re}]}]},st]]},Xt=this.resolveApiOriginPort();if(l.push({Id:rt,DomainName:lr,CustomOriginConfig:{HTTPPort:Xt,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),b.push(Re),Ae)b.push(Ae);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 Ae=[...it].sort((rt,Rt)=>{let st=!rt.path||rt.path==="/",lr=!Rt.path||Rt.path==="/";if(st&&!lr)return 1;if(!st&&lr)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 {
|
|
2
|
+
${st}
|
|
3
|
+
}`:` handle ${rt.path} {
|
|
4
|
+
${st}
|
|
5
5
|
}`});P.push(`${v} {
|
|
6
|
-
${
|
|
6
|
+
${Ae.join(`
|
|
7
7
|
`)}
|
|
8
8
|
}`)}return P.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:tt}=A.createVpc({slug:l,environment:S,cidr:P,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",v);let we=`${l}${S}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(we,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${l}-${S}-igw`},{Key:"Environment",Value:S}]}});let fe=`${l}${S}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(fe,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:we}}});let Ye=`${l}${S}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ye,{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:Ye},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:we}},DependsOn:fe});let ft=this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1",rt=["a","b"];for(let or=0;or<2;or++){let Jt=`PublicSubnet${or+1}`;this.builder.addResource(Jt,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${or}.0/24`,AvailabilityZone:`${ft}${rt[or]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${l}-${S}-public-${rt[or]}`},{Key:"Environment",Value:S}]}}),this.builder.addResource(`${Jt}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:Jt},RouteTableId:{Ref:Ye}}})}}generateContainerInfrastructure(l,S){let b=this.mergedConfig.infrastructure?.containers;if(!b)return;let P=this.mergedConfig.infrastructure?.loadBalancer,v=this.mergedConfig.infrastructure?.ssl,tt=this.mergedConfig.infrastructure?.dns,we;if(v?.enabled&&v.domains?.length)if(v.certificateArn);else{let rt=v.domains[0],or=v.domains.slice(1).map((Dt)=>{if(Dt.includes(".")&&Dt.endsWith(rt))return Dt.replace(`.${rt}`,"");return Dt}),{certificate:Jt,logicalId:pr}=I.createCertificate({domain:rt,subdomains:or,slug:l,environment:S,validationMethod:"DNS",hostedZoneId:tt?.hostedZoneId});we=pr,this.builder.addResource(pr,Jt)}let fe="ECSCluster";this.builder.addResource(fe,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${l}-${S}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${l}-${S}`},{Key:"Environment",Value:S}]}});let Ye=`${l}${S}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ye,{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 ft=`${l}${S}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[rt,or]of Object.entries(b)){let Jt=or.port||3000;this.builder.addResource(ft,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${l}-${S}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:Jt,ToPort:Jt,SourceSecurityGroupId:{Ref:Ye},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 pr=`${l}${S}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(pr,{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}${rt}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),Ze=`/ecs/${l}-${S}-${rt}`;this.builder.addResource(Rt,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:Ze,RetentionInDays:30}});let Nt=`${l}${S}${rt}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),ne=String(or.cpu||512),Tt=String(or.memory||1024);this.builder.addResource(Nt,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${S}-${rt}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:ne,Memory:Tt,ExecutionRoleArn:{"Fn::GetAtt":[pr,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[Dt,"Arn"]},ContainerDefinitions:[{Name:rt,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${l}:latest`},Essential:!0,PortMappings:[{ContainerPort:Jt,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":Ze,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":rt}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${Jt}${or.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${l}-${S}-${rt}`},{Key:"Environment",Value:S}]},DependsOn:[pr,Dt,Rt]});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:Ye}],Tags:[{Key:"Name",Value:`${l}-${S}-alb`},{Key:"Environment",Value:S}]}});let nr=`${l}${S}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),ir=P?.healthCheck?.path||or.healthCheck||"/health";this.builder.addResource(nr,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${l}-${S}-tg`,Port:Jt,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:ir,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 sr=`${l}${S}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(v?.enabled&&v?.redirectHttp)this.builder.addResource(sr,{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(sr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:nr}}]}});if(v?.enabled){let hn=v.certificateArn||(we?{Ref:we}:void 0);if(hn){let Sn=`${l}${S}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Sn,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:hn}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:nr}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let hr=`${l}${S}${rt}Service`.replace(/[^a-zA-Z0-9]/g,""),Jr=or.desiredCount||1;this.builder.addResource(hr,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-${rt}`,Cluster:{Ref:fe},TaskDefinition:{Ref:Nt},DesiredCount:Jr,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:ft}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:rt,ContainerPort:Jt,TargetGroupArn:{Ref:nr}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${l}-${S}-${rt}`},{Key:"Environment",Value:S}]},DependsOn:[Nt,sr,nr]});let mr=or.autoScaling;if(mr){let hn=`${l}${S}${rt}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(hn,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:mr.max||10,MinCapacity:mr.min||1,ResourceId:{"Fn::Sub":`service/\${${fe}}/${l}-${S}-${rt}`},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:hr}),mr.targetCpuUtilization)this.builder.addResource(`${l}${S}${rt}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${S}-${rt}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:hn},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:mr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(mr.targetMemoryUtilization)this.builder.addResource(`${l}${S}${rt}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${l}-${S}-${rt}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:hn},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:mr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(tt?.domain&&tt?.hostedZoneId)this.builder.addResource(`${l}${S}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:tt.hostedZoneId,Name:`api.${tt.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":[fe,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${l}-${S}-${rt}`,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 nr=`${l}${S}${rt}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(nr,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-${rt}`,Cluster:{Ref:fe},TaskDefinition:{Ref:Nt},DesiredCount:or.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:ft}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${l}-${S}-${rt}`},{Key:"Environment",Value:S}]},DependsOn:[Nt]})}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:tt}=X.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(tt,v);let{lambdaFunction:we,logicalId:fe}=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:tt,timeout:P.timeout,memorySize:P.memorySize});this.builder.addResource(fe,we)}if(this.mergedConfig.infrastructure?.api){let{restApi:b,logicalId:P}=id.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((we)=>!we.privateNetwork||we.privateNetwork==="create"))this.generateNetworkInfrastructure(l,S);for(let[we,fe]of Object.entries(b)){let Ye=fe.instanceType||fe.size||P?.size,rt=(Ye?o.InstanceSize.specs[Ye]:void 0)?.instanceType||Ye||"t3.micro",or=fe.type||"app",Jt=fe.userData||fe.startupScript;if(!Jt)Jt=o.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:fe.bunVersion||"latest",webServer:"none",domain:fe.domain,enableSsl:!!v?.enabled,sslEmail:v?.letsEncrypt?.email,installRedis:or==="cache",installDatabaseClients:!!fe.database});let pr=fe.privateNetwork&&fe.privateNetwork!=="create"?fe.privateNetwork:{Ref:"VPC"},Dt=fe.subnet||{Ref:"PublicSubnet1"},Ze=!!this.mergedConfig.infrastructure?.email?.server?.enabled,Nt=[22,80,443,this.resolveApiOriginPort()];if(Ze)Nt.push(25,465,587,143,993);let ne=o.createServerModeStack({slug:`${l}-${we}`,environment:S,vpcId:pr,subnetId:Dt,instanceType:rt,keyName:fe.keyName||`${l}-${S}`,domain:fe.domain,userData:Jt,volumeSize:fe.diskSize||20,imageId:fe.image,allowedPorts:Nt});for(let[Tt,wt]of Object.entries(ne.resources))this.builder.addResource(Tt,wt);this.serverEipLogicalIds.set(we,ne.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${we}Instance`,ne.outputs.instanceLogicalId),this.builder.addOutput(`${we}InstanceId`,{Value:{Ref:ne.outputs.instanceLogicalId},Description:`Instance ID for ${we} server`}),this.builder.addOutput(`${we}PublicIp`,{Value:{Ref:ne.outputs.eipLogicalId},Description:`Public IP for ${we} server`})}}generateComputeApp(l,S){let b=this.mergedConfig.infrastructure?.compute;if(!b)return;let P=this.mergedConfig.sites||{},v=Object.entries(P),we=this.mergedConfig.infrastructure?.dns?.domain,fe=this.mergedConfig.infrastructure?.database,Ye=b.size,rt=(Ye?o.InstanceSize.specs[Ye]:void 0)?.instanceType||Ye||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(l,S);let or=this.buildCaddyfile(v),Jt=o.UserData.generateBunAppScript({runtime:b.runtime||"bun",runtimeVersion:b.runtimeVersion||"latest",systemPackages:b.systemPackages,database:fe,caddyfile:or}),pr=cs(b.appUpdates),Dt=pr.length>0?`${Jt}
|
|
11
|
-
${
|
|
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}=A.createVpc({slug:l,environment:S,cidr:P,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",v);let Re=`${l}${S}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Re,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${l}-${S}-igw`},{Key:"Environment",Value:S}]}});let Ae=`${l}${S}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ae,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:Re}}});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:Re}},DependsOn:Ae});let Rt=this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1",st=["a","b"];for(let lr=0;lr<2;lr++){let Xt=`PublicSubnet${lr+1}`;this.builder.addResource(Xt,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${lr}.0/24`,AvailabilityZone:`${Rt}${st[lr]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${l}-${S}-public-${st[lr]}`},{Key:"Environment",Value:S}]}}),this.builder.addResource(`${Xt}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:Xt},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,Re;if(v?.enabled&&v.domains?.length)if(v.certificateArn);else{let st=v.domains[0],lr=v.domains.slice(1).map((Dt)=>{if(Dt.includes(".")&&Dt.endsWith(st))return Dt.replace(`.${st}`,"");return Dt}),{certificate:Xt,logicalId:fr}=I.createCertificate({domain:st,subdomains:lr,slug:l,environment:S,validationMethod:"DNS",hostedZoneId:it?.hostedZoneId});Re=fr,this.builder.addResource(fr,Xt)}let Ae="ECSCluster";this.builder.addResource(Ae,{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,lr]of Object.entries(b)){let Xt=lr.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:Xt,ToPort:Xt,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 Pt=`${l}${S}${st}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),xe=`/ecs/${l}-${S}-${st}`;this.builder.addResource(Pt,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:xe,RetentionInDays:30}});let kt=`${l}${S}${st}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),ne=String(lr.cpu||512),It=String(lr.memory||1024);this.builder.addResource(kt,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${S}-${st}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:ne,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:Xt,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":xe,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":st}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${Xt}${lr.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,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 ar=`${l}${S}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),cr=P?.healthCheck?.path||lr.healthCheck||"/health";this.builder.addResource(ar,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${l}-${S}-tg`,Port:Xt,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:cr,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:ar}}]}});if(v?.enabled){let Rn=v.certificateArn||(Re?{Ref:Re}:void 0);if(Rn){let In=`${l}${S}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(In,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:wt},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Rn}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:ar}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Ir=`${l}${S}${st}Service`.replace(/[^a-zA-Z0-9]/g,""),en=lr.desiredCount||1;this.builder.addResource(Ir,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-${st}`,Cluster:{Ref:Ae},TaskDefinition:{Ref:kt},DesiredCount:en,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Rt}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:st,ContainerPort:Xt,TargetGroupArn:{Ref:ar}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${l}-${S}-${st}`},{Key:"Environment",Value:S}]},DependsOn:[kt,dr,ar]});let yr=lr.autoScaling;if(yr){let Rn=`${l}${S}${st}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Rn,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:yr.max||10,MinCapacity:yr.min||1,ResourceId:{"Fn::Sub":`service/\${${Ae}}/${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:Rn},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:Rn},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":[Ae,"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 ar=`${l}${S}${st}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(ar,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-${st}`,Cluster:{Ref:Ae},TaskDefinition:{Ref:kt},DesiredCount:lr.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}=X.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:Re,logicalId:Ae}=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(Ae,Re)}if(this.mergedConfig.infrastructure?.api){let{restApi:b,logicalId:P}=ld.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((Re)=>!Re.privateNetwork||Re.privateNetwork==="create"))this.generateNetworkInfrastructure(l,S);for(let[Re,Ae]of Object.entries(b)){let rt=Ae.instanceType||Ae.size||P?.size,st=(rt?o.InstanceSize.specs[rt]:void 0)?.instanceType||rt||"t3.micro",lr=Ae.type||"app",Xt=Ae.userData||Ae.startupScript;if(!Xt)Xt=o.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:Ae.bunVersion||"latest",webServer:"none",domain:Ae.domain,enableSsl:!!v?.enabled,sslEmail:v?.letsEncrypt?.email,installRedis:lr==="cache",installDatabaseClients:!!Ae.database});let fr=Ae.privateNetwork&&Ae.privateNetwork!=="create"?Ae.privateNetwork:{Ref:"VPC"},Dt=Ae.subnet||{Ref:"PublicSubnet1"},xe=!!this.mergedConfig.infrastructure?.email?.server?.enabled,kt=[22,80,443,this.resolveApiOriginPort()];if(xe)kt.push(25,465,587,143,993);let ne=o.createServerModeStack({slug:`${l}-${Re}`,environment:S,vpcId:fr,subnetId:Dt,instanceType:st,keyName:Ae.keyName||`${l}-${S}`,domain:Ae.domain,userData:Xt,volumeSize:Ae.diskSize||20,imageId:Ae.image,allowedPorts:kt});for(let[It,wt]of Object.entries(ne.resources))this.builder.addResource(It,wt);this.serverEipLogicalIds.set(Re,ne.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${Re}Instance`,ne.outputs.instanceLogicalId),this.builder.addOutput(`${Re}InstanceId`,{Value:{Ref:ne.outputs.instanceLogicalId},Description:`Instance ID for ${Re} server`}),this.builder.addOutput(`${Re}PublicIp`,{Value:{Ref:ne.outputs.eipLogicalId},Description:`Public IP for ${Re} server`})}}generateComputeApp(l,S){let b=this.mergedConfig.infrastructure?.compute;if(!b)return;let P=this.mergedConfig.sites||{},v=Object.entries(P),Re=this.mergedConfig.infrastructure?.dns?.domain,Ae=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 lr=this.buildCaddyfile(v),Xt=o.UserData.generateBunAppScript({runtime:b.runtime||"bun",runtimeVersion:b.runtimeVersion||"latest",systemPackages:b.systemPackages,database:Ae,caddyfile:lr}),fr=ms(b.appUpdates),Dt=fr.length>0?`${Xt}
|
|
11
|
+
${fr.join(`
|
|
12
12
|
`)}
|
|
13
|
-
`:
|
|
14
|
-
else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`}});let va=[{Id:$i,DomainName:{"Fn::Sub":`\${${sr}}.s3.${vn}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Ze}}],Zo=[],Oa=[];if(this.shouldRouteStorageBucketToCompute(ne,Tt)){this.appendComputeAppOrigin(va,Zo,Oa,l,S,this.resolveComputeCachePathPatterns(Tt.computeRoutes));for(let tn of Nt){let Xo=`S3-${l}-${S}-${tn.name}`,Fa=`${l}${S}${tn.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Fa,{Type:"AWS::CloudFront::Function",Properties:{Name:`${l}-${S}-${tn.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${l} ${S} ${tn.name} at ${tn.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(tn.mountPath,tn.rewriteStyle)}}),va.push({Id:Xo,DomainName:{"Fn::Sub":`\${${tn.logicalId}}.s3.${vn}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Ze}}),Oa.push(tn.logicalId,Fa);for(let Tl of[tn.mountPath,`${tn.mountPath}/*`])Zo.push({PathPattern:Tl,TargetOriginId:Xo,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":[Fa,"FunctionARN"]}}]})}}let Ka={Type:"AWS::CloudFront::Distribution",DependsOn:[sr,Ze,...Fn?[Fn]:[],...Oa],Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${S} ${ne} site`,DefaultRootObject:"index.html",Origins:va,DefaultCacheBehavior:{TargetOriginId:$i,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...Fn?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Fn,"FunctionARN"]}}]}:{}},...Zo.length>0?{CacheBehaviors:Zo}:{},...mr.length>0?{Aliases:mr}:{},ViewerCertificate:Ji,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:Qn}}};if(fe)Ka.DependsOn.push(fe);this.builder.addResource(Jr,Ka);let Pl=`${sr}CloudFrontPolicy`;if(this.builder.addResource(Pl,{Type:"AWS::S3::BucketPolicy",DependsOn:[sr,Jr],Properties:{Bucket:{Ref:sr},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${sr}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Jr}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(ne,Tt))for(let tn of Nt){let Xo=`${tn.logicalId}CloudFrontPolicy`;this.builder.addResource(Xo,{Type:"AWS::S3::BucketPolicy",DependsOn:[tn.logicalId,Jr],Properties:{Bucket:{Ref:tn.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:::\${${tn.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Jr}}`}}}}]}}})}if(mr.length>0)we.push({name:ne,bucketLogicalId:sr,distLogicalId:Jr,oacLogicalId:Ze,aliases:mr});this.builder.addOutput(`${ne}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Jr,"DomainName"]},Description:`CloudFront domain for ${ne}`}),this.builder.addOutput(`${ne}CloudFrontDistributionId`,{Value:{Ref:Jr},Description:`CloudFront distribution ID for ${ne}`})}if(this.builder.addOutput(`${ne}BucketName`,{Value:{Ref:sr},Description:`S3 bucket name for ${ne}`}),ne==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:sr},Description:"Frontend S3 bucket name"});if(ne==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:sr},Description:"Documentation S3 bucket name"});if(ne==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:sr},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let Rt=this.mergedConfig.infrastructure.sftp,Ze=nd.create({...Rt,storage:this.resolveSftpStorage(Rt,l,S)??Rt.storage,slug:l,environment:S});for(let[Nt,ne]of Object.entries(Ze.resources))this.builder.addResource(Nt,ne);this.builder.addOutput("SftpServerId",{Value:{Ref:Ze.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${Ze.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:Ze.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(tt&&we.length>0)for(let{name:Rt,distLogicalId:Ze,aliases:Nt}of we)for(let ne of Nt){let Tt=ne.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Tt}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ze],Properties:{HostedZoneId:tt,Name:ne,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[Ze,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${Tt}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ze],Properties:{HostedZoneId:tt,Name:ne,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[Ze,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[Rt,Ze]of Object.entries(this.mergedConfig.infrastructure.databases))if(Ze.engine==="dynamodb"){let{table:Nt,logicalId:ne}=Ft.createTable({slug:l,environment:S,tableName:`${l}-${S}-${Rt}`,partitionKey:Ze.partitionKey||{name:"id",type:"S"},sortKey:Ze.sortKey});this.builder.addResource(ne,Nt)}else if(Ze.engine==="postgres"){let{dbInstance:Nt,logicalId:ne}=Ft.createPostgres({slug:l,environment:S,dbInstanceIdentifier:`${l}-${S}-${Rt}`,masterUsername:Ze.username||"admin",masterUserPassword:Ze.password||"changeme123",allocatedStorage:Ze.storage||20,dbInstanceClass:Ze.instanceClass||"db.t3.micro"});this.builder.addResource(ne,Nt)}else if(Ze.engine==="mysql"){let{dbInstance:Nt,logicalId:ne}=Ft.createMysql({slug:l,environment:S,dbInstanceIdentifier:`${l}-${S}-${Rt}`,masterUsername:Ze.username||"admin",masterUserPassword:Ze.password||"changeme123",allocatedStorage:Ze.storage||20,dbInstanceClass:Ze.instanceClass||"db.t3.micro"});this.builder.addResource(ne,Nt)}}if(this.mergedConfig.infrastructure?.cdn)for(let[Rt,Ze]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!Ze.origin)continue;let Nt=typeof Ze.customDomain==="string"?Ze.customDomain:Ze.customDomain?.domain||Ze.domain,ne=typeof Ze.customDomain==="object"?Ze.customDomain?.certificateArn:Ze.certificateArn,Tt=ne||Ye,wt=`${l}${S}${Rt}CDN`.replace(/[^a-zA-Z0-9]/g,""),nr=`S3-${l}-${S}-${Rt}-cdn`,ir=[{Id:nr,DomainName:Ze.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:Ze.originShield?{Enabled:!0,OriginShieldRegion:Ze.originShieldRegion||this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1}}],sr=[],hr=[];if(Ze.routeCompute)this.appendComputeAppOrigin(ir,sr,hr,l,S,this.resolveComputeCachePathPatterns(Ze.computeRoutes));let Jr=Tt&&Nt?{AcmCertificateArn:fe&&!ne?{Ref:fe}:Tt,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},mr=[...hr];if(fe&&!ne&&Nt)mr.push(fe);let hn={Type:"AWS::CloudFront::Distribution",...mr.length>0?{DependsOn:mr}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${S} ${Rt} CDN`,DefaultRootObject:"index.html",Origins:ir,DefaultCacheBehavior:{TargetOriginId:nr,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:Ze.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...sr.length>0?{CacheBehaviors:sr}:{},...Nt&&Tt?{Aliases:[Nt]}:{},ViewerCertificate:Jr,PriceClass:"PriceClass_100",HttpVersion:Ze.http3?"http2and3":"http2"}}};if(this.builder.addResource(wt,hn),tt&&Nt&&Tt){let Sn=Nt.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Sn}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[wt,...fe&&!ne?[fe]:[]],Properties:{HostedZoneId:tt,Name:Nt,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[wt,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[Rt,Ze]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(Ze))continue;let{queue:Nt,logicalId:ne}=M.createQueue({slug:l,environment:S,name:`${l}-${S}-${Rt}`,fifo:Ze.fifo,visibilityTimeout:Ze.visibilityTimeout,messageRetentionPeriod:Ze.messageRetentionPeriod,delaySeconds:Ze.delaySeconds,maxMessageSize:Ze.maxMessageSize,receiveMessageWaitTime:Ze.receiveMessageWaitTime,contentBasedDeduplication:Ze.contentBasedDeduplication,encrypted:Ze.encrypted,kmsKeyId:Ze.kmsKeyId});this.builder.addResource(ne,Nt);let Tt;if(Ze.deadLetterQueue){let{deadLetterQueue:wt,updatedSourceQueue:nr,deadLetterLogicalId:ir}=M.createDeadLetterQueue(ne,{slug:l,environment:S,maxReceiveCount:Ze.maxReceiveCount});Tt=ir,this.builder.addResource(ir,wt);let hr=this.builder.getResources()[ne];if(hr?.Properties)hr.Properties.RedrivePolicy=nr.Properties?.RedrivePolicy}if(Ze.trigger){let wt=Ze.trigger,nr=`${l}${S}${wt.functionName}`.replace(/[^a-zA-Z0-9]/g,""),ir={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[ne,"Arn"]},FunctionName:{Ref:nr},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:[ne,nr]};this.builder.addResource(`${ne}Trigger`,ir)}if(Ze.alarms?.enabled){let wt=Ze.alarms,nr=wt.notificationTopicArn;if(!nr&&wt.notificationEmails?.length){let hr=`${ne}AlarmTopic`;this.builder.addResource(hr,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-${Rt}-alarms`,DisplayName:`${Rt} Queue Alarms`}}),wt.notificationEmails.forEach((Jr,mr)=>{this.builder.addResource(`${hr}Sub${mr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:hr},Protocol:"email",Endpoint:Jr}})}),nr={Ref:hr}}let ir=wt.queueDepthThreshold||1000;this.builder.addResource(`${ne}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Rt}-queue-depth`,AlarmDescription:`Queue ${Rt} depth exceeds ${ir} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:ir,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ne,"QueueName"]}}],...nr&&{AlarmActions:[nr],OKActions:[nr]}}});let sr=wt.messageAgeThreshold||3600;if(this.builder.addResource(`${ne}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Rt}-message-age`,AlarmDescription:`Queue ${Rt} oldest message exceeds ${sr} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:sr,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ne,"QueueName"]}}],...nr&&{AlarmActions:[nr],OKActions:[nr]}}}),Tt&&wt.dlqAlarm!==!1)this.builder.addResource(`${Tt}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":[Tt,"QueueName"]}}],...nr&&{AlarmActions:[nr]}}})}if(Ze.subscribe){let wt=Ze.subscribe,nr=wt.topicArn;if(!nr&&wt.topicName)nr={Ref:wt.topicName};if(nr){this.builder.addResource(`${ne}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:ne}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[ne,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":nr}}}]}}});let ir={TopicArn:nr,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[ne,"Arn"]},RawMessageDelivery:wt.rawMessageDelivery||!1};if(wt.filterPolicy)ir.FilterPolicy=wt.filterPolicy,ir.FilterPolicyScope=wt.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${ne}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:ir,DependsOn:`${ne}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 ft=this.mergedConfig.infrastructure?.redirects;if(ft){let Rt=ft.target||this.mergedConfig.infrastructure?.dns?.domain||"",Ze=ft.protocol||"https";if(ft.domains?.length&&Rt)for(let Nt of ft.domains){let{bucket:ne,bucketPolicy:Tt,logicalId:wt,policyLogicalId:nr}=dt.createDomainRedirectBucket({slug:l,environment:S,sourceDomain:Nt,targetDomain:Rt,protocol:Ze});this.builder.addResource(wt,ne),this.builder.addResource(nr,Tt)}if(ft.paths&&Object.keys(ft.paths).length>0){let Nt=dt.fromMapping(ft.paths,{statusCode:ft.statusCode||301}),{function:ne,logicalId:Tt}=dt.createPathRedirectFunction({slug:l,environment:S,rules:Nt});this.builder.addResource(Tt,ne)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[Rt,Ze]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:Nt,logicalId:ne}=qs.createAlarm({slug:l,environment:S,alarmName:`${l}-${S}-${Rt}`,metricName:Ze.metricName||"Errors",namespace:Ze.namespace||"AWS/Lambda",threshold:Ze.threshold||1,comparisonOperator:Ze.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(ne,Nt)}let rt=this.mergedConfig.infrastructure?.cache;if(rt){let Rt=rt.type||"redis";if(Rt==="redis"){this.generateNetworkInfrastructure(l,S);let Ze=rt.redis||{},{replicationGroup:Nt,subnetGroup:ne,logicalId:Tt,subnetGroupId:wt}=Gs.createRedis({slug:l,environment:S,nodeType:Ze.nodeType||rt.nodeType||"cache.t3.micro",engineVersion:Ze.engineVersion||"7.1",port:Ze.port||6379,numCacheClusters:Ze.numCacheNodes||2,automaticFailover:Ze.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:Ze.snapshotRetentionLimit||7,snapshotWindow:Ze.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Tt,Nt),ne&&wt)this.builder.addResource(wt,ne);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Tt,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[Tt,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(Rt==="memcached"){this.generateNetworkInfrastructure(l,S);let Ze=rt.elasticache||{},{cluster:Nt,subnetGroup:ne,logicalId:Tt,subnetGroupId:wt}=Gs.createMemcached({slug:l,environment:S,nodeType:Ze.nodeType||rt.nodeType||"cache.t3.micro",engineVersion:Ze.engineVersion||"1.6.22",numCacheNodes:Ze.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Tt,Nt),ne&&wt)this.builder.addResource(wt,ne);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Tt,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let or=this.mergedConfig.infrastructure?.email;if(or){let Rt=or.domain||this.mergedConfig.infrastructure?.dns?.domain;if(Rt){let{emailIdentity:Ze,logicalId:Nt}=m.verifyDomain({domain:Rt,slug:l,environment:S,enableDkim:or.enableDkim!==!1,dkimKeyLength:or.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(Nt,Ze),or.configurationSet!==!1){let{configurationSet:wt,logicalId:nr}=m.createConfigurationSet({slug:l,environment:S});this.builder.addResource(nr,wt)}let ne=or.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(ne){if(or.enableDkim!==!1)for(let hr=1;hr<=3;hr++){let Jr=`DkimRecord${hr}${Rt.replace(/\./g,"")}`;this.builder.addResource(Jr,{Type:"AWS::Route53::RecordSet",DependsOn:[Nt],Properties:{HostedZoneId:ne,Name:{"Fn::GetAtt":[Nt,`DkimDNSTokenName${hr}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[Nt,`DkimDNSTokenValue${hr}`]}]}})}let{record:wt,logicalId:nr}=m.createSpfRecord(Rt,ne);this.builder.addResource(nr,wt);let{record:ir,logicalId:sr}=m.createDmarcRecord(Rt,ne,{policy:"none",reportingEmail:or.dmarcReportingEmail||`dmarc-reports@${Rt}`});this.builder.addResource(sr,ir)}this.builder.addOutput("EmailDomain",{Value:Rt,Description:"SES verified email domain"});let Tt=or.server;if(Tt?.enabled&&ne){let wt=this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1",nr=`${l}-${S}-email`,{role:ir,policy:sr,roleLogicalId:hr,policyLogicalId:Jr}=m.createEmailLambdaRole({slug:l,environment:S,s3BucketArn:`arn:aws:s3:::${nr}`,sesIdentityArn:`arn:aws:ses:${wt}:*:identity/${Rt}`});this.builder.addResource(hr,ir),this.builder.addResource(Jr,sr);let{function:mr,permission:hn,logicalId:Sn,permissionLogicalId:Bn}=m.createInboundEmailLambda({slug:l,environment:S,roleArn:{"Fn::GetAtt":[hr,"Arn"]},s3BucketName:nr,organizedPrefix:"mailboxes/"});this.builder.addResource(Sn,mr),this.builder.addResource(Bn,hn);let Qn=m.createInboundEmailSetup({slug:l,environment:S,domain:Rt,s3BucketName:nr,s3KeyPrefix:"inbox/",region:wt,hostedZoneId:ne,lambdaFunctionArn:{"Fn::GetAtt":[Sn,"Arn"]}});for(let[$i,vn]of Object.entries(Qn.resources)){if(vn.Type==="AWS::SES::ReceiptRule")vn.DependsOn=[Bn,Sn];this.builder.addResource($i,vn)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:Sn},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:nr,Description:"S3 bucket for email storage"});let Ji=this.serverEipLogicalIds.get("app");if(Ji&&ne){let vn=`${Tt?.subdomain||"mail"}.${Rt}`,Fn=vn.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Fn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:ne,Name:vn,Type:"A",TTL:"300",ResourceRecords:[{Ref:Ji}]}})}this.builder.addOutput("MailHost",{Value:`mail.${Rt}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let Jt=this.mergedConfig.infrastructure?.search;if(Jt){let Rt=Jt.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(Rt)this.generateNetworkInfrastructure(l,S);let{domain:Ze,logicalId:Nt}=Ut.createDomain({slug:l,environment:S,engineVersion:Jt.engineVersion||"OpenSearch_2.11",instanceType:Jt.instanceType||"t3.small.search",instanceCount:Jt.instanceCount||1,volumeSize:Jt.volumeSize||10,volumeType:Jt.volumeType||"gp3",dedicatedMaster:Jt.dedicatedMaster||!1,dedicatedMasterType:Jt.dedicatedMasterType,dedicatedMasterCount:Jt.dedicatedMasterCount||3,multiAz:Jt.multiAz||!1,encryption:Jt.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:Jt.advancedSecurity,autoTune:Jt.autoTune!==!1,vpc:Rt});this.builder.addResource(Nt,Ze),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[Nt,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[Nt,"Arn"]},Description:"OpenSearch domain ARN"})}let pr=this.mergedConfig.infrastructure?.fileSystem;if(pr&&Object.keys(pr).length>0){this.generateNetworkInfrastructure(l,S);for(let[Rt,Ze]of Object.entries(pr)){let{fileSystem:Nt,logicalId:ne}=Ue.createFileSystem({slug:`${l}-${Rt}`,environment:S,encrypted:Ze.encrypted!==!1,performanceMode:Ze.performanceMode||"generalPurpose",throughputMode:Ze.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(ne,Nt);let{securityGroup:Tt,logicalId:wt}=Ue.createEfsSecurityGroup({slug:`${l}-${Rt}`,environment:S,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(wt,Tt);let{mountTargets:nr,logicalIds:ir}=Ue.createMultiAzMountTargets(ne,{slug:`${l}-${Rt}`,environment:S,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:wt}});for(let sr=0;sr<nr.length;sr++)this.builder.addResource(ir[sr],nr[sr]);this.builder.addOutput(`${Rt}FileSystemId`,{Value:{Ref:ne},Description:`EFS file system ID for ${Rt}`})}}let Dt=this.mergedConfig.infrastructure?.ai;if(Dt){let Rt=Dt.service||"ecs",Ze=Dt.models||["*"],Nt=Dt.allowStreaming!==!1,ne;if(Rt==="ecs")ne=be.enableBedrockForEcs({slug:l,environment:S,models:Ze,allowStreaming:Nt});else if(Rt==="ec2")ne=be.enableBedrockForEc2({slug:l,environment:S,models:Ze,allowStreaming:Nt});else if(Rt==="lambda")ne=be.enableBedrockForLambda({slug:l,environment:S,models:Ze,allowStreaming:Nt});else ne=be.createBedrockRole(Rt,{slug:l,environment:S,models:Ze,allowStreaming:Nt});if(this.builder.addResource(ne.logicalId,ne.role),Dt.allowAsync){let{policy:Tt,logicalId:wt}=be.createBedrockPolicy({slug:l,environment:S,models:Ze,allowStreaming:Nt,allowAsync:!0});this.builder.addResource(wt,Tt)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[ne.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||{},tt=b.storage||{type:"dynamodb"},we=v.handlerMemory||256,fe=v.handlerTimeout||30,Ye=`${l}${S}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),ft=`${l}${S}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(tt.type==="dynamodb"){let ir=tt.dynamodb||{},sr=ir.billingMode||"PAY_PER_REQUEST";this.builder.addResource(Ye,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${S}-realtime-connections`,BillingMode:sr,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"},...sr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ir.readCapacity||5,WriteCapacityUnits:ir.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...sr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ir.readCapacity||5,WriteCapacityUnits:ir.writeCapacity||5}},...ir.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${l}-${S}-realtime-connections`},{Key:"Environment",Value:S}]}}),this.builder.addResource(ft,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${l}-${S}-realtime-channels`,BillingMode:sr,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"},...sr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ir.readCapacity||5,WriteCapacityUnits:ir.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...sr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:ir.readCapacity||5,WriteCapacityUnits:ir.writeCapacity||5}},Tags:[{Key:"Name",Value:`${l}-${S}-realtime-channels`},{Key:"Environment",Value:S}]}})}let rt=`${l}${S}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(rt,{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":[Ye,"Arn"]},{"Fn::Sub":`\${${Ye}.Arn}/index/*`},{"Fn::GetAtt":[ft,"Arn"]},{"Fn::Sub":`\${${ft}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let or=`${l}${S}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),Jt=`${l}${S}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),pr=`${l}${S}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(or,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[rt,"Arn"]},MemorySize:we,Timeout:fe,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:Ye},CHANNELS_TABLE:{Ref:ft},ENVIRONMENT:S}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[rt,Ye]}),this.builder.addResource(Jt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[rt,"Arn"]},MemorySize:we,Timeout:fe,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:Ye},CHANNELS_TABLE:{Ref:ft},ENVIRONMENT:S}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[rt,Ye,ft]}),this.builder.addResource(pr,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[rt,"Arn"]},MemorySize:we,Timeout:fe,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:Ye},CHANNELS_TABLE:{Ref:ft},ENVIRONMENT:S}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[rt,Ye,ft]});let Dt=`${l}${S}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Dt,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:P,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:P,Environment:S}}});let Rt=`${or}Permission`,Ze=`${Jt}Permission`,Nt=`${pr}Permission`;this.builder.addResource(Rt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:or},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Dt}}/*/$connect`}}}),this.builder.addResource(Ze,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Jt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Dt}}/*/$disconnect`}}}),this.builder.addResource(Nt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:pr},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Dt}}/*/$default`}}});let ne=`${Dt}ConnectInteg`,Tt=`${Dt}DisconnectInteg`,wt=`${Dt}MessageInteg`;this.builder.addResource(ne,{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/\${${or}.Arn}/invocations`}}}),this.builder.addResource(Tt,{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/\${${Jt}.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/\${${pr}.Arn}/invocations`}}}),this.builder.addResource(`${Dt}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Dt},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${ne}}`}}}),this.builder.addResource(`${Dt}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Dt},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${Tt}}`}}}),this.builder.addResource(`${Dt}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Dt},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${wt}}`}}});let nr=`${Dt}Stage`;if(this.builder.addResource(nr,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Dt},StageName:S,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:v.messagesPerSecond||1000,ThrottlingRateLimit:v.messagesPerSecond||1000}}}),b.monitoring?.enabled){let ir=b.monitoring,sr=ir.notificationTopicArn;if(!sr&&ir.notificationEmails?.length){let hr=`${Dt}AlarmTopic`;this.builder.addResource(hr,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),ir.notificationEmails.forEach((Jr,mr)=>{this.builder.addResource(`${hr}Sub${mr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:hr},Protocol:"email",Endpoint:Jr}})}),sr={Ref:hr}}if(ir.connectionThreshold)this.builder.addResource(`${Dt}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${ir.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:ir.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Dt}}],...sr&&{AlarmActions:[sr]}}});if(ir.errorThreshold)this.builder.addResource(`${Dt}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${ir.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:ir.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Dt}}],...sr&&{AlarmActions:[sr]}}})}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`
|
|
13
|
+
`:Xt,Pt=v.map(([,cr])=>cr.port).filter((cr)=>typeof cr==="number"&&![80,443].includes(cr)),xe=this.resolveApiOriginPort(),kt=`${l}${S}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),ne=`${l}-${S}-deploy`;this.builder.addResource(kt,{Type:"AWS::S3::Bucket",Properties:{BucketName:ne,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:b.allowSsh?`${l}-${S}`:void 0,domain:Re,userData:Dt,volumeSize:b.disk?.size||20,imageId:b.image,allowedPorts:[...b.allowSsh?[22]:[],80,443,xe,...Pt]}),wt=It.resources[It.outputs.instanceLogicalId];if(wt?.Properties){let cr=wt.Properties.Tags||[];wt.Properties.Tags=[...cr,{Key:"Project",Value:l},{Key:"Environment",Value:S},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let ar=It.resources[It.outputs.roleLogicalId];if(ar?.Properties)ar.Properties.Policies=ar.Properties.Policies||[],ar.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${ne}`,`arn:aws:s3:::${ne}/*`]}]}});for(let[cr,dr]of Object.entries(It.resources))this.builder.addResource(cr,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 b=this.mergedConfig.infrastructure?.jumpBox;if(!b)return;let P=b===!0?{}:b;if(P.enabled===!1)return;this.generateNetworkInfrastructure(l,S);let v=P.size||"micro",Re=o.InstanceSize.specs[v]?.instanceType||v||"t3.micro",Ae;if(P.mountEfs)Ae={fileSystemId:typeof P.mountEfs==="string"?P.mountEfs:{Ref:"FileSystem"},mountPath:P.mountPath||"/mnt/efs"};let rt;if(P.databaseTools)rt=o.JumpBox.withDatabaseTools({slug:l,environment:S,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:P.keyName||`${l}-${S}`,allowedCidrs:P.allowedCidrs});else if(Ae)rt=o.JumpBox.withEfsMount({slug:l,environment:S,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:P.keyName||`${l}-${S}`,fileSystemId:Ae.fileSystemId,mountPath:Ae.mountPath,allowedCidrs:P.allowedCidrs});else rt=o.createJumpBox({slug:l,environment:S,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:P.keyName||`${l}-${S}`,instanceType:Re,allowedCidrs:P.allowedCidrs,mountEfs:Ae});for(let[Rt,st]of Object.entries(rt.resources))this.builder.addResource(Rt,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 b=this.mergedConfig.infrastructure?.ssl,P=this.mergedConfig.infrastructure?.dns,v=P?.domain,it=P?.hostedZoneId,Re=[],Ae,rt;if(b?.certificateArn)rt=b.certificateArn;else if(b?.enabled&&v&&it){let Pt=b.domains||[v],xe=Pt[0],kt=Pt.slice(1).map((wt)=>{if(wt.includes(".")&&wt.endsWith(xe))return wt.replace(`.${xe}`,"");return wt}),{certificate:ne,logicalId:It}=I.createCertificate({domain:xe,subdomains:kt,slug:l,environment:S,validationMethod:"DNS",hostedZoneId:it});Ae=It,this.builder.addResource(It,ne)}if(this.mergedConfig.infrastructure?.storage){let Pt=Object.entries(this.mergedConfig.infrastructure.storage).some(([,ne])=>ne.website),xe;if(Pt&&(Ae||rt))xe=`${l}${S}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(xe,{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(([ne,It])=>({name:ne,config:It,mountPath:this.normalizeMountPath(It),rewriteStyle:It.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(l,S,ne)})).filter((ne)=>ne.name!=="public"&&ne.config.website&&ne.mountPath);for(let[ne,It]of Object.entries(this.mergedConfig.infrastructure.storage)){let wt=!!(It.website&&xe),ar=this.storageBucketName(l,S,ne),{bucket:cr,logicalId:dr}=Ce.createBucket({slug:l,name:ne,environment:S,bucketName:ar,versioning:It.versioning,encryption:It.encryption,public:wt?!1:It.public});if(wt&&cr.Properties)cr.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(dr,cr),It.website){let en=typeof It.website==="object"?It.website:{},yr=Ce.enableWebsiteHosting(cr,en.indexDocument||"index.html",en.errorDocument);this.builder.addResource(dr,yr)}let Ir=this.normalizeMountPath(It);if(wt&&xe&&v&&!(Ir&&ne!=="public")){let en=`${l}${S}${ne}CDN`.replace(/[^a-zA-Z0-9]/g,""),yr=[];if(It.aliases&&It.aliases.length>0)yr.push(...It.aliases);else if(ne==="public"){if(yr.push(v),b?.domains?.includes(`www.${v}`))yr.push(`www.${v}`)}else if(ne==="docs")yr.push(`docs.${v}`);else if(ne==="blog")yr.push(`blog.${v}`);let Rn=typeof It.website==="object"?It.website:{},In=It.spa===!0,Fn=Rn.errorDocument||(In?"index.html":"404.html"),Vn=[];if(In)Vn.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else Vn.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${Fn}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${Fn}`,ErrorCachingMinTTL:300});let na=rt&&yr.length>0?{AcmCertificateArn:rt,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:Ae&&yr.length>0?{AcmCertificateArn:{Ref:Ae},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Fi=`S3-${l}-${S}-${ne}`,vn=this.mergedConfig.project.region||"us-east-1",Ln;if(!In)Ln=`${l}${S}${ne}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(Ln,{Type:"AWS::CloudFront::Function",Properties:{Name:`${l}-${S}-${ne}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${l} ${S} ${ne} - 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 Va=[{Id:Fi,DomainName:{"Fn::Sub":`\${${dr}}.s3.${vn}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:xe}}],sa=[],Wa=[];if(this.shouldRouteStorageBucketToCompute(ne,It)){this.appendComputeAppOrigin(Va,sa,Wa,l,S,this.resolveComputeCachePathPatterns(It.computeRoutes));for(let on of kt){let Na=`S3-${l}-${S}-${on.name}`,za=`${l}${S}${on.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(za,{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)}}),Va.push({Id:Na,DomainName:{"Fn::Sub":`\${${on.logicalId}}.s3.${vn}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:xe}}),Wa.push(on.logicalId,za);for(let Ol of[on.mountPath,`${on.mountPath}/*`])sa.push({PathPattern:Ol,TargetOriginId:Na,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":[za,"FunctionARN"]}}]})}}let es={Type:"AWS::CloudFront::Distribution",DependsOn:[dr,xe,...Ln?[Ln]:[],...Wa],Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${S} ${ne} site`,DefaultRootObject:"index.html",Origins:Va,DefaultCacheBehavior:{TargetOriginId:Fi,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...Ln?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Ln,"FunctionARN"]}}]}:{}},...sa.length>0?{CacheBehaviors:sa}:{},...yr.length>0?{Aliases:yr}:{},ViewerCertificate:na,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:Vn}}};if(Ae)es.DependsOn.push(Ae);this.builder.addResource(en,es);let Dl=`${dr}CloudFrontPolicy`;if(this.builder.addResource(Dl,{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(ne,It))for(let on of kt){let Na=`${on.logicalId}CloudFrontPolicy`;this.builder.addResource(Na,{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)Re.push({name:ne,bucketLogicalId:dr,distLogicalId:en,oacLogicalId:xe,aliases:yr});this.builder.addOutput(`${ne}CloudFrontDomain`,{Value:{"Fn::GetAtt":[en,"DomainName"]},Description:`CloudFront domain for ${ne}`}),this.builder.addOutput(`${ne}CloudFrontDistributionId`,{Value:{Ref:en},Description:`CloudFront distribution ID for ${ne}`})}if(this.builder.addOutput(`${ne}BucketName`,{Value:{Ref:dr},Description:`S3 bucket name for ${ne}`}),ne==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:dr},Description:"Frontend S3 bucket name"});if(ne==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:dr},Description:"Documentation S3 bucket name"});if(ne==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:dr},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let Pt=this.mergedConfig.infrastructure.sftp,xe=dd.create({...Pt,storage:this.resolveSftpStorage(Pt,l,S)??Pt.storage,slug:l,environment:S});for(let[kt,ne]of Object.entries(xe.resources))this.builder.addResource(kt,ne);this.builder.addOutput("SftpServerId",{Value:{Ref:xe.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${xe.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:xe.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(it&&Re.length>0)for(let{name:Pt,distLogicalId:xe,aliases:kt}of Re)for(let ne of kt){let It=ne.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${It}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[xe],Properties:{HostedZoneId:it,Name:ne,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[xe,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${It}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[xe],Properties:{HostedZoneId:it,Name:ne,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[xe,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[Pt,xe]of Object.entries(this.mergedConfig.infrastructure.databases))if(xe.engine==="dynamodb"){let{table:kt,logicalId:ne}=Ut.createTable({slug:l,environment:S,tableName:`${l}-${S}-${Pt}`,partitionKey:xe.partitionKey||{name:"id",type:"S"},sortKey:xe.sortKey});this.builder.addResource(ne,kt)}else if(xe.engine==="postgres"){let{dbInstance:kt,logicalId:ne}=Ut.createPostgres({slug:l,environment:S,dbInstanceIdentifier:`${l}-${S}-${Pt}`,masterUsername:xe.username||"admin",masterUserPassword:xe.password||"changeme123",allocatedStorage:xe.storage||20,dbInstanceClass:xe.instanceClass||"db.t3.micro"});this.builder.addResource(ne,kt)}else if(xe.engine==="mysql"){let{dbInstance:kt,logicalId:ne}=Ut.createMysql({slug:l,environment:S,dbInstanceIdentifier:`${l}-${S}-${Pt}`,masterUsername:xe.username||"admin",masterUserPassword:xe.password||"changeme123",allocatedStorage:xe.storage||20,dbInstanceClass:xe.instanceClass||"db.t3.micro"});this.builder.addResource(ne,kt)}}if(this.mergedConfig.infrastructure?.cdn)for(let[Pt,xe]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!xe.origin)continue;let kt=typeof xe.customDomain==="string"?xe.customDomain:xe.customDomain?.domain||xe.domain,ne=typeof xe.customDomain==="object"?xe.customDomain?.certificateArn:xe.certificateArn,It=ne||rt,wt=`${l}${S}${Pt}CDN`.replace(/[^a-zA-Z0-9]/g,""),ar=`S3-${l}-${S}-${Pt}-cdn`,cr=[{Id:ar,DomainName:xe.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:xe.originShield?{Enabled:!0,OriginShieldRegion:xe.originShieldRegion||this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1}}],dr=[],Ir=[];if(xe.routeCompute)this.appendComputeAppOrigin(cr,dr,Ir,l,S,this.resolveComputeCachePathPatterns(xe.computeRoutes));let en=It&&kt?{AcmCertificateArn:Ae&&!ne?{Ref:Ae}:It,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},yr=[...Ir];if(Ae&&!ne&&kt)yr.push(Ae);let Rn={Type:"AWS::CloudFront::Distribution",...yr.length>0?{DependsOn:yr}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${l} ${S} ${Pt} CDN`,DefaultRootObject:"index.html",Origins:cr,DefaultCacheBehavior:{TargetOriginId:ar,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:xe.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...dr.length>0?{CacheBehaviors:dr}:{},...kt&&It?{Aliases:[kt]}:{},ViewerCertificate:en,PriceClass:"PriceClass_100",HttpVersion:xe.http3?"http2and3":"http2"}}};if(this.builder.addResource(wt,Rn),it&&kt&&It){let In=kt.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${In}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[wt,...Ae&&!ne?[Ae]:[]],Properties:{HostedZoneId:it,Name:kt,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[wt,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[Pt,xe]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(xe))continue;let{queue:kt,logicalId:ne}=M.createQueue({slug:l,environment:S,name:`${l}-${S}-${Pt}`,fifo:xe.fifo,visibilityTimeout:xe.visibilityTimeout,messageRetentionPeriod:xe.messageRetentionPeriod,delaySeconds:xe.delaySeconds,maxMessageSize:xe.maxMessageSize,receiveMessageWaitTime:xe.receiveMessageWaitTime,contentBasedDeduplication:xe.contentBasedDeduplication,encrypted:xe.encrypted,kmsKeyId:xe.kmsKeyId});this.builder.addResource(ne,kt);let It;if(xe.deadLetterQueue){let{deadLetterQueue:wt,updatedSourceQueue:ar,deadLetterLogicalId:cr}=M.createDeadLetterQueue(ne,{slug:l,environment:S,maxReceiveCount:xe.maxReceiveCount});It=cr,this.builder.addResource(cr,wt);let Ir=this.builder.getResources()[ne];if(Ir?.Properties)Ir.Properties.RedrivePolicy=ar.Properties?.RedrivePolicy}if(xe.trigger){let wt=xe.trigger,ar=`${l}${S}${wt.functionName}`.replace(/[^a-zA-Z0-9]/g,""),cr={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[ne,"Arn"]},FunctionName:{Ref:ar},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:[ne,ar]};this.builder.addResource(`${ne}Trigger`,cr)}if(xe.alarms?.enabled){let wt=xe.alarms,ar=wt.notificationTopicArn;if(!ar&&wt.notificationEmails?.length){let Ir=`${ne}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}})}),ar={Ref:Ir}}let cr=wt.queueDepthThreshold||1000;this.builder.addResource(`${ne}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-${Pt}-queue-depth`,AlarmDescription:`Queue ${Pt} depth exceeds ${cr} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:cr,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ne,"QueueName"]}}],...ar&&{AlarmActions:[ar],OKActions:[ar]}}});let dr=wt.messageAgeThreshold||3600;if(this.builder.addResource(`${ne}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":[ne,"QueueName"]}}],...ar&&{AlarmActions:[ar],OKActions:[ar]}}}),It&&wt.dlqAlarm!==!1)this.builder.addResource(`${It}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":[It,"QueueName"]}}],...ar&&{AlarmActions:[ar]}}})}if(xe.subscribe){let wt=xe.subscribe,ar=wt.topicArn;if(!ar&&wt.topicName)ar={Ref:wt.topicName};if(ar){this.builder.addResource(`${ne}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:ne}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[ne,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":ar}}}]}}});let cr={TopicArn:ar,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[ne,"Arn"]},RawMessageDelivery:wt.rawMessageDelivery||!1};if(wt.filterPolicy)cr.FilterPolicy=wt.filterPolicy,cr.FilterPolicyScope=wt.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${ne}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:cr,DependsOn:`${ne}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||"",xe=Rt.protocol||"https";if(Rt.domains?.length&&Pt)for(let kt of Rt.domains){let{bucket:ne,bucketPolicy:It,logicalId:wt,policyLogicalId:ar}=pt.createDomainRedirectBucket({slug:l,environment:S,sourceDomain:kt,targetDomain:Pt,protocol:xe});this.builder.addResource(wt,ne),this.builder.addResource(ar,It)}if(Rt.paths&&Object.keys(Rt.paths).length>0){let kt=pt.fromMapping(Rt.paths,{statusCode:Rt.statusCode||301}),{function:ne,logicalId:It}=pt.createPathRedirectFunction({slug:l,environment:S,rules:kt});this.builder.addResource(It,ne)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[Pt,xe]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:kt,logicalId:ne}=Js.createAlarm({slug:l,environment:S,alarmName:`${l}-${S}-${Pt}`,metricName:xe.metricName||"Errors",namespace:xe.namespace||"AWS/Lambda",threshold:xe.threshold||1,comparisonOperator:xe.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(ne,kt)}let st=this.mergedConfig.infrastructure?.cache;if(st){let Pt=st.type||"redis";if(Pt==="redis"){this.generateNetworkInfrastructure(l,S);let xe=st.redis||{},{replicationGroup:kt,subnetGroup:ne,logicalId:It,subnetGroupId:wt}=Ws.createRedis({slug:l,environment:S,nodeType:xe.nodeType||st.nodeType||"cache.t3.micro",engineVersion:xe.engineVersion||"7.1",port:xe.port||6379,numCacheClusters:xe.numCacheNodes||2,automaticFailover:xe.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:xe.snapshotRetentionLimit||7,snapshotWindow:xe.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(It,kt),ne&&wt)this.builder.addResource(wt,ne);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(Pt==="memcached"){this.generateNetworkInfrastructure(l,S);let xe=st.elasticache||{},{cluster:kt,subnetGroup:ne,logicalId:It,subnetGroupId:wt}=Ws.createMemcached({slug:l,environment:S,nodeType:xe.nodeType||st.nodeType||"cache.t3.micro",engineVersion:xe.engineVersion||"1.6.22",numCacheNodes:xe.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(It,kt),ne&&wt)this.builder.addResource(wt,ne);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[It,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let lr=this.mergedConfig.infrastructure?.email;if(lr){let Pt=lr.domain||this.mergedConfig.infrastructure?.dns?.domain;if(Pt){let{emailIdentity:xe,logicalId:kt}=m.verifyDomain({domain:Pt,slug:l,environment:S,enableDkim:lr.enableDkim!==!1,dkimKeyLength:lr.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(kt,xe),lr.configurationSet!==!1){let{configurationSet:wt,logicalId:ar}=m.createConfigurationSet({slug:l,environment:S});this.builder.addResource(ar,wt)}let ne=lr.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(ne){if(lr.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:ne,Name:{"Fn::GetAtt":[kt,`DkimDNSTokenName${Ir}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[kt,`DkimDNSTokenValue${Ir}`]}]}})}let{record:wt,logicalId:ar}=m.createSpfRecord(Pt,ne);this.builder.addResource(ar,wt);let{record:cr,logicalId:dr}=m.createDmarcRecord(Pt,ne,{policy:"none",reportingEmail:lr.dmarcReportingEmail||`dmarc-reports@${Pt}`});this.builder.addResource(dr,cr)}this.builder.addOutput("EmailDomain",{Value:Pt,Description:"SES verified email domain"});let It=lr.server;if(It?.enabled&&ne){let wt=this.mergedConfig.environments[S]?.region||this.mergedConfig.project.region||"us-east-1",ar=`${l}-${S}-email`,{role:cr,policy:dr,roleLogicalId:Ir,policyLogicalId:en}=m.createEmailLambdaRole({slug:l,environment:S,s3BucketArn:`arn:aws:s3:::${ar}`,sesIdentityArn:`arn:aws:ses:${wt}:*:identity/${Pt}`});this.builder.addResource(Ir,cr),this.builder.addResource(en,dr);let{function:yr,permission:Rn,logicalId:In,permissionLogicalId:Fn}=m.createInboundEmailLambda({slug:l,environment:S,roleArn:{"Fn::GetAtt":[Ir,"Arn"]},s3BucketName:ar,organizedPrefix:"mailboxes/"});this.builder.addResource(In,yr),this.builder.addResource(Fn,Rn);let Vn=m.createInboundEmailSetup({slug:l,environment:S,domain:Pt,s3BucketName:ar,s3KeyPrefix:"inbox/",region:wt,hostedZoneId:ne,lambdaFunctionArn:{"Fn::GetAtt":[In,"Arn"]}});for(let[Fi,vn]of Object.entries(Vn.resources)){if(vn.Type==="AWS::SES::ReceiptRule")vn.DependsOn=[Fn,In];this.builder.addResource(Fi,vn)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:In},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:ar,Description:"S3 bucket for email storage"});let na=this.serverEipLogicalIds.get("app");if(na&&ne){let vn=`${It?.subdomain||"mail"}.${Pt}`,Ln=vn.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Ln}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:ne,Name:vn,Type:"A",TTL:"300",ResourceRecords:[{Ref:na}]}})}this.builder.addOutput("MailHost",{Value:`mail.${Pt}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let Xt=this.mergedConfig.infrastructure?.search;if(Xt){let Pt=Xt.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(Pt)this.generateNetworkInfrastructure(l,S);let{domain:xe,logicalId:kt}=Qt.createDomain({slug:l,environment:S,engineVersion:Xt.engineVersion||"OpenSearch_2.11",instanceType:Xt.instanceType||"t3.small.search",instanceCount:Xt.instanceCount||1,volumeSize:Xt.volumeSize||10,volumeType:Xt.volumeType||"gp3",dedicatedMaster:Xt.dedicatedMaster||!1,dedicatedMasterType:Xt.dedicatedMasterType,dedicatedMasterCount:Xt.dedicatedMasterCount||3,multiAz:Xt.multiAz||!1,encryption:Xt.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:Xt.advancedSecurity,autoTune:Xt.autoTune!==!1,vpc:Pt});this.builder.addResource(kt,xe),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,xe]of Object.entries(fr)){let{fileSystem:kt,logicalId:ne}=Ge.createFileSystem({slug:`${l}-${Pt}`,environment:S,encrypted:xe.encrypted!==!1,performanceMode:xe.performanceMode||"generalPurpose",throughputMode:xe.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(ne,kt);let{securityGroup:It,logicalId:wt}=Ge.createEfsSecurityGroup({slug:`${l}-${Pt}`,environment:S,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(wt,It);let{mountTargets:ar,logicalIds:cr}=Ge.createMultiAzMountTargets(ne,{slug:`${l}-${Pt}`,environment:S,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:wt}});for(let dr=0;dr<ar.length;dr++)this.builder.addResource(cr[dr],ar[dr]);this.builder.addOutput(`${Pt}FileSystemId`,{Value:{Ref:ne},Description:`EFS file system ID for ${Pt}`})}}let Dt=this.mergedConfig.infrastructure?.ai;if(Dt){let Pt=Dt.service||"ecs",xe=Dt.models||["*"],kt=Dt.allowStreaming!==!1,ne;if(Pt==="ecs")ne=Ee.enableBedrockForEcs({slug:l,environment:S,models:xe,allowStreaming:kt});else if(Pt==="ec2")ne=Ee.enableBedrockForEc2({slug:l,environment:S,models:xe,allowStreaming:kt});else if(Pt==="lambda")ne=Ee.enableBedrockForLambda({slug:l,environment:S,models:xe,allowStreaming:kt});else ne=Ee.createBedrockRole(Pt,{slug:l,environment:S,models:xe,allowStreaming:kt});if(this.builder.addResource(ne.logicalId,ne.role),Dt.allowAsync){let{policy:It,logicalId:wt}=Ee.createBedrockPolicy({slug:l,environment:S,models:xe,allowStreaming:kt,allowAsync:!0});this.builder.addResource(wt,It)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[ne.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"},Re=v.handlerMemory||256,Ae=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 cr=it.dynamodb||{},dr=cr.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:cr.readCapacity||5,WriteCapacityUnits:cr.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:cr.readCapacity||5,WriteCapacityUnits:cr.writeCapacity||5}},...cr.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:cr.readCapacity||5,WriteCapacityUnits:cr.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...dr==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:cr.readCapacity||5,WriteCapacityUnits:cr.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 lr=`${l}${S}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),Xt=`${l}${S}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),fr=`${l}${S}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(lr,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[st,"Arn"]},MemorySize:Re,Timeout:Ae,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:rt},CHANNELS_TABLE:{Ref:Rt},ENVIRONMENT:S}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[st,rt]}),this.builder.addResource(Xt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${l}-${S}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[st,"Arn"]},MemorySize:Re,Timeout:Ae,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:Re,Timeout:Ae,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:rt},CHANNELS_TABLE:{Ref:Rt},ENVIRONMENT:S}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[st,rt,Rt]});let Dt=`${l}${S}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Dt,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:P,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:P,Environment:S}}});let Pt=`${lr}Permission`,xe=`${Xt}Permission`,kt=`${fr}Permission`;this.builder.addResource(Pt,{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}}/*/$connect`}}}),this.builder.addResource(xe,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Xt},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 ne=`${Dt}ConnectInteg`,It=`${Dt}DisconnectInteg`,wt=`${Dt}MessageInteg`;this.builder.addResource(ne,{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(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/\${${Xt}.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/\${${ne}}`}}}),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 ar=`${Dt}Stage`;if(this.builder.addResource(ar,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Dt},StageName:S,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:v.messagesPerSecond||1000,ThrottlingRateLimit:v.messagesPerSecond||1000}}}),b.monitoring?.enabled){let cr=b.monitoring,dr=cr.notificationTopicArn;if(!dr&&cr.notificationEmails?.length){let Ir=`${Dt}AlarmTopic`;this.builder.addResource(Ir,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),cr.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(cr.connectionThreshold)this.builder.addResource(`${Dt}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${cr.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:cr.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Dt}}],...dr&&{AlarmActions:[dr]}}});if(cr.errorThreshold)this.builder.addResource(`${Dt}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${l}-${S}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${cr.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:cr.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref: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 b=this.mergedConfig.infrastructure?.realtime;if(!b)return;let P=b.server||{},v=P.port||6001,
|
|
173
|
+
`.trim()}generateRealtimeServerResources(l,S){let b=this.mergedConfig.infrastructure?.realtime;if(!b)return;let P=b.server||{},v=P.port||6001,it=P.instances||1,Re=`${l}${S}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Re,{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 Ae=`${l}${S}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),rt=`${l}${S}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),Rt=`${l}${S}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Rt,{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:"*"},...P.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let st=[{Name:"BROADCAST_HOST",Value:P.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(v)},{Name:"NODE_ENV",Value:S==="production"?"production":"development"}];if(P.redis?.enabled){if(P.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:P.redis.host||"localhost"}),st.push({Name:"REDIS_PORT",Value:String(P.redis.port||6379)});if(P.redis.keyPrefix)st.push({Name:"REDIS_KEY_PREFIX",Value:P.redis.keyPrefix})}this.builder.addResource(Ae,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${l}-${S}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[Rt,"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}${P.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${l}-${S}-realtime`},{Key:"Environment",Value:S}]},DependsOn:[Rt,rt]});let lr=`${l}${S}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(lr,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${l}-${S}-realtime`,RetentionInDays:30}});let Xt=`${l}${S}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Xt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${l}-${S}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:Ae},DesiredCount:it,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Re}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${l}-${S}-realtime`},{Key:"Environment",Value:S}]},DependsOn:[Ae,Re,lr]}),P.autoScaling){let fr=P.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:Xt}),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(b.monitoring?.enabled){let fr=b.monitoring,Dt=fr.notificationTopicArn;if(!Dt&&fr.notificationEmails?.length){let Pt=`${l}${S}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${l}-${S}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),fr.notificationEmails.forEach((xe,kt)=>{this.builder.addResource(`${Pt}Sub${kt}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Pt},Protocol:"email",Endpoint:xe}})}),Dt={Ref:Pt}}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:Xt}),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:Xt})}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 Ml(l){let S=[],b=[];if(!l.AWSTemplateFormatVersion)S.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(l.AWSTemplateFormatVersion!=="2010-09-09")b.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[P,v]of Object.entries(l.Resources))Wl(P,v,S,b);if(l.Resources){let P=Jl(l.Resources);if(P.length>0)S.push({path:"Resources",message:`Circular dependencies detected: ${P.join(" -> ")}`,severity:"error"})}if(l.Parameters)for(let[P,v]of Object.entries(l.Parameters))zl(P,v,S,b);if(l.Outputs)for(let[P,v]of Object.entries(l.Outputs))jl(P,v,S,b);return{valid:S.length===0,errors:S,warnings:b}}function Wl(l,S,b,P){if(!S.Type)b.push({path:`Resources.${l}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(l))P.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::"))b.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)P.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)b.push({path:`Resources.${l}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(S.DependsOn)){if(S.DependsOn.includes(l))b.push({path:`Resources.${l}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function zl(l,S,b,P){if(!S.Type)b.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::"))P.push({path:`Parameters.${l}.Type`,message:`Uncommon parameter type: ${S.Type}`,severity:"warning"});if(S.NoEcho&&S.Default)P.push({path:`Parameters.${l}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function jl(l,S,b,P){if(!S.Value)b.push({path:`Outputs.${l}.Value`,message:"Output Value is required",severity:"error"})}function Jl(l){let S={};for(let[Re,Ae]of Object.entries(l)){if(S[Re]=[],Ae.DependsOn){if(typeof Ae.DependsOn==="string")S[Re].push(Ae.DependsOn);else if(Array.isArray(Ae.DependsOn))S[Re].push(...Ae.DependsOn)}let rt=Ua(Ae);S[Re].push(...rt)}let b=new Set,P=new Set,v=[];function it(Re,Ae){b.add(Re),P.add(Re),Ae.push(Re);let rt=S[Re]||[];for(let Rt of rt)if(!b.has(Rt)){if(it(Rt,Ae))return!0}else if(P.has(Rt)){let st=Ae.indexOf(Rt);return v.push(...Ae.slice(st),Rt),!0}return Ae.pop(),P.delete(Re),!1}for(let Re of Object.keys(S))if(!b.has(Re)){if(it(Re,[]))return v}return[]}function Ua(l,S=[]){if(typeof l!=="object"||l===null)return S;if(Array.isArray(l)){for(let b of l)Ua(b,S);return S}if(l.Ref&&typeof l.Ref==="string"&&!l.Ref.startsWith("AWS::"))S.push(l.Ref);if(l["Fn::GetAtt"]){let b=l["Fn::GetAtt"];if(Array.isArray(b)&&b.length>0)S.push(b[0])}for(let b of Object.values(l))Ua(b,S);return S}function Xl(l){let S=[],b=[],P=new TextEncoder().encode(l).length,v=51200,it=460800;if(P>51200)if(P>460800)S.push({path:"template",message:`Template size (${P} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else b.push({path:"template",message:`Template size (${P} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:S.length===0,errors:S,warnings:b}}function Pd(l){let S=[],b=[],P=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(P>500)S.push({path:"Resources",message:`Template has ${P} resources, exceeding the limit of 500`,severity:"error"});else if(P>200)b.push({path:"Resources",message:`Template has ${P} 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:b}}function Lm(l){let{domains:S,email:b,staging:P=!1,challengeType:v="http-01",certPath:it="/etc/letsencrypt/live",autoRenew:Re=!0}=l,Ae=S[0],rt=S.map((st)=>`-d ${st}`).join(" "),Rt=P?"--staging":"";if(v==="http-01")return iu({domains:S,email:b,staging:P,certPath:it,autoRenew:Re,domainFlags:rt,stagingFlag:Rt,primaryDomain:Ae});else{let st=l.dnsProvider?.provider||(l.hostedZoneId?"route53":void 0);return ou({domains:S,email:b,staging:P,certPath:it,autoRenew:Re,domainFlags:rt,stagingFlag:Rt,primaryDomain:Ae,hostedZoneId:l.hostedZoneId,dnsProvider:l.dnsProvider,dnsProviderType:st})}}function iu(l){let{email:S,certPath:b,autoRenew:P,domainFlags:v,stagingFlag:it,primaryDomain:Re}=l;return`
|
|
223
223
|
# ==========================================
|
|
224
224
|
# Let's Encrypt Certificate Setup (HTTP-01)
|
|
225
225
|
# ==========================================
|
|
@@ -236,28 +236,28 @@ certbot certonly \\
|
|
|
236
236
|
--non-interactive \\
|
|
237
237
|
--agree-tos \\
|
|
238
238
|
--email ${S} \\
|
|
239
|
-
${
|
|
239
|
+
${it} \\
|
|
240
240
|
${v}
|
|
241
241
|
|
|
242
242
|
# Check if certificate was obtained
|
|
243
|
-
if [ -f "${b}/${
|
|
243
|
+
if [ -f "${b}/${Re}/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 ${b}/${
|
|
249
|
-
ln -sf ${b}/${
|
|
250
|
-
ln -sf ${b}/${
|
|
251
|
-
ln -sf ${b}/${
|
|
248
|
+
ln -sf ${b}/${Re}/fullchain.pem /etc/ssl/stacks/fullchain.pem
|
|
249
|
+
ln -sf ${b}/${Re}/privkey.pem /etc/ssl/stacks/privkey.pem
|
|
250
|
+
ln -sf ${b}/${Re}/cert.pem /etc/ssl/stacks/cert.pem
|
|
251
|
+
ln -sf ${b}/${Re}/chain.pem /etc/ssl/stacks/chain.pem
|
|
252
252
|
else
|
|
253
253
|
echo "Failed to obtain certificate!"
|
|
254
254
|
fi
|
|
255
255
|
|
|
256
|
-
${P?
|
|
256
|
+
${P?Ka(Re):"# Auto-renewal disabled"}
|
|
257
257
|
|
|
258
258
|
# Restart the application
|
|
259
259
|
systemctl start stacks
|
|
260
|
-
`}function
|
|
260
|
+
`}function ou(l){let{email:S,certPath:b,autoRenew:P,domainFlags:v,stagingFlag:it,primaryDomain:Re,hostedZoneId:Ae,dnsProvider:rt,dnsProviderType:Rt}=l;if(Rt==="route53"||Ae){if(!Ae)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
|
|
261
261
|
# ==========================================
|
|
262
262
|
# Let's Encrypt Certificate Setup (DNS-01 via Route53)
|
|
263
263
|
# ==========================================
|
|
@@ -271,48 +271,48 @@ certbot certonly \\
|
|
|
271
271
|
--non-interactive \\
|
|
272
272
|
--agree-tos \\
|
|
273
273
|
--email ${S} \\
|
|
274
|
-
${
|
|
274
|
+
${it} \\
|
|
275
275
|
${v}
|
|
276
276
|
|
|
277
277
|
# Check if certificate was obtained
|
|
278
|
-
if [ -f "${b}/${
|
|
278
|
+
if [ -f "${b}/${Re}/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 ${b}/${
|
|
284
|
-
ln -sf ${b}/${
|
|
285
|
-
ln -sf ${b}/${
|
|
286
|
-
ln -sf ${b}/${
|
|
283
|
+
ln -sf ${b}/${Re}/fullchain.pem /etc/ssl/stacks/fullchain.pem
|
|
284
|
+
ln -sf ${b}/${Re}/privkey.pem /etc/ssl/stacks/privkey.pem
|
|
285
|
+
ln -sf ${b}/${Re}/cert.pem /etc/ssl/stacks/cert.pem
|
|
286
|
+
ln -sf ${b}/${Re}/chain.pem /etc/ssl/stacks/chain.pem
|
|
287
287
|
else
|
|
288
288
|
echo "Failed to obtain certificate!"
|
|
289
289
|
fi
|
|
290
290
|
|
|
291
|
-
${P?
|
|
292
|
-
`}if(!
|
|
291
|
+
${P?Ka(Re):"# 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(),lr=au(rt);return`
|
|
293
293
|
# ==========================================
|
|
294
|
-
# Let's Encrypt Certificate Setup (DNS-01 via ${
|
|
294
|
+
# Let's Encrypt Certificate Setup (DNS-01 via ${st})
|
|
295
295
|
# ==========================================
|
|
296
296
|
|
|
297
297
|
# Install certbot
|
|
298
298
|
dnf install -y certbot jq curl
|
|
299
299
|
|
|
300
|
-
${
|
|
300
|
+
${lr}
|
|
301
301
|
|
|
302
302
|
# Create DNS challenge hook scripts directory
|
|
303
303
|
mkdir -p /etc/letsencrypt/hooks
|
|
304
304
|
|
|
305
|
-
# Create authenticator hook for ${
|
|
305
|
+
# Create authenticator hook for ${st}
|
|
306
306
|
cat > /etc/letsencrypt/hooks/auth-hook.sh << 'AUTHHOOK'
|
|
307
307
|
#!/bin/bash
|
|
308
|
-
# DNS-01 authenticator hook for ${
|
|
308
|
+
# DNS-01 authenticator hook for ${st}
|
|
309
309
|
# This creates the TXT record for ACME challenge
|
|
310
310
|
|
|
311
311
|
DOMAIN="$CERTBOT_DOMAIN"
|
|
312
312
|
VALIDATION="$CERTBOT_VALIDATION"
|
|
313
313
|
RECORD_NAME="_acme-challenge.$DOMAIN"
|
|
314
314
|
|
|
315
|
-
${
|
|
315
|
+
${su(rt)}
|
|
316
316
|
|
|
317
317
|
# Wait for DNS propagation
|
|
318
318
|
echo "Waiting 60 seconds for DNS propagation..."
|
|
@@ -321,17 +321,17 @@ AUTHHOOK
|
|
|
321
321
|
|
|
322
322
|
chmod +x /etc/letsencrypt/hooks/auth-hook.sh
|
|
323
323
|
|
|
324
|
-
# Create cleanup hook for ${
|
|
324
|
+
# Create cleanup hook for ${st}
|
|
325
325
|
cat > /etc/letsencrypt/hooks/cleanup-hook.sh << 'CLEANUPHOOK'
|
|
326
326
|
#!/bin/bash
|
|
327
|
-
# DNS-01 cleanup hook for ${
|
|
327
|
+
# DNS-01 cleanup hook for ${st}
|
|
328
328
|
# This removes the TXT record after validation
|
|
329
329
|
|
|
330
330
|
DOMAIN="$CERTBOT_DOMAIN"
|
|
331
331
|
VALIDATION="$CERTBOT_VALIDATION"
|
|
332
332
|
RECORD_NAME="_acme-challenge.$DOMAIN"
|
|
333
333
|
|
|
334
|
-
${
|
|
334
|
+
${cu(rt)}
|
|
335
335
|
CLEANUPHOOK
|
|
336
336
|
|
|
337
337
|
chmod +x /etc/letsencrypt/hooks/cleanup-hook.sh
|
|
@@ -345,25 +345,25 @@ certbot certonly \\
|
|
|
345
345
|
--non-interactive \\
|
|
346
346
|
--agree-tos \\
|
|
347
347
|
--email ${S} \\
|
|
348
|
-
${
|
|
348
|
+
${it} \\
|
|
349
349
|
${v}
|
|
350
350
|
|
|
351
351
|
# Check if certificate was obtained
|
|
352
|
-
if [ -f "${b}/${
|
|
352
|
+
if [ -f "${b}/${Re}/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 ${b}/${
|
|
358
|
-
ln -sf ${b}/${
|
|
359
|
-
ln -sf ${b}/${
|
|
360
|
-
ln -sf ${b}/${
|
|
357
|
+
ln -sf ${b}/${Re}/fullchain.pem /etc/ssl/stacks/fullchain.pem
|
|
358
|
+
ln -sf ${b}/${Re}/privkey.pem /etc/ssl/stacks/privkey.pem
|
|
359
|
+
ln -sf ${b}/${Re}/cert.pem /etc/ssl/stacks/cert.pem
|
|
360
|
+
ln -sf ${b}/${Re}/chain.pem /etc/ssl/stacks/chain.pem
|
|
361
361
|
else
|
|
362
362
|
echo "Failed to obtain certificate!"
|
|
363
363
|
fi
|
|
364
364
|
|
|
365
|
-
${P?
|
|
366
|
-
`}function
|
|
365
|
+
${P?Ka(Re):"# Auto-renewal disabled"}
|
|
366
|
+
`}function au(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 su(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 cu(l){switch(l.provider){case"porkbun":return`
|
|
422
422
|
# Extract root domain
|
|
423
423
|
ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
|
|
424
424
|
|
|
@@ -461,7 +461,7 @@ fi
|
|
|
461
461
|
|
|
462
462
|
curl -s -X DELETE "$API_URL/v1/domains/$ROOT_DOMAIN/records/TXT/$RECORD_NAME" \\
|
|
463
463
|
-H "Authorization: sso-key $GODADDY_API_KEY:$GODADDY_API_SECRET"
|
|
464
|
-
`;default:return'echo "Unsupported DNS provider"'}}function
|
|
464
|
+
`;default:return'echo "Unsupported DNS provider"'}}function Ka(l){return`
|
|
465
465
|
# ==========================================
|
|
466
466
|
# Certificate Auto-Renewal Setup
|
|
467
467
|
# ==========================================
|
|
@@ -506,7 +506,7 @@ systemctl enable certbot-renewal.timer
|
|
|
506
506
|
systemctl start certbot-renewal.timer
|
|
507
507
|
|
|
508
508
|
echo "Certificate auto-renewal configured"
|
|
509
|
-
`}function
|
|
509
|
+
`}function Fm(l){let{httpPort:S=80,httpsPort:b=443,certPath:P="/etc/ssl/stacks",redirectHttp:v=!0}=l;return`
|
|
510
510
|
// HTTPS Server with Let's Encrypt certificates
|
|
511
511
|
import { readFileSync, existsSync } from 'node:fs'
|
|
512
512
|
|
|
@@ -592,5 +592,5 @@ async function handleRequest(request: Request): Promise<Response> {
|
|
|
592
592
|
// Implement your request handling here
|
|
593
593
|
return new Response('Hello from Stacks!')
|
|
594
594
|
}
|
|
595
|
-
`}async function
|
|
596
|
-
`).filter((tt)=>!tt.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=Qa("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 tt=this.base64UrlEncode(JSON.stringify(v)),we=S===""?"":this.base64UrlEncode(JSON.stringify(S)),fe=`${tt}.${we}`,Ye=nu("SHA256");Ye.update(fe);let ft=Ye.sign(this.accountKey),rt=ft.subarray(4,4+ft[3]),or=4+ft[3]+2,Jt=ft.subarray(or,or+ft[or-1]),pr=Buffer.alloc(32),Dt=Buffer.alloc(32);rt.copy(pr,32-rt.length),Jt.copy(Dt,32-Jt.length);let Rt=Buffer.concat([pr,Dt]);return JSON.stringify({protected:tt,payload:we,signature:this.base64UrlEncode(Rt)})}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 tt,we=P.headers.get("content-type");if(we?.includes("application/json")||we?.includes("application/problem+json"))tt=await P.json();else tt=await P.text();if(!P.ok)throw Error(`ACME request failed: ${JSON.stringify(tt)}`);return{body:tt,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((tt)=>({type:"dns",value:tt}))}),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((tt)=>tt.type==="http-01"||tt.type==="dns-01").map((tt)=>{let we=`${tt.token}.${P}`;if(tt.type==="http-01")return{type:"http-01",token:tt.token,keyAuthorization:we,identifier:`/.well-known/acme-challenge/${tt.token}`};else{let fe=this.base64UrlEncode(Qa("sha256").update(we).digest());return{type:"dns-01",token:tt.token,keyAuthorization:we,identifier:`_acme-challenge.${b}`,dnsValue:fe}}});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}=as("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"))}),tt=v.certificate;if(!tt)throw Error("Certificate not immediately available - polling not implemented");let fe=await(await fetch(tt)).text(),Ye=fe.split(/(?=-----BEGIN CERTIFICATE-----)/g),ft=Ye[0],rt=Ye.slice(1).join("");return{certificate:ft,privateKey:P,chain:rt,fullchain:fe,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var ds=["js","mjs","cjs","css","map","woff","woff2","ttf","otf","eot","png","jpg","jpeg","gif","webp","avif","svg","ico","mp4","webm","ogg","mp3","wav","pdf","wasm"],ou=[{name:"x-stx-router",value:"true"}];function Vi(l){return`"${l.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`}function ec(l){return`{${l.map(Vi).join(" ")}}`}function au(l){let S=`http.request.headers[${Vi(l.name.toLowerCase())}]`;return l.value===void 0?`len(${S}) > 0`:`any(${S}[*] == ${Vi(l.value)})`}function Va(l){if(l.length===1)return`http.host eq ${Vi(l[0])}`;return`http.host in ${ec(l)}`}function Wa(l,S={}){if(S.enabled===!1||l.length===0)return[];let b=Va(l),P=[],tt=(S.bypassPaths??[]).map((pr)=>`starts_with(http.request.uri.path, ${Vi(pr)})`),fe=(S.negotiatedRequestHeaders??ou).map(au),Ye=[...tt,...fe],ft=Ye.length>0?`(${Ye.join(" or ")})`:void 0;if(ft)P.push({action:"set_cache_settings",description:"bypass cache",expression:`(${b} and ${ft})`,enabled:!0,action_parameters:{cache:!1}});let rt=ft?`${b} and not ${ft}`:b,or=S.assetExtensions??ds,Jt=or.length>0?`lower(http.request.uri.path.extension) in ${ec([...or])}`:void 0;if(Jt)P.push({action:"set_cache_settings",description:"cache fingerprinted assets",expression:`(${rt} and ${Jt})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:S.assetEdgeTtl??2592000},browser_ttl:{mode:"override_origin",default:S.assetBrowserTtl??31536000}}});return P.push({action:"set_cache_settings",description:"cache documents",expression:Jt?`(${rt} and not ${Jt})`:`(${rt})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:S.documentEdgeTtl??3600},browser_ttl:{mode:"override_origin",default:S.documentBrowserTtl??0}}}),P}function Ha(l,S,b){if(l.length===0||!S||!b)return[];return[{action:"rewrite",description:"origin guard header",expression:`(${Va(l)})`,enabled:!0,action_parameters:{headers:{[S]:{operation:"set",value:b}}}}]}var En=(l)=>l===void 0?void 0:l?"on":"off";function Ga(l){let S={ssl:l.ssl,always_use_https:En(l.alwaysUseHttps),automatic_https_rewrites:En(l.automaticHttpsRewrites),min_tls_version:l.minTlsVersion,tls_1_3:En(l.tls13),brotli:En(l.brotli),http3:En(l.http3),"0rtt":En(l.zeroRtt),early_hints:En(l.earlyHints),browser_cache_ttl:l.browserCacheTtl,always_online:En(l.alwaysOnline),websockets:En(l.websockets),email_obfuscation:En(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 su}from"node:tls";async function ja(l){let{address:S,serverName:b,port:P=443,timeoutMs:v=5000}=l;return new Promise((tt)=>{let we=!1,fe=(ft)=>{if(we)return;we=!0;try{Ye.destroy()}catch{}tt(ft)},Ye=su({host:S,port:P,servername:b,rejectUnauthorized:!1,timeout:v});Ye.once("secureConnect",()=>{if(Ye.authorized){fe({reachable:!0,trusted:!0});return}fe({reachable:!0,trusted:!1,reason:Ye.authorizationError?String(Ye.authorizationError):"origin certificate is not trusted for this hostname"})}),Ye.once("timeout",()=>{fe({reachable:!1,trusted:!1,reason:`no TLS handshake within ${v}ms`})}),Ye.once("error",(ft)=>{fe({reachable:!1,trusted:!1,reason:ft.message})})})}function cu(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 tt=v.slice(2);if(!b.endsWith(`.${tt}`))return!1;return!b.slice(0,b.length-tt.length-1).includes(".")})}async function lu(l){let{provider:S,zone:b,hosts:P,ipv4:v,ipv6:tt,proxied:we=!0,settings:fe=ji,cache:Ye,originGuard:ft,purge:rt=!0,ttl:or=300,skipOriginProbe:Jt=!1,skipEdgeCertificateCheck:pr=!1}=l,Dt={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(P.length===0)return Dt;let Rt=[],Ze=we&&!pr?await S.listEdgeCertificateHosts(b):null;for(let ne of P){let Tt=we;if(Tt&&Ze&&!cu(Ze,ne)){Tt=!1;let nr=Ze.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${Ze.join(", ")})`;Dt.deferredProxy.push({host:ne,reason:nr}),Dt.warnings.push(`${ne}: publishing DNS-only — ${nr}. 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(Tt&&!Jt){let nr=await ja({address:v,serverName:ne});if(!nr.trusted){Tt=!1;let ir=nr.reason||"origin is not serving a trusted certificate";Dt.deferredProxy.push({host:ne,reason:ir}),Dt.warnings.push(`${ne}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${ir}). 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(Tt)Rt.push(ne);let wt=[{type:"A",content:v}];if(tt&&mn(ne))wt.push({type:"AAAA",content:tt});for(let{type:nr,content:ir}of wt){let sr=await S.upsertRecord(b,{name:ne,type:nr,content:ir,ttl:or,proxied:Tt});if(sr.success)Dt.records.push({host:ne,type:nr,content:ir,proxied:Tt});else Dt.warnings.push(`${ne} ${nr} → ${ir} failed: ${sr.message||"unknown provider error"}`)}}if(Rt.length===0){if(we)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 ne=Ga(fe),Tt=await S.applyZoneSettings(b,ne);Dt.settingsChanged=Tt.changed;for(let wt of Tt.failed)Dt.warnings.push(`zone setting '${wt.id}' could not be applied: ${wt.error}`)}catch(ne){Dt.warnings.push(`zone settings could not be read: ${ne instanceof Error?ne.message:String(ne)}`)}let Nt=Wa(Rt,Ye);if(Nt.length>0){let ne=await S.putManagedPhaseRules(b,"http_request_cache_settings",Nt);if(ne.success)Dt.cacheRules=Nt.length;else Dt.warnings.push(`cache rules could not be written: ${ne.message}`)}if(ft){let ne=Ha(Rt,ft.header,ft.value);if(ne.length>0){let Tt=await S.putManagedPhaseRules(b,"http_request_late_transform",ne);if(Tt.success)Dt.originGuard=!0;else Dt.warnings.push(`origin guard header could not be written: ${Tt.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(rt){if(Dt.purged=await S.purgeCache(b,{hosts:Rt}),!Dt.purged)Dt.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Dt}var du=(l)=>process.env[l];function tc(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 uu(l,S={}){let b=S.env??du,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 tt=b("CLOUDFLARE_API_TOKEN");if(!tt)return v.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:v};let we=l.sites??{},fe=P.frontedHosts?.length?[...new Set(P.frontedHosts.map((Jt)=>Jt.toLowerCase()))]:In(we,{autoWww:l.infrastructure?.compute?.proxy?.autoWww!==!1});if(fe.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 Ye=l.infrastructure?.dns?.domain,ft=new Set(fe.map((Jt)=>tc(Jt,Ye)));if(ft.size>1)return v.push(`Fronted hosts span more than one zone (${[...ft].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:v};let rt=P.cloudflare??{},or=P.secret?{header:P.secretHeader??"X-Origin-Verify",value:P.secret}:void 0;return{plan:{zone:[...ft][0],hosts:fe,apiToken:tt,zoneId:rt.zoneId??b("CLOUDFLARE_ZONE_ID"),accountId:rt.accountId??b("CLOUDFLARE_ACCOUNT_ID"),proxied:rt.proxied!==!1,settings:rt.settings??ji,cache:rt.cache,originGuard:or,purge:rt.purgeOnDeploy!==!1,skipOriginProbe:rt.skipOriginProbe===!0},errors:v}}var pu=26214400;var mu=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class Cl{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 wa(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 wa("POST","/pages/assets/check-missing",`Bearer ${l}`,{hashes:S});return new Set(b)}async upsertHashes(l,S){await wa("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:gu(P.extension)},base64:!0}));await wa("POST","/pages/assets/upload",`Bearer ${l}`,b)}async createDeployment(l,S,b){let P={};for(let tt of S)P[tt.path]=tt.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 Rl(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((Ye)=>Ye.hash)),v=S.filter((Ye)=>P.has(Ye.hash)),tt=[];for(let Ye=0;Ye<v.length;Ye+=100)tt.push(v.slice(Ye,Ye+100));let we=0;for(let Ye=0;Ye<tt.length;Ye+=4){let ft=tt.slice(Ye,Ye+4);await Promise.all(ft.map((rt)=>this.uploadBatch(b,rt))),we+=ft.reduce((rt,or)=>rt+or.length,0),l.onProgress?.(we,v.length)}return await this.upsertHashes(b,S.map((Ye)=>Ye.hash)),{deployment:await this.createDeployment(l.project,S,l.branch),total:S.length,uploaded:v.length,uploadedBytes:v.reduce((Ye,ft)=>Ye+ft.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 fu(l,S){return{type:"CNAME",name:l,value:S.endsWith(".pages.dev")?S:`${S}.pages.dev`,ttl:1,proxied:!0}}async function bl(l,S){let{blake3:b}=await import("./chunk-rbem58rx.js").then((m)=>Zm(m.default,1));return(await b(l+S)).slice(0,32)}async function Rl(l){let{readdir:S}=await import("node:fs/promises"),{join:b,relative:P,sep:v}=await import("node:path"),tt=[];async function we(fe){let Ye=await S(fe,{withFileTypes:!0});for(let ft of Ye){let rt=b(fe,ft.name);if(ft.isDirectory()){await we(rt);continue}if(!ft.isFile())continue;let or=`/${P(l,rt).split(v).join("/")}`;if(mu.has(or))continue;let Jt=await Bun.file(rt).bytes();if(Jt.byteLength>26214400)throw Error(`${or} is ${Jt.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let pr=Buffer.from(Jt).toString("base64"),Dt=ft.name.lastIndexOf("."),Rt=Dt>0?ft.name.slice(Dt+1):"";tt.push({path:or,hash:await bl(pr,Rt),base64:pr,extension:Rt,size:Jt.byteLength})}}return await we(l),tt.sort((fe,Ye)=>fe.path.localeCompare(Ye.path)),tt}function gu(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 wa(l,S,b,P){let v={Authorization:b},tt;if(P instanceof FormData)tt=P;else if(P!==void 0)v["Content-Type"]="application/json",tt=JSON.stringify(P);let we=await fetch(`https://api.cloudflare.com/client/v4${S}`,{method:l,headers:v,body:tt}),fe=await we.text(),Ye;try{Ye=JSON.parse(fe)}catch{throw Error(`Cloudflare Pages API returned ${we.status} with a non-JSON body: ${fe.slice(0,200)}`)}if(!Ye.success){let ft=(Ye.errors??[]).map((rt)=>`${rt.code}: ${rt.message}`).join(", ");throw Error(`Cloudflare Pages API error (${we.status}): ${ft||fe.slice(0,200)}`)}return Ye.result}export{tg as ABTestManager,se as ACMClient,rr as ACMDnsValidator,ls as ACME_DIRECTORIES,be as AI,Od as API_IDEMPOTENCY_TTL_MS,xd as API_TOKEN_DEFAULT_TTL_MS,_d as API_TOKEN_MAX_TTL_MS,Ri as API_VERSION,ae as AUTHORIZATION_CAPABILITIES,Pd as AUTH_ACTION_TOKEN_TTL_MS,Nd as AUTH_MFA_CHALLENGE_TTL_MS,kd as AUTH_OIDC_TRANSACTION_TTL_MS,Ge as AUTH_SESSION_ABSOLUTE_TTL_MS,Dd as AUTH_SESSION_IDLE_TTL_MS,wf as AWSAPIError,n as AWSClient,f as AWSCloudFormationClient,y as AWSCloudFrontClient,Xp as AWSConfigManager,xy as AWS_PSEUDO_PARAMETERS,Ee as AWS_REGIONS,iu as AcmeClient,wr as AlertEvaluator,ii as AlertStore,ks as AnomalyConfigStore,id as ApiGateway,i as ApiServiceError,Ta as ApplicationAutoScalingClient,Vs as Arn,D as AssetHasher,U as Auth,bi as AuthenticationStore,di as AutomationApiService,Ei as AutomationIdentityStore,xo as AwsAuroraDataAdapter,Mo as AwsAuroraTransport,ra as AwsDatabaseBackupSource,ar as AwsDriver,_o as AwsElastiCacheDataAdapter,Fo as AwsElastiCacheTransport,Zg as AwsIamCapabilityScanner,aa as AwsInfrastructureBackupSource,Bo as AwsRdsDataAdapter,$o as AwsRdsTransport,pm as AwsRegionalDriver,da as AwsSecretsManagerConfigurationBackend,Ap as AwsSpendTransport,la as AwsSsmConfigurationBackend,Mi as BackupCoordinator,Wp as BackupManager,ea as BackupStore,xg as BatchProcessingManager,on as BedrockClient,sn as BedrockRuntimeClient,Hd as BitbucketSourceAdapter,eg as BlueGreenManager,Rg as BounceComplaintHandler,hg as BuildOptimizationManager,ll as BunDockerRuntime,Ll as BunDockerVolumeRuntime,Ol as BunFilesystemArchiveRuntime,Ce as CDN,Ys as CHAIN_HEADER,Xi as CLOUDFLARE_MANAGED_RULE_PREFIX,DS as COMMON_CROSS_ACCOUNT_ROLES,Le as CONTROL_PLANE_SCHEMA_VERSION,Gs as Cache,Ks as CanaryManager,pg as CertificateManager,Oh as CloudBlockVolumeDriver,us as CloudDriverFactory,He as CloudError,Tp as CloudFormationBuilder,f as CloudFormationClient,y as CloudFrontClient,Yp as CloudTrailManager,pe as CloudWatchLogsClient,Cl as CloudflarePagesProvider,Et as CloudflareProvider,Uf as CommandHistory,H as Communication,Cr as ComposeApplicationService,_t as ComposeApplicationStore,yt as ComprehendClient,o as Compute,yp as ComputeSpendTransport,zs as ConfigurationError,pa as ConfigurationService,ca as ConfigurationStore,rn as ConnectClient,Lo as ContainerDataAdapter,fg as ContainerRegistryManager,oa as ControlPlaneBackupSource,Jo as ControlPlaneCleanupDriver,Xn as ControlPlaneStore,Ds as CounterTracker,Ht as CredentialError,Gp as CrossRegionReferenceManager,uf as DASHBOARD_ENTRY,pf as DASHBOARD_PORT_BASE,gf as DASHBOARD_PORT_SPAN,lf as DASHBOARD_STATE_DIR,so as DEFAULT_ATTACK_MODE_HOURS,Vc as DEFAULT_DDOS_THRESHOLDS,wc as DEFAULT_METER_MAPPINGS,vc as DEFAULT_PRICE_BOOK,fi as DEFAULT_RECURSION_LIMITS,An as DEFAULT_RPX_CERTS_DIR,q as DEFAULT_SERVICE_LIMITS,bp as DEFAULT_STATE_DIR,ds as DEFAULT_STATIC_ASSET_EXTENSIONS,Kh as DEFAULT_TELEMETRY_POLICY,tp as DEFAULT_THRESHOLDS,Nh as DEPLOYMENT_QUEUE_KINDS,Xs as DEPTH_HEADER,vr as DETECTABLE_SIGNALS,sl as DIAGNOSTIC_PRESETS,Bg as DLQMonitoringManager,L as DNS,Tg as DNSSECManager,ki as DataServiceLifecycle,ko as DataServiceStore,Ft as Database,dg as DatabaseUserManager,Z as DebugLogger,of as DependencyGraph,Q as Deployment,Tf as DeploymentError,Jp as DisasterRecoveryManager,gn as DnsProviderFactory,jt as DockerDataTransport,To as DockerDiscoveryAdapter,Sr as DockerNamedVolumeDriver,sa as DockerVolumeBackupSource,c as DurableOperationQueue,Cs as DurableQueueWorker,De as DynamoDBClient,gr as EC2Client,Pe as ECRClient,Ke as ECSClient,tr as EFSClient,Ca as ELBv2Client,$h as ENFORCEMENT_ACTIONS,ri as ENFORCEMENT_DESCRIPTIONS,R as ENFORCEMENT_SEVERITY,Pu as ENVIRONMENT_LABEL,nl as EcsRuntimeAdapter,io as EdgeRateLimiter,Je as ElastiCacheClient,m as Email,Gf as EmailAdvanced,Dg as EmailAnalyticsManager,ln as EmailClient,qf as EmailHandlers,Ng as EmailTemplateManager,Uo as EncryptedDataSecretStore,Rf as ErrorCodes,Zt as EventBridgeClient,dm as EventBridgeJobAdapter,ua as ExternalConfigurationBackend,kg as FIFOQueueManager,dp as FOCUS_VERSION,kp as FileCache,Ue as FileSystem,na as FilesystemBackupSource,Ho as FleetService,Qo as FleetStore,e as Fn,Gd as GiteaSourceAdapter,Ud as GithubSourceAdapter,Qd as GitlabSourceAdapter,qp as GlobalResourceManager,bt as GoDaddyProvider,Zp as GuardDutyManager,nt as HOST_SITES_DIR,Nf as HashCache,Qg as HealthCheckManager,Me as HealthCheckRunner,dr as HetznerClient,Ae as HetznerDriver,ge as IAMClient,Ba as IPV6_EXCLUDED_HOST_LABELS,mg as ImageScanningManager,kl as InfrastructureGenerator,gc as InvalidOperationTransitionError,ct as JobLoader,lm as JobProviderReconciler,No as JobService,Do as JobStore,Yt as KendraClient,dA as LARAVEL_SERVERLESS_BUILD_STEPS,C as LambdaClient,Sg as LambdaConcurrencyManager,Eg as LambdaDLQManager,Cg as LambdaDestinationsManager,yg as LambdaLayersManager,il as LambdaRuntimeAdapter,bg as LambdaVPCManager,Ig as LambdaVersionsManager,Xr as LocalEncryptedConfigurationBackend,ia as LogicalDatabaseBackupSource,sg as LogsManager,Wf as MANAGED_NODE_VERSIONS,rc as MANAGEMENT_DASHBOARD_SITE,wp as MANAGEMENT_DASHBOARD_SITE_PREFIX,Si as MAX_CONTROL_HOURS,mc as MAX_CONTROL_PLANE_ERROR_BYTES,Ju as MAX_CONTROL_PLANE_JSON_BYTES,Ts as METERS,Lh as METER_KEYS,Mh as MICRO_CENTS,rp as MIN_PROJECTION_CONFIDENCE,Xl as MTA_STS_PORT,Wo as MaintenanceService,Ko as MaintenanceStore,Y as Messaging,ig as MetricsManager,og as MigrationManager,Lp as MockCloudFormation,Mp as MockDynamoDB,$p as MockS3,qs as Monitoring,zp as MultiAccountManager,Hp as MultiRegionManager,_f as MultiStepProgress,A as Network,Hg as NetworkSecurityManager,si as NotificationRouter,ba as OpenSearchClient,it as OptimisticConcurrencyError,Kp as OrganizationManager,pu as PAGES_MAX_FILE_BYTES,lA as PHP_DEFAULT_EXCLUDES,Jf as PHP_LAYER_EXTENSIONS,Du as PROJECT_LABEL,un as PROXIABLE_RECORD_TYPES,E as ParameterStore,cg as PerformanceManager,X as Permissions,Ea as PersonalizeClient,Qe as Phone,Vf as PhoneAdvanced,af as PhoneHandlers,qo as PlacementService,Go as PlacementStore,an as PollyClient,Ne as PorkbunProvider,Ur as PreDeployScanner,Fp as PreviewEnvironmentManager,Ir as PreviewEnvironmentService,$e as PreviewEnvironmentStore,Up as PreviewNotificationService,xf as ProgressBar,rg as ProgressiveDeploymentManager,oo as ProtectionControlStore,by as Pseudo,M as Queue,Yn as QueueCancellationError,_g as QueueManagementManager,Sy as QueuePresets,Ss as QueueTimeoutError,Sd as RATE_LIMIT_KEY_SEPARATOR,j as RDSClient,Hf as RECOMMENDED_ACCOUNT_STRUCTURES,RS as RECOMMENDED_SCPS,Wg as RELEASE_QUEUE_KINDS,$f as REPL,Ff as REPLCommandBuilder,Mf as REPLContext,Nu as ROLE_LABEL,kf as RateLimiter,Cy as RealtimePresets,lp as RecordingSpendTransport,eo as RecursionGuard,dt as Redirects,Vp as RegionPairManager,jo as RegionService,Vo as RegionStore,Fe as Registry,It as RekognitionClient,lt as ReleaseService,fo as ReleaseStore,um as RemoteBuildService,ag as ReplicaManager,Gg as ResourceManagementManager,J as RetryableOperationError,h as Route53Client,Sa as Route53DomainsClient,me as Route53Provider,wg as Route53ResolverManager,vg as Route53RoutingManager,le as RuntimeOperationService,Ro as RuntimeStreamRegistry,ta as S3BackupDestinationAdapter,a as S3Client,G as S3Error,jd as SECRET_PATTERNS,ap as SENSITIVITY_THRESHOLDS,Xe as SESClient,F as SMS,We as SNSClient,fp as SPEND_CYCLE_SECONDS,Fc as SPEND_GATE_SETTING,Yh as SPEND_LEASE_SETTING,re as SQSClient,ye as SSH_BOOTSTRAP_VERSION,Rn as SSH_PREFLIGHT_SCRIPT,Ie as SSMClient,Ep as STATE_DIR_ENV_VAR,ji as STATIC_SITE_ZONE_SETTINGS,ue as STSClient,cn as SchedulerClient,Ut as Search,Qr as SecretFindingScanner,pi as Secrets,ug as SecretsManager,V as SecretsManagerClient,lg as SecretsRotationManager,I as Security,Br as SecurityHubManager,Fr as SecurityPostureStore,ut as SecurityScannerRunner,gg as SecurityScanningManager,Pg as SenderReputationManager,cm as ServerCronJobAdapter,Oo as ServerDataAdapter,vs as ServerPathVolumeDriver,Ag as ServiceMeshManager,nd as Sftp,xs as SignalSource,jf as SmsAdvanced,Ct as SmsClient,cf as SmsHandlers,Da as SmsVoiceClient,Ao as SourceConnectionStore,qt as SourceProviderError,Uc as SpendCapError,Tr as SpendGate,mp as SpendLoopLease,Ms as SpendNotificationRouter,hp as SpendRunner,Lt as SpendService,ei as SpendStore,Of as Spinner,ur as SshDriver,qr as SshFleetDriver,jp as StackDependencyManager,By as StacksIntegration,Fg as StaticSiteManager,Se as Storage,Ug as StorageAdvancedManager,dn as SupportClient,xr as SyntheticsManager,ul as SystemFleetSshTransport,lr as SystemSshTransport,wo as SystemdDiscoveryAdapter,Zs as TRACE_HEADER,Lf as TaskList,at as TelemetryStore,td as TemplateBuilder,Bp as TemplateCache,St as TextractClient,nn as TranscribeClient,Xt as TranslateClient,hm as TransportDisasterRecoveryDriver,mm as TransportPlatformMaintenanceDriver,Bi as TransportRemoteBuildDriver,Eo as TrivyImageScanner,ho as TsCloudApiError,Ld as TsCloudClient,Xh as URGENT_SPEND_EVENTS,np as USER_VISIBLE_ACTIONS,zo as UnavailableRegionalDriver,ie as UnifiedDnsValidator,As as UnsupportedSchemaVersionError,Pp as ValidationError,er as VoiceClient,Es as VolumeService,xt as VolumeStore,df as Workflow,ng as XRayManager,rC as abTestManager,$d as activateImmutableRelease,jr as addSiteToCloudConfig,gt as ageSeconds,Dc as aggregateDeltas,zu as allocateSitePorts,Ny as analyzeStackDiff,ni as anomalyOptionsForSignal,ao as applyControlsToDdos,Td as applyControlsToRateLimits,Pr as applyMitigationFactor,uh as applyPlan,rs as applyZoneMigration,dd as artifactKey,vi as assertReleaseStrategy,zh as assertSpendAllows,fh as attachConflicts,Ah as attachIsViable,hh as attachPreconditions,Xd as attachProvenanceToRelease,vo as attachSbomToRelease,Wd as attachVulnerabilitySummary,zg as authEncryptionKeyFile,w as authorizeOrganization,om as authorizeRuntimePath,nS as autocomplete,JS as awsConfigManager,xl as backupCredentialStatus,KS as backupManager,bI as batch,OC as batchProcessingManager,go as beginOidcAuthorization,eC as blueGreenManager,PC as bounceComplaintHandler,st as budgetWindow,Aa as buildAndPushServerlessImage,MC as buildBunRuntimeLayerZip,Eh as buildCertificatePackScript,Sh as buildCertificateStateScript,vh as buildCertificateUnpackScript,sd as buildCloudFormationTemplate,za as buildCloudInitFirstBoot,yc as buildComposeLogsCommand,dy as buildComposeRuntimeCommand,ly as buildComposeScaleCommand,Ic as buildComposeShellCommand,qu as buildDrainSourceScript,rh as buildDrainedSiteScanScript,Kt as buildFunctionEnv,Gu as buildHealthGateScript,Hn as buildHostCleanupScript,Wn as buildHostSitePortsScript,ed as buildMailEnv,gs as buildManagementDashboardArtifact,Iu as buildMediaCdnPlan,Jl as buildMtaStsPolicy,$m as buildMtaStsServer,$C as buildNodeRuntimeLayerZip,AC as buildOptimizationManager,Ha as buildOriginGuardRule,Lu as buildPauseWorkersScript,HC as buildPhpRuntimeLayerZip,Uu as buildRestoreScript,z as buildRpxConfig,ke as buildRpxFragmentRefreshScript,gh as buildSetHostnameScript,Mn as buildSiteDeployScript,Fu as buildSnapshotScript,Vu as buildSourceStateScript,Cn as buildSshArgs,Tn as buildSshBootstrapScript,Wa as buildStaticSiteCacheRules,Un as buildStaticSiteDeployScript,Qu as buildTargetStateScript,$u as buildWorkersStateScript,Zd as bytes,tC as canaryManager,Vr as canonicalJson,pt as capabilities,zt as capacity,kI as categorizeChanges,mC as certificateManager,bh as certificatesMatch,lI as checkIAMPermissions,rA as checkInvocation,pI as checkServiceQuotas,Bf as chunk,km as cleanupDns01Challenge,fy as clearSigningKeyCache,Io as cloneSourceBinding,_I as cloudConfigSchema,yu as cloudDrivers,XS as cloudTrailManager,Rl as collectAssets,ro as collectPhpAppEntries,Kl as collectServerDnsDomains,Xu as completeComposeVolumeDeletion,mo as completeOidcAuthorization,Xy as composePresets,Is as composeProjectName,ud as composeServerlessAppTemplate,ef as compositeSpendTransport,At as compressBackup,pA as config,cl as connectionGuidance,yC as containerRegistryManager,Dh as controlPlaneDatabaseFile,uc as controlPlaneMigrations,Fy as createApiBackendPreset,bo as createApiV1Handler,CA as createAsgBuildDriver,_l as createBackupQueueHandlers,aA as createCliHandler,k as createCloudDriver,Xa as createCloudFrontPolicy,sI as createCredentialProvider,Wy as createDashboardSite,qy as createDataPipelinePreset,dl as createDataServiceQueueHandlers,Sc as createDeploymentQueueHandlers,T as createDnsProvider,SA as createEcsBuildDriver,Qc as createEnforcementHandlers,Np as createError,od as createExistingStaticFullStackPreset,pl as createFleetQueueHandlers,My as createFullStackAppPreset,ss as createGoDaddyValidator,QC as createHandlers,sA as createHttpHandler,Qy as createJamstackPreset,al as createJobQueueHandlers,zy as createLaravelPreset,Vy as createMLApiPreset,Il as createMaintenanceQueueHandlers,Au as createMediaAccessToken,Hy as createMicroservicesPreset,UI as createMockAWS,Oy as createNodeJsServerPreset,Ly as createNodeJsServerlessPreset,Wi as createObjectStorageClient,is as createPorkbunValidator,Yy as createPreset,rf as createPresignedUrl,uy as createPresignedUrlAsync,oA as createQueueHandler,Gy as createRealtimeAppPreset,ml as createRegionQueueHandlers,Jd as createReleaseProvenance,Fd as createReleaseQueueHandlers,yA as createRemoteBuildQueueHandlers,os as createRoute53Validator,sm as createRuntimeAdapters,oI as createS3Client,IA as createServerBuildDriver,Ky as createServerlessLaravelPreset,$y as createServerlessNodePreset,zl as createSmsInfrastructure,Ve as createSourceAdapter,_y as createStaticSitePreset,jy as createTraditionalWebAppPreset,Cc as createVolumeQueueHandlers,Uy as createWordPressPreset,hi as createZip,uS as crossRegionReferenceManager,Yr as dashboardActions,ps as dashboardCredentialsFile,Gr as dataServiceCapabilities,uC as databaseUserManager,Rd as decodeBase32,Re as decompressBackup,Tm as decryptBackup,co as defaultConfig,Op as defaultLocalConfig,bd as defaultRateLimitRules,ha as deleteStaticSite,ic as deployAllComputeSites,Yo as deployServerlessApp,Nl as deploySite,ms as deploySiteRelease,Hi as deployStaticSite,fa as deployStaticSiteFull,Zr as deployStaticSiteWithExternalDns,en as deployStaticSiteWithExternalDnsFull,Yc as deploymentCoexistenceError,mf as deriveManagementDashboardPort,vd as describePosture,am as desiredJobProviderState,op as detectAnomalies,vp as detectDeploymentTargets,Pa as detectDnsProvider,Lc as detectLatestAnomaly,cI as detectMisconfigurations,Sp as detectServiceRegion,fc as diffCompose,DI as diffTemplates,yo as discoverGitRefs,po as discoverOidcProvider,el as discoverRuntimeInventory,_C as dlqMonitoringManager,Na as dnsProviders,RC as dnssecManager,rm as dockerWorkloads,xi as documentDigest,WS as drManager,xe as driverStatePath,tl as ecsWorkloads,Bt as effectiveCapabilities,NC as emailAnalyticsManager,BC as emailTemplateManager,Ci as encodeBase32,vm as encryptBackup,Yd as ensureDefaultSecurityPolicies,_n as ensureFirewall,Gn as ensureManagementDashboard,On as ensureServer,xn as ensureSshKey,W as escapeSecLang,Nc as evaluateBudget,Pn as evaluatePreflight,$s as evaluateTelemetryAlertRules,ol as eventBridgeScheduleInput,iA as eventToRequest,qh as ewma,hc as exportCompose,es as exportRoute53Zone,Dp as extendPreset,xC as fifoQueueManager,CI as findChangedFiles,Zu as findMapping,Yu as findPriceEntry,BS as formatAccountStructure,yh as formatAttachPlan,WI as formatBytes,Rr as formatCents,ky as formatDiff,ih as formatDrainedSiteRefusal,JI as formatDuration,sS as formatFlagSuggestions,cS as formatHistory,dS as formatHistoryStats,ch as formatInventory,YI as formatKeyValue,XI as formatList,lh as formatPlan,kn as formatPreflightFindings,KI as formatProgressBar,Qf as formatRegion,ES as formatRegionList,Yg as formatScanResults,ZI as formatSuggestion,jI as formatTable,Er as formatTimeToExhaustion,zI as formatTree,If as fromEC2Metadata,Sf as fromECSMetadata,Af as fromEnvironment,yf as fromSharedCredentials,Cf as fromWebIdentity,gd as functionFingerprint,In as gatewayHostnames,pd as generateAppImageDockerfile,jS as generateApprovalConfig,zf as generateBootstrap,GI as generateCleanupWorkflow,qI as generateCostReportWorkflow,NS as generateCrossAccountRoleCF,zd as generateCycloneDxSbom,GS as generateDeploymentConfig,MS as generateDeploymentPipeline,xS as generateDeploymentWorkflow,ma as generateExternalDnsStaticSiteTemplate,Om as generateHttpsServerCode,Kd as generateImageSbom,wm as generateLetsEncryptUserData,t as generateLogicalId,HS as generateManualPipeline,$S as generateMatrixWorkflow,qS as generateMultiEnvConfig,FS as generateMultiEnvPipeline,_S as generateMultiEnvWorkflow,OS as generatePRPreviewWorkflow,zS as generateParallelConfig,cA as generatePhpFpmConfig,Yf as generatePhpLayerDockerfile,US as generatePreviewPipeline,HI as generatePreviewWorkflow,r as generateResourceName,VS as generateScheduledConfig,QS as generateScheduledPipeline,LS as generateScheduledWorkflow,Qi as generateStaticSiteTemplate,N as generateUbuntuAppCloudInit,vf as getAccountId,hS as getAllRegions,SS as getClosestRegion,oS as getCommandUsage,Ph as getComposeTemplate,qg as getConfig,tS as getContextualHelp,js as getCredentials,BI as getDeploymentStrategy,xI as getDiffStats,PI as getDiffSummary,Df as getErrorDetails,cd as getLocalConfig,MI as getLocalCredentials,$I as getLocalEndpoint,FI as getLocalEnvVars,gI as getQuotaUsageSummary,PS as getRecommendedStructure,mi as getRegion,vS as getRegionStats,AS as getRegionsByCompliance,fS as getRegionsByLocation,yS as getRegionsByPricingTier,Pf as getRequiredPermissions,Ay as getSigningKeyCacheSize,jl as getSmsInfrastructureStatus,Ey as getTimestamp,no as globMatches,hs as globToRegex,pS as globalResourceManager,ti as governingLimitCents,YS as guardDutyManager,Fs as handleSpendRequest,yn as hasAutoWwwVariant,Qt as hasManagementDashboardSite,lc as hasProxyUpstream,fI as hashBuffer,yI as hashDirectory,xp as hashFile,II as hashManifest,_p as hashString,VC as healthCheckManager,mn as hostAcceptsIpv6,Va as hostCondition,lo as hotp,br as hourBucket,Gh as hourBucketsBetween,fC as imageScanningManager,Li as infraEnvFromOutputs,hd as inspectInvocation,eA as installRecursionFetch,qi as invalidateCache,$g as invocationContext,eS as isLikelyTypo,fn as isLocalDatabase,LI as isLocalDevelopment,Nr as isManagementDashboardSiteName,yy as isNodeCryptoAvailable,Oc as isOperationAllowed,Ls as isQuietHours,Vn as isSafePattern,Jc as isStateDirConfigured,Xc as isStatePath,Dr as isValidCidr,IS as isValidRegion,Zn as isValidTimeZone,Iy as isWebCryptoAvailable,Hr as jobProviderCapability,Ki as keyMatchesFilters,bC as lambdaConcurrencyManager,TC as lambdaDLQManager,EC as lambdaDestinationsManager,SC as lambdaLayersManager,vC as lambdaVPCManager,CC as lambdaVersionsManager,rl as lambdaWorkloads,yd as laravelServerlessEnvDefaults,yr as listComposeTemplates,wi as listSourceReferences,wd as loadCloudConfig,$t as loadTelemetryPolicy,oC as logsManager,$c as lookbackHoursForSignal,sf as mailEnabled,Zc as mailFirewallPorts,gm as maintenanceWindowOpen,nf as makeAWSRequest,gy as makeAWSRequestAsync,py as makeAWSRequestOnce,Rp as managementDashboardSiteName,hl as manifestDigest,Or as matchTotpCounter,Tu as mediaObjectHeaders,Ns as median,ip as medianAbsoluteDeviation,kc as mergeDecisions,kr as mergeInfrastructure,Qh as mergePriceBooks,Rc as meterTelemetry,sC as metricsManager,Hl as migrateObjectStorage,cC as migrationManager,TS as multiAccountManager,lS as multiRegionManager,xm as needsRenewal,jC as networkSecurityManager,mt as nextScheduleRuns,he as normalizePublicIpv6,ve as normalizeRuntimeStatus,je as normalizeScheduleExpression,Jg as normalizeSourceEvent,Be as normalizeSshPublicKey,up as normalizeTelemetryPolicy,Kn as occupiedHostPorts,Co as openApiDocument,_s as optionsForSignal,wS as organizationManager,Id as packagePhpApp,_r as packageServerlessApp,bl as pagesAssetHash,fu as pagesDnsRecord,ad as parallel,EI as parallelMap,vI as parallelWithRetry,Ch as parseCertificateState,md as parseChain,Ar as parseCompose,ay as parseComposeCatalog,tm as parseDockerInspect,$l as parseDotenv,nh as parseDrainedSites,Jn as parseHostSiteFragments,hy as parseJSONResponse,Dn as parsePreflightFacts,ju as parseSourceDrained,nm as parseSystemdRecords,Hu as parseTargetReady,dc as parseUpstreamPort,Mu as parseWorkersPaused,my as parseXMLResponse,ai as pathTemplate,ac as pendingSteps,Ps as percentOfLimit,lC as performanceManager,Og as phpLayerBuildStage,Xf as phpLayerPackages,Ai as phpRuntimeLayerAssets,cy as planComposeTemplateUpgrade,Bc as planEnforcement,_u as planIsDestructive,Ip as planMitigation,ph as planServerRename,Th as planSiteMove,ts as planZoneMigration,vt as policyTag,Nn as preflightFailed,QI as previewManager,VI as previewNotifications,ht as previewSchedule,Hh as previousBudgetWindow,ws as priceUsage,Fh as priceUsageLines,oh as probeHostRoutes,ja as probeOriginTls,RI as processInChunks,qd as processSourceWebhook,Pi as productionChangeReview,nC as progressiveDeploymentManager,Pc as projectSpend,fd as propagationHeaders,ya as providerEndpoint,fl as publicKeyFingerprint,pn as qualifyName,LC as queueManagementManager,SI as quickHash,Cd as rateLimitHeaders,Ii as rateLimitKey,_e as readDriverState,ah as reconcile,Wl as reconcileAddressRecords,lu as reconcileCloudflareCdn,Zi as reconcileDeclaredRecords,AA as reconcileJobObservation,Mr as reconcileSourceWebhook,Di as recordDashboardHostPosture,mA as recordPreDeploySecretScan,hA as recordSkippedSecretScan,Ad as recursionBlockedResponse,Te as redactRuntimeConfig,qc as redactTelemetryText,oi as redactTelemetryValue,Kr as redeployServerlessApp,gS as regionPairManager,$r as releaseStrategyCapabilities,Kg as releaseTrafficPlan,qn as reloadRpxGateway,zi as remapKey,zr as removeSiteFromCloudConfig,Vd as removeSourceWebhook,ka as removeStaleServerAddressRecords,Ac as renderComposeTemplate,li as renderDdosInstallScript,Kc as renderNftablesRuleset,Ni as renderServerCron,zc as renderSysctlFile,oc as renderWafConfig,jn as renderWafInstallScript,sc as renewRpxCertificates,dC as replicaManager,tf as requestHash,NI as requiresReplacement,FC as resetRecursionRuntime,UC as resolveApp,p as resolveAppDatabase,mh as resolveAttachTarget,qe as resolveAuthEncryptionKey,ce as resolveCloudProvider,uu as resolveCloudflareCdnPlan,bf as resolveCredentials,Ui as resolveDashboardAction,nc as resolveDashboardAuth,hf as resolveDashboardDomain,ff as resolveDashboardDomains,Yi as resolveDeclaredRecords,Py as resolveDeployBucketName,O as resolveDeploymentMode,$n as resolveExecStart,Ua as resolveHetznerApiToken,ui as resolveMailService,Jy as resolveManagementDashboardSite,gi as resolveManagementDashboardSites,Ia as resolveObjectStorage,dh as resolvePlan,g as resolveProjectStackName,fr as resolveProxyUpstreams,ld as resolveQueueNames,kh as resolveQueuedDeploymentCommand,Gt as resolveQueues,Zf as resolveRecursionConfig,Ef as resolveRegion,te as resolveRuntimeInventory,Mt as resolveServerlessAppStackName,rd as resolveServerlessArtifactBucketName,Hs as resolveServerlessAssetBucketName,Js as resolveServerlessRuntime,Ry as resolveSiteBucketName,fs as resolveSiteDeployTarget,u as resolveSiteKind,wy as resolveSiteResourceName,Ty as resolveSiteStackName,wn as resolveSshSettings,d as resolveStatePath,Dy as resolveStorageBucketName,Pt as resolveUiSource,tc as resolveZoneApex,zC as resourceManagementManager,Mg as responseToResult,sp as robustZScore,kt as roleCapabilities,Md as rollbackImmutableRelease,Wr as rollbackServerlessApp,Uh as roundCents,DC as route53ResolverManager,wC as route53RoutingManager,cp as routeMatches,ku as routesFromFragments,yi as ruleMatches,Kf as runBuildHooks,xc as runEnforcement,to as runPhpBuildHooks,ze as runRemoteCommand,de as runtimeId,Fi as sanitizeCloudConfig,s as sanitizeControlPlaneValue,vy as sanitizeName,Bd as sanitizeOidcReturnPath,Hc as saveTelemetryPolicy,Xg as scanForSecrets,pc as scopeContains,ot as scopeKey,La as scpUpload,rS as searchCommands,ys as searchControlPlane,gC as secretsManager,pC as secretsRotationManager,fA as secureContainerRelease,ZS as securityHubManager,hC as securityScanningManager,ee as securityScope,Lr as sendAuthenticationEmail,kC as senderReputationManager,TI as sequence,Ml as serializeDotenv,Ln as serverPublicIpv4,IC as serviceMeshManager,wl as setAttachToInCloudConfig,Wt as setMaintenance,_i as setSitePropertyInCloudConfig,Wc as setStateDir,Nm as setupDns01Challenge,Ra as setupSmsInfrastructure,Ws as sha256,tA as sharedRecursionGuard,Lg as sharedRuntimeLoop,Wu as shipsARelease,Su as signCloudFrontCookies,Cu as signCloudFrontUrl,x as signRequest,Cp as signRequestAsync,Bs as signalDefinition,B as siteInstallBase,zn as siteMoveArchivePath,Ih as siteMoveCertArchivePath,cc as siteUnitGlob,gp as spendNotificationText,Us as spendOpenApiPaths,cr as sshExec,oe as sshExecOrThrow,mS as stackDependencyManager,ga as startLocalDashboardServer,Zh as startSpendLoop,Qs as stateDir,_ as statePath,GC as staticSiteManager,qC as storageAdvancedManager,Vh as streamFocusJsonl,_c as strongestActiveAction,Qp as suggestCommand,iS as suggestFlags,uI as suggestIAMPolicy,mI as suggestQuotaIncrease,bS as suggestRegionPairs,CS as suggestRegions,Ti as syncSourceRepositories,bc as synchronizeComposeVolumes,Fl as synchronizeConfiguredConfiguration,Po as synchronizeConfiguredJobs,aC as syntheticsManager,jc as sysctlHardening,im as systemdWorkloads,Jh as telemetryBucketLabel,ci as telemetryCursor,Gc as telemetryEstimatedMonthlyCost,Wh as telemetryPercentile,pp as telemetryPolicyKey,hI as templateCache,Bu as tenantsOf,So as testSourceConnection,Ec as tieredMicroCents,Ga as toCloudflareZoneSettings,Os as toFocusJsonl,Mc as toFocusRecords,sh as toInventoryServer,Vg as totp,uo as totpUri,xu as unaccountedSites,em as unsupportedCapabilities,Bh as unsupportedVolumeCapabilities,yl as updateCompatibility,Sl as updateSiteInCloudConfig,Gi as uploadStaticFiles,ep as usageDeltaKey,Ot as utcInstantOfLocal,kS as validateAccountStructure,OI as validateAgainstSchema,_h as validateAttachment,Em as validateBackupDestination,aS as validateCommand,aI as validateConfiguration,dI as validateCredentials,Ku as validateDeploymentConfig,xh as validateMountPath,Yl as validateResourceLimits,Ou as validateServerName,Bl as validateTemplate,Zl as validateTemplateSize,xa as verifyAddressRecord,gA as verifyArtifactSignature,bu as verifyMediaAccessToken,jg as verifyTotp,Al as verifyUpdateSignature,ns as verifyZoneParity,bs as volumeCapabilities,Ru as wafEventTelemetry,$a as waitForCloudInit,bn as waitForSsh,Vt as webhookEndpoint,nI as withCDN,rI as withCache,tI as withDatabase,nA as withInvocation,Zy as withMonitoring,iI as withQueue,eI as withSecurity,wI as withTimeout,K as wrapCloudInitUserData,et as writeDriverState,iC as xrayManager,gl as zeroCapacity,jh as zeroFill,Tc as zoneOffsetMs,Rs as zonedParts};
|
|
595
|
+
`}async function _m(l){let{domain:S,challengeValue:b,hostedZoneId:P,dnsProvider:v,region:it="us-east-1"}=l;if(v){let Ae=await T(v).upsertRecord(S,{name:`_acme-challenge.${S}`,type:"TXT",content:b,ttl:60});if(!Ae.success)throw Error(`Failed to create DNS challenge record: ${Ae.message}`);return}if(P){await new h(it).changeResourceRecordSets({HostedZoneId:P,ChangeBatch:{Comment:"ACME DNS-01 challenge",Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:`_acme-challenge.${S}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${b}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}async function Mm(l){let{domain:S,challengeValue:b,hostedZoneId:P,dnsProvider:v,region:it="us-east-1"}=l;if(v){let Ae=await T(v).deleteRecord(S,{name:`_acme-challenge.${S}`,type:"TXT",content:b});if(!Ae.success)console.warn(`Failed to delete DNS challenge record: ${Ae.message}`);return}if(P){await new h(it).changeResourceRecordSets({HostedZoneId:P,ChangeBatch:{Comment:"Remove ACME DNS-01 challenge",Changes:[{Action:"DELETE",ResourceRecordSet:{Name:`_acme-challenge.${S}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${b}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}function Bm(l){try{let{execSync:S}=Me("node:child_process"),b=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 rc,createSign as lu,generateKeyPairSync as nc}from"node:crypto";var ic={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class du{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(l){this.directoryUrl=l.staging?ic.staging:ic.production,this.email=l.email,this.accountKey=l.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:l}=nc("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 P=this.nonce;return this.nonce=null,P}let l=await this.getDirectory(),b=(await fetch(l.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!b)throw Error("Failed to get nonce from ACME server");return b}getJwk(){let l=this.accountKey.split(`
|
|
596
|
+
`).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=rc("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)),Re=S===""?"":this.base64UrlEncode(JSON.stringify(S)),Ae=`${it}.${Re}`,rt=lu("SHA256");rt.update(Ae);let Rt=rt.sign(this.accountKey),st=Rt.subarray(4,4+Rt[3]),lr=4+Rt[3]+2,Xt=Rt.subarray(lr,lr+Rt[lr-1]),fr=Buffer.alloc(32),Dt=Buffer.alloc(32);st.copy(fr,32-st.length),Xt.copy(Dt,32-Xt.length);let Pt=Buffer.concat([fr,Dt]);return JSON.stringify({protected:it,payload:Re,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,Re=P.headers.get("content-type");if(Re?.includes("application/json")||Re?.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 Re=`${it.token}.${P}`;if(it.type==="http-01")return{type:"http-01",token:it.token,keyAuthorization:Re,identifier:`/.well-known/acme-challenge/${it.token}`};else{let Ae=this.base64UrlEncode(rc("sha256").update(Re).digest());return{type:"dns-01",token:it.token,keyAuthorization:Re,identifier:`_acme-challenge.${b}`,dnsValue:Ae}}});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}=nc("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 Ae=await(await fetch(it)).text(),rt=Ae.split(/(?=-----BEGIN CERTIFICATE-----)/g),Rt=rt[0],st=rt.slice(1).join("");return{certificate:Rt,privateKey:P,chain:st,fullchain:Ae,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var oc=["js","mjs","cjs","css","map","woff","woff2","ttf","otf","eot","png","jpg","jpeg","gif","webp","avif","svg","ico","mp4","webm","ogg","mp3","wav","pdf","wasm"],uu=[{name:"x-stx-router",value:"true"}];function Ji(l){return`"${l.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`}function ac(l){return`{${l.map(Ji).join(" ")}}`}function pu(l){let S=`http.request.headers[${Ji(l.name.toLowerCase())}]`;return l.value===void 0?`len(${S}) > 0`:`any(${S}[*] == ${Ji(l.value)})`}function qa(l){if(l.length===1)return`http.host eq ${Ji(l[0])}`;return`http.host in ${ac(l)}`}function Ja(l,S={}){if(S.enabled===!1||l.length===0)return[];let b=qa(l),P=[],it=(S.bypassPaths??[]).map((fr)=>`starts_with(http.request.uri.path, ${Ji(fr)})`),Ae=(S.negotiatedRequestHeaders??uu).map(pu),rt=[...it,...Ae],Rt=rt.length>0?`(${rt.join(" or ")})`:void 0;if(Rt)P.push({action:"set_cache_settings",description:"bypass cache",expression:`(${b} and ${Rt})`,enabled:!0,action_parameters:{cache:!1}});let st=Rt?`${b} and not ${Rt}`:b,lr=S.assetExtensions??oc,Xt=lr.length>0?`lower(http.request.uri.path.extension) in ${ac([...lr])}`:void 0;if(Xt)P.push({action:"set_cache_settings",description:"cache fingerprinted assets",expression:`(${st} and ${Xt})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:S.assetEdgeTtl??2592000},browser_ttl:{mode:"override_origin",default:S.assetBrowserTtl??31536000}}});return P.push({action:"set_cache_settings",description:"cache documents",expression:Xt?`(${st} and not ${Xt})`:`(${st})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:S.documentEdgeTtl??3600},browser_ttl:{mode:"override_origin",default:S.documentBrowserTtl??0}}}),P}function Ya(l,S,b){if(l.length===0||!S||!b)return[];return[{action:"rewrite",description:"origin guard header",expression:`(${qa(l)})`,enabled:!0,action_parameters:{headers:{[S]:{operation:"set",value:b}}}}]}var Dn=(l)=>l===void 0?void 0:l?"on":"off";function Xa(l){let S={ssl:l.ssl,always_use_https:Dn(l.alwaysUseHttps),automatic_https_rewrites:Dn(l.automaticHttpsRewrites),min_tls_version:l.minTlsVersion,tls_1_3:Dn(l.tls13),brotli:Dn(l.brotli),http3:Dn(l.http3),"0rtt":Dn(l.zeroRtt),early_hints:Dn(l.earlyHints),browser_cache_ttl:l.browserCacheTtl,always_online:Dn(l.alwaysOnline),websockets:Dn(l.websockets),email_obfuscation:Dn(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 Qi={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 mu}from"node:tls";async function Qa(l){let{address:S,serverName:b,port:P=443,timeoutMs:v=5000}=l;return new Promise((it)=>{let Re=!1,Ae=(Rt)=>{if(Re)return;Re=!0;try{rt.destroy()}catch{}it(Rt)},rt=mu({host:S,port:P,servername:b,rejectUnauthorized:!1,timeout:v});rt.once("secureConnect",()=>{if(rt.authorized){Ae({reachable:!0,trusted:!0});return}Ae({reachable:!0,trusted:!1,reason:rt.authorizationError?String(rt.authorizationError):"origin certificate is not trusted for this hostname"})}),rt.once("timeout",()=>{Ae({reachable:!1,trusted:!1,reason:`no TLS handshake within ${v}ms`})}),rt.once("error",(Rt)=>{Ae({reachable:!1,trusted:!1,reason:Rt.message})})})}function fu(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 gu(l){let{provider:S,zone:b,hosts:P,ipv4:v,ipv6:it,proxied:Re=!0,settings:Ae=Qi,cache:rt,originGuard:Rt,purge:st=!0,ttl:lr=300,skipOriginProbe:Xt=!1,skipEdgeCertificateCheck:fr=!1}=l,Dt={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(P.length===0)return Dt;let Pt=[],xe=Re&&!fr?await S.listEdgeCertificateHosts(b):null;for(let ne of P){let It=Re;if(It&&xe&&!fu(xe,ne)){It=!1;let ar=xe.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${xe.join(", ")})`;Dt.deferredProxy.push({host:ne,reason:ar}),Dt.warnings.push(`${ne}: publishing DNS-only — ${ar}. 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&&!Xt){let ar=await Qa({address:v,serverName:ne});if(!ar.trusted){It=!1;let cr=ar.reason||"origin is not serving a trusted certificate";Dt.deferredProxy.push({host:ne,reason:cr}),Dt.warnings.push(`${ne}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${cr}). The origin issues certificates over HTTP-01, which needs the name to reach it directly; re-run the deploy once it has one and the record will be proxied.`)}}if(It)Pt.push(ne);let wt=[{type:"A",content:v}];if(it&&yn(ne))wt.push({type:"AAAA",content:it});for(let{type:ar,content:cr}of wt){let dr=await S.upsertRecord(b,{name:ne,type:ar,content:cr,ttl:lr,proxied:It});if(dr.success)Dt.records.push({host:ne,type:ar,content:cr,proxied:It});else Dt.warnings.push(`${ne} ${ar} → ${cr} failed: ${dr.message||"unknown provider error"}`)}}if(Pt.length===0){if(Re)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 ne=Xa(Ae),It=await S.applyZoneSettings(b,ne);Dt.settingsChanged=It.changed;for(let wt of It.failed)Dt.warnings.push(`zone setting '${wt.id}' could not be applied: ${wt.error}`)}catch(ne){Dt.warnings.push(`zone settings could not be read: ${ne instanceof Error?ne.message:String(ne)}`)}let kt=Ja(Pt,rt);if(kt.length>0){let ne=await S.putManagedPhaseRules(b,"http_request_cache_settings",kt);if(ne.success)Dt.cacheRules=kt.length;else Dt.warnings.push(`cache rules could not be written: ${ne.message}`)}if(Rt){let ne=Ya(Pt,Rt.header,Rt.value);if(ne.length>0){let It=await S.putManagedPhaseRules(b,"http_request_late_transform",ne);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(b,{hosts:Pt}),!Dt.purged)Dt.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Dt}var hu=(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 yu(l,S={}){let b=S.env??hu,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 Re=l.sites??{},Ae=P.frontedHosts?.length?[...new Set(P.frontedHosts.map((Xt)=>Xt.toLowerCase()))]:En(Re,{autoWww:l.infrastructure?.compute?.proxy?.autoWww!==!1});if(Ae.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(Ae.map((Xt)=>sc(Xt,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??{},lr=P.secret?{header:P.secretHeader??"X-Origin-Verify",value:P.secret}:void 0;return{plan:{zone:[...Rt][0],hosts:Ae,apiToken:it,zoneId:st.zoneId??b("CLOUDFLARE_ZONE_ID"),accountId:st.accountId??b("CLOUDFLARE_ACCOUNT_ID"),proxied:st.proxied!==!1,settings:st.settings??Qi,cache:st.cache,originGuard:lr,purge:st.purgeOnDeploy!==!1,skipOriginProbe:st.skipOriginProbe===!0},errors:v}}var Cu=26214400;var Su=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class Rl{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 Ba(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 Ba("POST","/pages/assets/check-missing",`Bearer ${l}`,{hashes:S});return new Set(b)}async upsertHashes(l,S){await Ba("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:bu(P.extension)},base64:!0}));await Ba("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 $l(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 Re=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))),Re+=Rt.reduce((st,lr)=>st+lr.length,0),l.onProgress?.(Re,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 Au(l,S){return{type:"CNAME",name:l,value:S.endsWith(".pages.dev")?S:`${S}.pages.dev`,ttl:1,proxied:!0}}async function Pl(l,S){let{blake3:b}=await import("./chunk-nw0tvrrr.js").then((m)=>sh(m.default,1));return(await b(l+S)).slice(0,32)}async function $l(l){let{readdir:S}=await import("node:fs/promises"),{join:b,relative:P,sep:v}=await import("node:path"),it=[];async function Re(Ae){let rt=await S(Ae,{withFileTypes:!0});for(let Rt of rt){let st=b(Ae,Rt.name);if(Rt.isDirectory()){await Re(st);continue}if(!Rt.isFile())continue;let lr=`/${P(l,st).split(v).join("/")}`;if(Su.has(lr))continue;let Xt=await Bun.file(st).bytes();if(Xt.byteLength>26214400)throw Error(`${lr} is ${Xt.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let fr=Buffer.from(Xt).toString("base64"),Dt=Rt.name.lastIndexOf("."),Pt=Dt>0?Rt.name.slice(Dt+1):"";it.push({path:lr,hash:await Pl(fr,Pt),base64:fr,extension:Pt,size:Xt.byteLength})}}return await Re(l),it.sort((Ae,rt)=>Ae.path.localeCompare(rt.path)),it}function bu(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 Ba(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 Re=await fetch(`https://api.cloudflare.com/client/v4${S}`,{method:l,headers:v,body:it}),Ae=await Re.text(),rt;try{rt=JSON.parse(Ae)}catch{throw Error(`Cloudflare Pages API returned ${Re.status} with a non-JSON body: ${Ae.slice(0,200)}`)}if(!rt.success){let Rt=(rt.errors??[]).map((st)=>`${st.code}: ${st.message}`).join(", ");throw Error(`Cloudflare Pages API error (${Re.status}): ${Rt||Ae.slice(0,200)}`)}return rt.result}export{ag as ABTestManager,oe as ACMClient,or as ACMDnsValidator,ic as ACME_DIRECTORIES,Ee as AI,Qd as API_IDEMPOTENCY_TTL_MS,Fd as API_TOKEN_DEFAULT_TTL_MS,Ud as API_TOKEN_MAX_TTL_MS,ki as API_VERSION,ce as AUTHORIZATION_CAPABILITIES,Od as AUTH_ACTION_TOKEN_TTL_MS,Ld as AUTH_MFA_CHALLENGE_TTL_MS,$d as AUTH_OIDC_TRANSACTION_TTL_MS,je as AUTH_SESSION_ABSOLUTE_TTL_MS,_d as AUTH_SESSION_IDLE_TTL_MS,Bf as AWSAPIError,n as AWSClient,f as AWSCloudFormationClient,y as AWSCloudFrontClient,ng as AWSConfigManager,Fy as AWS_PSEUDO_PARAMETERS,ve as AWS_REGIONS,du as AcmeClient,Nr as AlertEvaluator,ci as AlertStore,$s as AnomalyConfigStore,ld as ApiGateway,i as ApiServiceError,ka as ApplicationAutoScalingClient,Xs as Arn,D as AssetHasher,U as Auth,wi as AuthenticationStore,gi as AutomationApiService,Ri as AutomationIdentityStore,Fo as AwsAuroraDataAdapter,qo as AwsAuroraTransport,ca as AwsDatabaseBackupSource,ur as AwsDriver,Uo as AwsElastiCacheDataAdapter,Vo as AwsElastiCacheTransport,sm as AwsIamCapabilityScanner,ga as AwsInfrastructureBackupSource,Mo as AwsRdsDataAdapter,Go as AwsRdsTransport,ym as AwsRegionalDriver,ha as AwsSecretsManagerConfigurationBackend,Ep as AwsSpendTransport,fa as AwsSsmConfigurationBackend,Hi as BackupCoordinator,tg as BackupManager,oa as BackupStore,Fg as BatchProcessingManager,ln as BedrockClient,dn as BedrockRuntimeClient,Kd as BitbucketSourceAdapter,og as BlueGreenManager,xg as BounceComplaintHandler,Cg as BuildOptimizationManager,fl as BunDockerRuntime,Hl as BunDockerVolumeRuntime,Ql as BunFilesystemArchiveRuntime,be as CDN,io as CHAIN_HEADER,ts as CLOUDFLARE_MANAGED_RULE_PREFIX,_S as COMMON_CROSS_ACCOUNT_ROLES,Fe as CONTROL_PLANE_SCHEMA_VERSION,Ws as Cache,eo as CanaryManager,yg as CertificateManager,Qh as CloudBlockVolumeDriver,As as CloudDriverFactory,Ve as CloudError,kp as CloudFormationBuilder,f as CloudFormationClient,y as CloudFrontClient,ig as CloudTrailManager,ge as CloudWatchLogsClient,Rl as CloudflarePagesProvider,Be as CloudflareProvider,jf as CommandHistory,H as Communication,Tr as ComposeApplicationService,Ot as ComposeApplicationStore,Ct as ComprehendClient,o as Compute,vp as ComputeSpendTransport,Zs as ConfigurationError,ya as ConfigurationService,ma as ConfigurationStore,an as ConnectClient,Ho as ContainerDataAdapter,bg as ContainerRegistryManager,pa as ControlPlaneBackupSource,ra as ControlPlaneCleanupDriver,ti as ControlPlaneStore,_s as CounterTracker,Gt as CredentialError,Wp as CrossRegionReferenceManager,Af as DASHBOARD_ENTRY,yf as DASHBOARD_PORT_BASE,If as DASHBOARD_PORT_SPAN,ff as DASHBOARD_STATE_DIR,po as DEFAULT_ATTACK_MODE_HOURS,Xc as DEFAULT_DDOS_THRESHOLDS,Bc as DEFAULT_METER_MAPPINGS,Nc as DEFAULT_PRICE_BOOK,Si as DEFAULT_RECURSION_LIMITS,Cn as DEFAULT_RPX_CERTS_DIR,q as DEFAULT_SERVICE_LIMITS,Dp as DEFAULT_STATE_DIR,oc as DEFAULT_STATIC_ASSET_EXTENSIONS,ef as DEFAULT_TELEMETRY_POLICY,ap as DEFAULT_THRESHOLDS,Lh as DEPLOYMENT_QUEUE_KINDS,no as DEPTH_HEADER,Dr as DETECTABLE_SIGNALS,ul as DIAGNOSTIC_PRESETS,Mg as DLQMonitoringManager,L as DNS,kg as DNSSECManager,Oi as DataServiceLifecycle,$o as DataServiceStore,Ut as Database,hg as DatabaseUserManager,Z as DebugLogger,pf as DependencyGraph,Q as Deployment,kf as DeploymentError,rg as DisasterRecoveryManager,An as DnsProviderFactory,zt as DockerDataTransport,ko as DockerDiscoveryAdapter,vr as DockerNamedVolumeDriver,ua as DockerVolumeBackupSource,c as DurableOperationQueue,Rs as DurableQueueWorker,Pe as DynamoDBClient,Ar as EC2Client,Ne as ECRClient,Xe as ECSClient,rr as EFSClient,Ra as ELBv2Client,Gh as ENFORCEMENT_ACTIONS,oi as ENFORCEMENT_DESCRIPTIONS,R as ENFORCEMENT_SEVERITY,Ou as ENVIRONMENT_LABEL,dl as EcsRuntimeAdapter,uo as EdgeRateLimiter,Ze as ElastiCacheClient,m as Email,Wf as EmailAdvanced,_g as EmailAnalyticsManager,mn as EmailClient,Jf as EmailHandlers,Lg as EmailTemplateManager,jo as EncryptedDataSecretStore,xf as ErrorCodes,er as EventBridgeClient,hm as EventBridgeJobAdapter,Aa as ExternalConfigurationBackend,$g as FIFOQueueManager,hp as FOCUS_VERSION,$p as FileCache,Ge as FileSystem,da as FilesystemBackupSource,Ko as FleetService,zo as FleetStore,e as Fn,Wd as GiteaSourceAdapter,jd as GithubSourceAdapter,zd as GitlabSourceAdapter,Jp as GlobalResourceManager,ke as GoDaddyProvider,sg as GuardDutyManager,ot as HOST_SITES_DIR,Lf as HashCache,zg as HealthCheckManager,Qe as HealthCheckRunner,gr as HetznerClient,ye as HetznerDriver,me as IAMClient,Ma as IPV6_EXCLUDED_HOST_LABELS,Sg as ImageScanningManager,_l as InfrastructureGenerator,Ic as InvalidOperationTransitionError,ut as JobLoader,fm as JobProviderReconciler,Lo as JobService,_o as JobStore,Zt as KendraClient,hA as LARAVEL_SERVERLESS_BUILD_STEPS,C as LambdaClient,wg as LambdaConcurrencyManager,Pg as LambdaDLQManager,Rg as LambdaDestinationsManager,vg as LambdaLayersManager,ll as LambdaRuntimeAdapter,Dg as LambdaVPCManager,Tg as LambdaVersionsManager,tn as LocalEncryptedConfigurationBackend,la as LogicalDatabaseBackupSource,ug as LogsManager,tA as MANAGED_NODE_VERSIONS,cc as MANAGEMENT_DASHBOARD_SITE,Bp as MANAGEMENT_DASHBOARD_SITE_PREFIX,vi as MAX_CONTROL_HOURS,Sc as MAX_CONTROL_PLANE_ERROR_BYTES,rp as MAX_CONTROL_PLANE_JSON_BYTES,ks as METERS,Hh as METER_KEYS,qh as MICRO_CENTS,cp as MIN_PROJECTION_CONFIDENCE,nu as MTA_STS_PORT,ta as MaintenanceService,ea as MaintenanceStore,Y as Messaging,lg as MetricsManager,pg as MigrationManager,Hp as MockCloudFormation,qp as MockDynamoDB,Gp as MockS3,Js as Monitoring,Zp as MultiAccountManager,Kp as MultiRegionManager,Uf as MultiStepProgress,A as Network,Kg as NetworkSecurityManager,di as NotificationRouter,Da as OpenSearchClient,at as OptimisticConcurrencyError,eg as OrganizationManager,Cu as PAGES_MAX_FILE_BYTES,fA as PHP_DEFAULT_EXCLUDES,rA as PHP_LAYER_EXTENSIONS,_u as PROJECT_LABEL,tt as PROXIABLE_RECORD_TYPES,E as ParameterStore,mg as PerformanceManager,X as Permissions,Pa as PersonalizeClient,qe as Phone,Xf as PhoneAdvanced,gf as PhoneHandlers,Jo as PlacementService,Wo as PlacementStore,un as PollyClient,ie as PorkbunProvider,qr as PreDeployScanner,Vp as PreviewEnvironmentManager,Er as PreviewEnvironmentService,Ue as PreviewEnvironmentStore,jp as PreviewNotificationService,Ff as ProgressBar,cg as ProgressiveDeploymentManager,go as ProtectionControlStore,Dy as Pseudo,M as Queue,ri as QueueCancellationError,Ug as QueueManagementManager,wy as QueuePresets,ws as QueueTimeoutError,wd as RATE_LIMIT_KEY_SEPARATOR,j as RDSClient,Kf as RECOMMENDED_ACCOUNT_STRUCTURES,xS as RECOMMENDED_SCPS,tm as RELEASE_QUEUE_KINDS,Gf as REPL,Vf as REPLCommandBuilder,qf as REPLContext,Lu as ROLE_LABEL,$f as RateLimiter,Ry as RealtimePresets,fp as RecordingSpendTransport,oo as RecursionGuard,pt as Redirects,Xp as RegionPairManager,Yo as RegionService,Xo as RegionStore,He as Registry,bt as RekognitionClient,gt as ReleaseService,bo as ReleaseStore,Am as RemoteBuildService,gg as ReplicaManager,Wg as ResourceManagementManager,J as RetryableOperationError,h as Route53Client,wa as Route53DomainsClient,he as Route53Provider,Bg as Route53ResolverManager,Ng as Route53RoutingManager,ue as RuntimeOperationService,xo as RuntimeStreamRegistry,aa as S3BackupDestinationAdapter,a as S3Client,G as S3Error,Yd as SECRET_PATTERNS,gp as SENSITIVITY_THRESHOLDS,et as SESClient,F as SMS,Ye as SNSClient,bp as SPEND_CYCLE_SECONDS,Vc as SPEND_GATE_SETTING,sf as SPEND_LEASE_SETTING,re as SQSClient,Ie as SSH_BOOTSTRAP_VERSION,kn as SSH_PREFLIGHT_SCRIPT,Se as SSMClient,Pp as STATE_DIR_ENV_VAR,Qi as STATIC_SITE_ZONE_SETTINGS,pe as STSClient,pn as SchedulerClient,Qt as Search,Vr as SecretFindingScanner,fi as Secrets,Ag as SecretsManager,V as SecretsManagerClient,fg as SecretsRotationManager,I as Security,Lr as SecurityHubManager,Gr as SecurityPostureStore,mt as SecurityScannerRunner,Ig as SecurityScanningManager,Og as SenderReputationManager,mm as ServerCronJobAdapter,Qo as ServerDataAdapter,Ns as ServerPathVolumeDriver,Eg as ServiceMeshManager,dd as Sftp,Fs as SignalSource,Yf as SmsAdvanced,vt as SmsClient,mf as SmsHandlers,_a as SmsVoiceClient,Eo as SourceConnectionStore,Vt as SourceProviderError,jc as SpendCapError,Pr as SpendGate,Sp as SpendLoopLease,qs as SpendNotificationRouter,Cp as SpendRunner,$t as SpendService,ii as SpendStore,Qf as Spinner,hr as SshDriver,Kr as SshFleetDriver,Yp as StackDependencyManager,My as StacksIntegration,Vg as StaticSiteManager,Ce as Storage,jg as StorageAdvancedManager,gn as SupportClient,$r as SyntheticsManager,Al as SystemFleetSshTransport,mr as SystemSshTransport,Bo as SystemdDiscoveryAdapter,so as TRACE_HEADER,Hf as TaskList,lt as TelemetryStore,ad as TemplateBuilder,Mp as TemplateCache,Et as TextractClient,cn as TranscribeClient,Yt as TranslateClient,Cm as TransportDisasterRecoveryDriver,Sm as TransportPlatformMaintenanceDriver,Li as TransportRemoteBuildDriver,Po as TrivyImageScanner,Co as TsCloudApiError,Hd as TsCloudClient,nf as URGENT_SPEND_EVENTS,dp as USER_VISIBLE_ACTIONS,Zo as UnavailableRegionalDriver,se as UnifiedDnsValidator,Es as UnsupportedSchemaVersionError,Op as ValidationError,tr as VoiceClient,Ps as VolumeService,_t as VolumeStore,hf as Workflow,dg as XRayManager,cC as abTestManager,Gd as activateImmutableRelease,Jr as addSiteToCloudConfig,ft as ageSeconds,_c as aggregateDeltas,Zu as allocateSitePorts,Ly as analyzeStackDiff,ai as anomalyOptionsForSignal,mo as applyControlsToDdos,kd as applyControlsToRateLimits,xr as applyMitigationFactor,Ah as applyPlan,cs as applyZoneMigration,hd as artifactKey,Di as assertReleaseStrategy,Zh as assertSpendAllows,bh as attachConflicts,Eh as attachIsViable,Ch as attachPreconditions,nl as attachProvenanceToRelease,No as attachSbomToRelease,tl as attachVulnerabilitySummary,Zg as authEncryptionKeyFile,w as authorizeOrganization,pm as authorizeRuntimePath,dS as autocomplete,rC as awsConfigManager,Fl as backupCredentialStatus,eC as backupManager,DI as batch,QC as batchProcessingManager,Io as beginOidcAuthorization,oC as blueGreenManager,OC as bounceComplaintHandler,ct as budgetWindow,Ea as buildAndPushServerlessImage,qC as buildBunRuntimeLayerZip,Ph as buildCertificatePackScript,wh as buildCertificateStateScript,Nh as buildCertificateUnpackScript,ud as buildCloudFormationTemplate,Za as buildCloudInitFirstBoot,vc as buildComposeLogsCommand,hy as buildComposeRuntimeCommand,fy as buildComposeScaleCommand,Tc as buildComposeShellCommand,Ju as buildDrainSourceScript,ch as buildDrainedSiteScanScript,Wt as buildFunctionEnv,Wu as buildHealthGateScript,jn as buildHostCleanupScript,Zn as buildHostSitePortsScript,od as buildMailEnv,Is as buildManagementDashboardArtifact,Eu as buildMediaCdnPlan,ru as buildMtaStsPolicy,Gm as buildMtaStsServer,GC as buildNodeRuntimeLayerZip,EC as buildOptimizationManager,Ya as buildOriginGuardRule,Hu as buildPauseWorkersScript,KC as buildPhpRuntimeLayerZip,ju as buildRestoreScript,z as buildRpxConfig,_e as buildRpxFragmentRefreshScript,Ih as buildSetHostnameScript,Gn as buildSiteDeployScript,Vu as buildSnapshotScript,Xu as buildSourceStateScript,Tn as buildSshArgs,Pn as buildSshBootstrapScript,Ja as buildStaticSiteCacheRules,qn as buildStaticSiteDeployScript,zu as buildTargetStateScript,Gu as buildWorkersStateScript,sl as bytes,aC as canaryManager,Wr as canonicalJson,ht as capabilities,Kt as capacity,$I as categorizeChanges,SC as certificateManager,Dh as certificatesMatch,fI as checkIAMPermissions,cA as checkInvocation,II as checkServiceQuotas,Mf as chunk,Mm as cleanupDns01Challenge,by as clearSigningKeyCache,To as cloneSourceBinding,UI as cloudConfigSchema,vu as cloudDrivers,nC as cloudTrailManager,$l as collectAssets,co as collectPhpAppEntries,eu as collectServerDnsDomains,np as completeComposeVolumeDeletion,So as completeOidcAuthorization,nI as composePresets,Ts as composeProjectName,Ad as composeServerlessAppTemplate,af as compositeSpendTransport,St as compressBackup,yA as config,ml as connectionGuidance,vC as containerRegistryManager,_h as controlPlaneDatabaseFile,Ac as controlPlaneMigrations,Vy as createApiBackendPreset,Do as createApiV1Handler,RA as createAsgBuildDriver,Ul as createBackupQueueHandlers,gA as createCliHandler,k as createCloudDriver,tc as createCloudFrontPolicy,uI as createCredentialProvider,tI as createDashboardSite,Jy as createDataPipelinePreset,hl as createDataServiceQueueHandlers,wc as createDeploymentQueueHandlers,T as createDnsProvider,wA as createEcsBuildDriver,zc as createEnforcementHandlers,Lp as createError,pd as createExistingStaticFullStackPreset,yl as createFleetQueueHandlers,qy as createFullStackAppPreset,us as createGoDaddyValidator,zC as createHandlers,uA as createHttpHandler,zy as createJamstackPreset,gl as createJobQueueHandlers,Zy as createLaravelPreset,Xy as createMLApiPreset,Tl as createMaintenanceQueueHandlers,Iu as createMediaAccessToken,Ky as createMicroservicesPreset,jI as createMockAWS,Qy as createNodeJsServerPreset,Hy as createNodeJsServerlessPreset,Zi as createObjectStorageClient,ls as createPorkbunValidator,iI as createPreset,df as createPresignedUrl,Ay as createPresignedUrlAsync,pA as createQueueHandler,Wy as createRealtimeAppPreset,Sl as createRegionQueueHandlers,rl as createReleaseProvenance,Vd as createReleaseQueueHandlers,vA as createRemoteBuildQueueHandlers,ps as createRoute53Validator,um as createRuntimeAdapters,pI as createS3Client,TA as createServerBuildDriver,eI as createServerlessLaravelPreset,Gy as createServerlessNodePreset,Zl as createSmsInfrastructure,Ke as createSourceAdapter,Uy as createStaticSitePreset,Yy as createTraditionalWebAppPreset,Rc as createVolumeQueueHandlers,jy as createWordPressPreset,Ii as createZip,AS as crossRegionReferenceManager,rn as dashboardActions,ys as dashboardCredentialsFile,zr as dataServiceCapabilities,AC as databaseUserManager,xd as decodeBase32,De as decompressBackup,km as decryptBackup,ho as defaultConfig,Qp as defaultLocalConfig,Dd as defaultRateLimitRules,sr as delegateZone,is as delegateZoneFromConfig,Ca as deleteStaticSite,lc as deployAllComputeSites,ia as deployServerlessApp,Ll as deploySite,Ss as deploySiteRelease,ji as deployStaticSite,ba as deployStaticSiteFull,nn as deployStaticSiteWithExternalDns,sn as deployStaticSiteWithExternalDnsFull,id as deploymentCoexistenceError,Sf as deriveManagementDashboardPort,ss as describeDelegation,Nd as describePosture,gm as desiredJobProviderState,pp as detectAnomalies,Np as detectDeploymentTargets,Oa as detectDnsProvider,Hc as detectLatestAnomaly,mI as detectMisconfigurations,wp as detectServiceRegion,bc as diffCompose,_I as diffTemplates,vo as discoverGitRefs,yo as discoverOidcProvider,ol as discoverRuntimeInventory,UC as dlqMonitoringManager,La as dnsProviders,xC as dnssecManager,cm as dockerWorkloads,$i as documentDigest,tC as drManager,Le as driverStatePath,al as ecsWorkloads,xt as effectiveCapabilities,LC as emailAnalyticsManager,MC as emailTemplateManager,Ti as encodeBase32,Nm as encryptBackup,il as ensureDefaultSecurityPolicies,Mn as ensureFirewall,zn as ensureManagementDashboard,Un as ensureServer,$n as ensureSshKey,W as escapeSecLang,Lc as evaluateBudget,xn as evaluatePreflight,Gs as evaluateTelemetryAlertRules,pl as eventBridgeScheduleInput,lA as eventToRequest,Jh as ewma,Cc as exportCompose,os as exportRoute53Zone,_p as extendPreset,FC as fifoQueueManager,RI as findChangedFiles,sp as findMapping,ip as findPriceEntry,MS as formatAccountStructure,vh as formatAttachPlan,tS as formatBytes,kr as formatCents,$y as formatDiff,lh as formatDrainedSiteRefusal,rS as formatDuration,uS as formatFlagSuggestions,mS as formatHistory,hS as formatHistoryStats,mh as formatInventory,iS as formatKeyValue,nS as formatList,fh as formatPlan,On as formatPreflightFindings,eS as formatProgressBar,zf as formatRegion,PS as formatRegionList,im as formatScanResults,sS as formatSuggestion,YI as formatTable,Rr as formatTimeToExhaustion,ZI as formatTree,Tf as fromEC2Metadata,wf as fromECSMetadata,Ef as fromEnvironment,vf as fromSharedCredentials,Rf as fromWebIdentity,Id as functionFingerprint,En as gatewayHostnames,yd as generateAppImageDockerfile,YS as generateApprovalConfig,Zf as generateBootstrap,WI as generateCleanupWorkflow,JI as generateCostReportWorkflow,LS as generateCrossAccountRoleCF,Zd as generateCycloneDxSbom,WS as generateDeploymentConfig,qS as generateDeploymentPipeline,FS as generateDeploymentWorkflow,Sa as generateExternalDnsStaticSiteTemplate,Fm as generateHttpsServerCode,el as generateImageSbom,Lm as generateLetsEncryptUserData,t as generateLogicalId,KS as generateManualPipeline,GS as generateMatrixWorkflow,JS as generateMultiEnvConfig,VS as generateMultiEnvPipeline,US as generateMultiEnvWorkflow,QS as generatePRPreviewWorkflow,ZS as generateParallelConfig,mA as generatePhpFpmConfig,iA as generatePhpLayerDockerfile,jS as generatePreviewPipeline,KI as generatePreviewWorkflow,r as generateResourceName,XS as generateScheduledConfig,zS as generateScheduledPipeline,HS as generateScheduledWorkflow,Vi as generateStaticSiteTemplate,N as generateUbuntuAppCloudInit,Nf as getAccountId,CS as getAllRegions,wS as getClosestRegion,pS as getCommandUsage,Oh as getComposeTemplate,Jg as getConfig,aS as getContextualHelp,Ys as getCredentials,MI as getDeploymentStrategy,FI as getDiffStats,OI as getDiffSummary,_f as getErrorDetails,md as getLocalConfig,qI as getLocalCredentials,GI as getLocalEndpoint,VI as getLocalEnvVars,SI as getQuotaUsageSummary,OS as getRecommendedStructure,yi as getRegion,NS as getRegionStats,ES as getRegionsByCompliance,bS as getRegionsByLocation,vS as getRegionsByPricingTier,Of as getRequiredPermissions,Ey as getSigningKeyCacheSize,Yl as getSmsInfrastructureStatus,Py as getTimestamp,lo as globMatches,Cs as globToRegex,yS as globalResourceManager,si as governingLimitCents,iC as guardDutyManager,Vs as handleSpendRequest,bn as hasAutoWwwVariant,Ht as hasManagementDashboardSite,fc as hasProxyUpstream,EI as hashBuffer,vI as hashDirectory,Fp as hashFile,TI as hashManifest,Up as hashString,XC as healthCheckManager,yn as hostAcceptsIpv6,qa as hostCondition,fo as hotp,wr as hourBucket,Wh as hourBucketsBetween,bC as imageScanningManager,Ui as infraEnvFromOutputs,Cd as inspectInvocation,oA as installRecursionFetch,Ki as invalidateCache,Gg as invocationContext,oS as isLikelyTypo,Sn as isLocalDatabase,HI as isLocalDevelopment,_r as isManagementDashboardSiteName,nr as isNameserverRegistrar,vy as isNodeCryptoAvailable,Qc as isOperationAllowed,Hs as isQuietHours,Wn as isSafePattern,rd as isStateDirConfigured,nd as isStatePath,Br as isValidCidr,TS as isValidRegion,ni as isValidTimeZone,Ty as isWebCryptoAvailable,ir as isZoneHost,jr as jobProviderCapability,Yi as keyMatchesFilters,DC as lambdaConcurrencyManager,kC as lambdaDLQManager,PC as lambdaDestinationsManager,wC as lambdaLayersManager,NC as lambdaVPCManager,RC as lambdaVersionsManager,cl as lambdaWorkloads,vd as laravelServerlessEnvDefaults,br as listComposeTemplates,Ni as listSourceReferences,Bd as loadCloudConfig,Mt as loadTelemetryPolicy,pC as logsManager,Gc as lookbackHoursForSignal,uf as mailEnabled,sd as mailFirewallPorts,Im as maintenanceWindowOpen,lf as makeAWSRequest,Iy as makeAWSRequestAsync,yy as makeAWSRequestOnce,xp as managementDashboardSiteName,Cl as manifestDigest,Fr as matchTotpCounter,wu as mediaObjectHeaders,Ls as median,lp as medianAbsoluteDeviation,$c as mergeDecisions,Or as mergeInfrastructure,zh as mergePriceBooks,xc as meterTelemetry,uC as metricsManager,Kl as migrateObjectStorage,mC as migrationManager,kS as multiAccountManager,fS as multiRegionManager,Bm as needsRenewal,YC as networkSecurityManager,At as nextScheduleRuns,fe as normalizePublicIpv6,Te as normalizeRuntimeStatus,We as normalizeScheduleExpression,rm as normalizeSourceEvent,Oe as normalizeSshPublicKey,Ap as normalizeTelemetryPolicy,Yn as occupiedHostPorts,Ro as openApiDocument,Us as optionsForSignal,BS as organizationManager,Td as packagePhpApp,Mr as packageServerlessApp,Pl as pagesAssetHash,Au as pagesDnsRecord,gd as parallel,PI as parallelMap,NI as parallelWithRetry,Rh as parseCertificateState,Sd as parseChain,Cr as parseCompose,gy as parseComposeCatalog,am as parseDockerInspect,Gl as parseDotenv,dh as parseDrainedSites,ei as parseHostSiteFragments,Cy as parseJSONResponse,Bn as parsePreflightFacts,Yu as parseSourceDrained,dm as parseSystemdRecords,Ku as parseTargetReady,hc as parseUpstreamPort,qu as parseWorkersPaused,Sy as parseXMLResponse,ui as pathTemplate,gc as pendingSteps,Os as percentOfLimit,fC as performanceManager,Qg as phpLayerBuildStage,nA as phpLayerPackages,Ci as phpRuntimeLayerAssets,my as planComposeTemplateUpgrade,Mc as planEnforcement,Uu as planIsDestructive,Tp as planMitigation,yh as planServerRename,kh as planSiteMove,as as planZoneMigration,Tt as policyTag,_n as preflightFailed,zI as previewManager,XI as previewNotifications,yt as previewSchedule,Kh as previousBudgetWindow,Bs as priceUsage,Vh as priceUsageLines,ph as probeHostRoutes,Qa as probeOriginTls,xI as processInChunks,Jd as processSourceWebhook,xi as productionChangeReview,dC as progressiveDeploymentManager,Oc as projectSpend,bd as propagationHeaders,va as providerEndpoint,bl as publicKeyFingerprint,hn as qualifyName,HC as queueManagementManager,wI as quickHash,Rd as rateLimitHeaders,Ei as rateLimitKey,$e as readDriverState,gh as reconcile,tu as reconcileAddressRecords,gu as reconcileCloudflareCdn,ns as reconcileDeclaredRecords,EA as reconcileJobObservation,Hr as reconcileSourceWebhook,Bi as recordDashboardHostPosture,SA as recordPreDeploySecretScan,CA as recordSkippedSecretScan,Ed as recursionBlockedResponse,we as redactRuntimeConfig,Jc as redactTelemetryText,li as redactTelemetryValue,Yr as redeployServerlessApp,IS as regionPairManager,Qr as releaseStrategyCapabilities,em as releaseTrafficPlan,Kn as reloadRpxGateway,Xi as remapKey,Xr as removeSiteFromCloudConfig,Xd as removeSourceWebhook,$a as removeStaleServerAddressRecords,Ec as renderComposeTemplate,mi as renderDdosInstallScript,ed as renderNftablesRuleset,_i as renderServerCron,Zc as renderSysctlFile,pc as renderWafConfig,Jn as renderWafInstallScript,uc as renewRpxCertificates,hC as replicaManager,cf as requestHash,LI as requiresReplacement,VC as resetRecursionRuntime,jC as resolveApp,p as resolveAppDatabase,Sh as resolveAttachTarget,ze as resolveAuthEncryptionKey,de as resolveCloudProvider,yu as resolveCloudflareCdnPlan,Df as resolveCredentials,qi as resolveDashboardAction,dc as resolveDashboardAuth,Cf as resolveDashboardDomain,bf as resolveDashboardDomains,rs as resolveDeclaredRecords,Oy as resolveDeployBucketName,O as resolveDeploymentMode,Hn as resolveExecStart,ja as resolveHetznerApiToken,hi as resolveMailService,rI as resolveManagementDashboardSite,Ai as resolveManagementDashboardSites,Ta as resolveObjectStorage,hh as resolvePlan,g as resolveProjectStackName,Sr as resolveProxyUpstreams,fd as resolveQueueNames,$h as resolveQueuedDeploymentCommand,qt as resolveQueues,sA as resolveRecursionConfig,Pf as resolveRegion,te as resolveRuntimeInventory,Ft as resolveServerlessAppStackName,cd as resolveServerlessArtifactBucketName,Ks as resolveServerlessAssetBucketName,ro as resolveServerlessRuntime,xy as resolveSiteBucketName,bs as resolveSiteDeployTarget,u as resolveSiteKind,By as resolveSiteResourceName,ky as resolveSiteStackName,Nn as resolveSshSettings,d as resolveStatePath,_y as resolveStorageBucketName,Nt as resolveUiSource,sc as resolveZoneApex,ZC as resourceManagementManager,qg as responseToResult,up as robustZScore,Bt as roleCapabilities,qd as rollbackImmutableRelease,Zr as rollbackServerlessApp,jh as roundCents,_C as route53ResolverManager,BC as route53RoutingManager,mp as routeMatches,$u as routesFromFragments,bi as ruleMatches,eA as runBuildHooks,Fc as runEnforcement,ao as runPhpBuildHooks,Je as runRemoteCommand,le as runtimeId,fn as sameNameservers,Gi as sanitizeCloudConfig,s as sanitizeControlPlaneValue,Ny as sanitizeName,Md as sanitizeOidcReturnPath,Kc as saveTelemetryPolicy,nm as scanForSecrets,yc as scopeContains,dt as scopeKey,Ha as scpUpload,cS as searchCommands,vs as searchControlPlane,IC as secretsManager,yC as secretsRotationManager,bA as secureContainerRelease,sC as securityHubManager,CC as securityScanningManager,ee as securityScope,Ur as sendAuthenticationEmail,$C as senderReputationManager,kI as sequence,ql as serializeDotenv,Qn as serverPublicIpv4,TC as serviceMeshManager,Bl as setAttachToInCloudConfig,Jt as setMaintenance,Mi as setSitePropertyInCloudConfig,td as setStateDir,_m as setupDns01Challenge,xa as setupSmsInfrastructure,to as sha256,aA as sharedRecursionGuard,Hg as sharedRuntimeLoop,tp as shipsARelease,Tu as signCloudFrontCookies,Pu as signCloudFrontUrl,x as signRequest,Rp as signRequestAsync,Ms as signalDefinition,B as siteInstallBase,Xn as siteMoveArchivePath,Th as siteMoveCertArchivePath,mc as siteUnitGlob,Ip as spendNotificationText,js as spendOpenApiPaths,pr as sshExec,ae as sshExecOrThrow,SS as stackDependencyManager,Ia as startLocalDashboardServer,of as startSpendLoop,zs as stateDir,_ as statePath,WC as staticSiteManager,JC as storageAdvancedManager,Xh as streamFocusJsonl,Uc as strongestActiveAction,zp as suggestCommand,lS as suggestFlags,yI as suggestIAMPolicy,CI as suggestQuotaIncrease,DS as suggestRegionPairs,RS as suggestRegions,Pi as syncSourceRepositories,Dc as synchronizeComposeVolumes,Vl as synchronizeConfiguredConfiguration,Oo as synchronizeConfiguredJobs,gC as syntheticsManager,Yc as sysctlHardening,lm as systemdWorkloads,rf as telemetryBucketLabel,pi as telemetryCursor,Wc as telemetryEstimatedMonthlyCost,tf as telemetryPercentile,yp as telemetryPolicyKey,bI as templateCache,Mu as tenantsOf,wo as testSourceConnection,Pc as tieredMicroCents,Xa as toCloudflareZoneSettings,Qs as toFocusJsonl,qc as toFocusRecords,uh as toInventoryServer,Xg as totp,Ao as totpUri,Fu as unaccountedSites,om as unsupportedCapabilities,Mh as unsupportedVolumeCapabilities,vl as updateCompatibility,wl as updateSiteInCloudConfig,zi as uploadStaticFiles,op as usageDeltaKey,Lt as utcInstantOfLocal,$S as validateAccountStructure,QI as validateAgainstSchema,Uh as validateAttachment,Pm as validateBackupDestination,gS as validateCommand,gI as validateConfiguration,hI as validateCredentials,ep as validateDeploymentConfig,Fh as validateMountPath,Pd as validateResourceLimits,Qu as validateServerName,Ml as validateTemplate,Xl as validateTemplateSize,Fa as verifyAddressRecord,IA as verifyArtifactSignature,Du as verifyMediaAccessToken,Yg as verifyTotp,El as verifyUpdateSignature,ds as verifyZoneParity,Ds as volumeCapabilities,xu as wafEventTelemetry,Ga as waitForCloudInit,wn as waitForSsh,jt as webhookEndpoint,dI as withCDN,cI as withCache,aI as withDatabase,dA as withInvocation,sI as withMonitoring,lI as withQueue,oI as withSecurity,BI as withTimeout,K as wrapCloudInitUserData,nt as writeDriverState,lC as xrayManager,Il as zeroCapacity,Yh as zeroFill,kc as zoneOffsetMs,xs as zonedParts};
|