@stacksjs/ts-cloud 0.16.16 → 0.16.18

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