@stacksjs/ts-cloud 0.16.35 → 0.16.37

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