@stacksjs/ts-cloud 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/chunk-0djsffn6.js +1 -0
  3. package/dist/bin/chunk-0t3sev1j.js +1 -0
  4. package/dist/{chunk-cp54a0qn.js → bin/chunk-0y89hs67.js} +1 -1
  5. package/dist/bin/{chunk-6eat8ezk.js → chunk-21gggxvf.js} +2 -2
  6. package/dist/bin/{chunk-wewcjam5.js → chunk-26cj89s6.js} +1 -1
  7. package/dist/bin/{chunk-eh40fpvj.js → chunk-35xstvnq.js} +1 -1
  8. package/dist/bin/{chunk-d6zzgvtn.js → chunk-4a85nk2q.js} +2 -2
  9. package/dist/bin/{chunk-anm3ae6z.js → chunk-4a97kbk1.js} +2 -2
  10. package/dist/bin/{chunk-svyd4v6c.js → chunk-4kbhbfq8.js} +2 -2
  11. package/dist/bin/{chunk-35ttwn26.js → chunk-4vdv41nh.js} +1 -1
  12. package/dist/bin/{chunk-dvkj4k6h.js → chunk-67jsyn0g.js} +1 -1
  13. package/dist/bin/chunk-6tct7e89.js +1 -0
  14. package/dist/bin/{chunk-jnx4jgw8.js → chunk-6vjrts39.js} +1 -1
  15. package/dist/bin/chunk-7v5ff3vc.js +1 -0
  16. package/dist/bin/chunk-80nra92y.js +1 -0
  17. package/dist/bin/{chunk-sbejksrh.js → chunk-9mydnqr6.js} +1 -1
  18. package/dist/bin/{chunk-m3nqw76h.js → chunk-9rsn48qg.js} +1 -1
  19. package/dist/bin/{chunk-q46zr2tv.js → chunk-a2t1e5yb.js} +1 -1
  20. package/dist/bin/chunk-akbfefwq.js +1 -0
  21. package/dist/bin/chunk-b704nznp.js +1 -0
  22. package/dist/bin/{chunk-8rwhsp5b.js → chunk-c1j9v7ee.js} +1 -1
  23. package/dist/bin/chunk-cjz36ths.js +1 -0
  24. package/dist/bin/{chunk-nb0yjkv5.js → chunk-cxd5cevb.js} +1 -1
  25. package/dist/bin/{chunk-b35989e3.js → chunk-dbv8w56s.js} +2 -2
  26. package/dist/bin/chunk-dxchg0g1.js +1 -0
  27. package/dist/bin/{chunk-axvr7dwa.js → chunk-e1bfd1yv.js} +2 -2
  28. package/dist/bin/{chunk-g90nqfgv.js → chunk-fpcghdr3.js} +47 -47
  29. package/dist/bin/{chunk-dj9a67c3.js → chunk-ftse39wf.js} +2 -2
  30. package/dist/bin/chunk-g0ewbkbq.js +1 -0
  31. package/dist/bin/{chunk-6zjy949y.js → chunk-gskbezam.js} +1 -1
  32. package/dist/bin/chunk-gvs85t2j.js +1 -0
  33. package/dist/bin/{chunk-pkgkfe6s.js → chunk-hej39dwr.js} +2 -2
  34. package/dist/bin/{chunk-b0hj9m5e.js → chunk-jce28gnz.js} +1 -1
  35. package/dist/bin/{chunk-80ar3aty.js → chunk-kbtrr0c3.js} +1 -1
  36. package/dist/bin/chunk-khrye4x9.js +1 -0
  37. package/dist/bin/{chunk-b2ymh8k0.js → chunk-ks4ewy1s.js} +1 -1
  38. package/dist/bin/{chunk-kybdb0ws.js → chunk-mbnwt3r5.js} +2 -2
  39. package/dist/{chunk-xtwjt370.js → bin/chunk-md2k3n21.js} +1 -1
  40. package/dist/bin/chunk-memfxrcn.js +1 -0
  41. package/dist/{chunk-cd0zpxhf.js → bin/chunk-mwgxyc0z.js} +1 -1
  42. package/dist/bin/{chunk-9px3rg4a.js → chunk-neampxq1.js} +2 -2
  43. package/dist/bin/{chunk-da8zpf82.js → chunk-nkpf91d3.js} +1 -1
  44. package/dist/bin/{chunk-pjpa4x52.js → chunk-nmkm1f68.js} +1 -1
  45. package/dist/bin/{chunk-7wzdaqh6.js → chunk-nyc2jxd8.js} +1 -1
  46. package/dist/bin/chunk-pqr8jqnd.js +1 -0
  47. package/dist/bin/{chunk-ckxpgwxw.js → chunk-q182t9ba.js} +2 -2
  48. package/dist/bin/{chunk-pnz5hk8n.js → chunk-r6x7beew.js} +2 -2
  49. package/dist/bin/chunk-rfqk5xym.js +1 -0
  50. package/dist/bin/{chunk-jnsbzqzz.js → chunk-ww770qpn.js} +2 -2
  51. package/dist/bin/chunk-wy20ztb6.js +1 -0
  52. package/dist/bin/{chunk-y9f8649w.js → chunk-wzepfqf4.js} +5 -5
  53. package/dist/bin/chunk-xcqmwphz.js +1 -0
  54. package/dist/bin/{chunk-jt1tndm2.js → chunk-xev7qr2h.js} +1 -1
  55. package/dist/bin/{chunk-1v6bt68w.js → chunk-y3rm37z1.js} +3 -3
  56. package/dist/bin/{chunk-mn6j22zn.js → chunk-zejwh9cy.js} +2 -2
  57. package/dist/bin/{chunk-ezftw2q4.js → chunk-zwwnt4x1.js} +1 -1
  58. package/dist/bin/cli.js +93 -90
  59. package/dist/bin/dashboard-server.js +1 -1
  60. package/dist/{chunk-06jk7ba9.js → chunk-0hj552t7.js} +2 -2
  61. package/dist/{chunk-0e16qt6k.js → chunk-1ypkh8g6.js} +1 -1
  62. package/dist/{chunk-9a22225r.js → chunk-2m09t0c0.js} +2 -2
  63. package/dist/chunk-7fkyfh65.js +1 -0
  64. package/dist/{chunk-hhdx5k96.js → chunk-7xpxzbkr.js} +49 -49
  65. package/dist/{chunk-e1666vjv.js → chunk-8e0az001.js} +2 -2
  66. package/dist/{bin/chunk-936vp7dx.js → chunk-b10cbk8z.js} +1 -1
  67. package/dist/{bin/chunk-ey9fagrr.js → chunk-gk58959n.js} +1 -1
  68. package/dist/{chunk-88z37ey4.js → chunk-h1rc94df.js} +1 -1
  69. package/dist/{chunk-zmxffmmq.js → chunk-hbhxk5a0.js} +2 -2
  70. package/dist/chunk-hz7k9ymh.js +1 -0
  71. package/dist/chunk-kj7gzdj6.js +1 -0
  72. package/dist/{chunk-dckz9xve.js → chunk-ky5c6t5y.js} +1 -1
  73. package/dist/chunk-mch30cyc.js +1 -0
  74. package/dist/chunk-n04a3bgf.js +1 -0
  75. package/dist/{chunk-13hxhzaz.js → chunk-nnqxmh7f.js} +1 -1
  76. package/dist/{chunk-snak8s7m.js → chunk-p6vszgc2.js} +2 -2
  77. package/dist/{chunk-d67xbk4v.js → chunk-q2njk4hx.js} +1 -1
  78. package/dist/{chunk-xd6w0c11.js → chunk-qjk1v1gs.js} +1 -1
  79. package/dist/{chunk-2p89vt3b.js → chunk-qtp90j44.js} +1 -1
  80. package/dist/{bin/chunk-c2b6nk0q.js → chunk-r5natbed.js} +1 -1
  81. package/dist/{chunk-qh9ep11z.js → chunk-rcxq9aaa.js} +5 -5
  82. package/dist/{chunk-kv2ztkp4.js → chunk-s3rpd72x.js} +2 -2
  83. package/dist/{chunk-77t2ctwn.js → chunk-spx89gaw.js} +1 -1
  84. package/dist/{chunk-8c4715hz.js → chunk-t0kh8haz.js} +1 -1
  85. package/dist/{chunk-y26yh5zp.js → chunk-vz95qy3n.js} +1 -1
  86. package/dist/deploy/index.js +1 -1
  87. package/dist/dns/index.js +1 -1
  88. package/dist/drivers/index.js +1 -1
  89. package/dist/drivers/shared/app-updates.d.ts +36 -0
  90. package/dist/index.js +24 -21
  91. package/dist/protection/index.js +1 -1
  92. package/dist/push/index.js +1 -1
  93. package/dist/spend/index.js +1 -1
  94. package/dist/ui/404.html +1 -1
  95. package/dist/ui/accept-invitation.html +1 -1
  96. package/dist/ui/access-denied.html +1 -1
  97. package/dist/ui/account/automation.html +6 -6
  98. package/dist/ui/account/security.html +2 -2
  99. package/dist/ui/applications/compose.html +6 -6
  100. package/dist/ui/applications/new.html +2 -2
  101. package/dist/ui/data/backups.html +6 -6
  102. package/dist/ui/data/services.html +6 -6
  103. package/dist/ui/data/volumes.html +6 -6
  104. package/dist/ui/index.html +6 -6
  105. package/dist/ui/infrastructure/topology.html +5 -5
  106. package/dist/ui/integrations.html +2 -2
  107. package/dist/ui/operations/alerts.html +6 -6
  108. package/dist/ui/operations/configuration.html +6 -6
  109. package/dist/ui/operations/jobs.html +6 -6
  110. package/dist/ui/operations/maintenance.html +6 -6
  111. package/dist/ui/operations/observability.html +6 -6
  112. package/dist/ui/operations/previews.html +6 -6
  113. package/dist/ui/operations/queue.html +5 -5
  114. package/dist/ui/operations/regions.html +6 -6
  115. package/dist/ui/operations/releases.html +5 -5
  116. package/dist/ui/operations/spend.html +6 -6
  117. package/dist/ui/operations/workloads.html +6 -6
  118. package/dist/ui/security.html +2 -2
  119. package/dist/ui/server/actions.html +6 -6
  120. package/dist/ui/server/activity.html +1 -1
  121. package/dist/ui/server/capacity.html +6 -6
  122. package/dist/ui/server/database.html +6 -6
  123. package/dist/ui/server/deployments.html +5 -5
  124. package/dist/ui/server/diagnostics.html +2 -2
  125. package/dist/ui/server/firewall.html +6 -6
  126. package/dist/ui/server/fleet.html +6 -6
  127. package/dist/ui/server/logs.html +6 -6
  128. package/dist/ui/server/metrics.html +5 -5
  129. package/dist/ui/server/security.html +2 -2
  130. package/dist/ui/server/services.html +2 -2
  131. package/dist/ui/server/sites.html +6 -6
  132. package/dist/ui/server/ssh-keys.html +6 -6
  133. package/dist/ui/server/team.html +6 -6
  134. package/dist/ui/server/terminal.html +2 -2
  135. package/dist/ui/serverless/alarms.html +6 -6
  136. package/dist/ui/serverless/assets.html +2 -2
  137. package/dist/ui/serverless/cost.html +2 -2
  138. package/dist/ui/serverless/data.html +6 -6
  139. package/dist/ui/serverless/deployments.html +2 -2
  140. package/dist/ui/serverless/firewall.html +1 -1
  141. package/dist/ui/serverless/functions.html +6 -6
  142. package/dist/ui/serverless/logs.html +6 -6
  143. package/dist/ui/serverless/metrics.html +2 -2
  144. package/dist/ui/serverless/queues.html +6 -6
  145. package/dist/ui/serverless/secrets.html +6 -6
  146. package/dist/ui/serverless/traces.html +6 -6
  147. package/dist/ui/serverless.html +6 -6
  148. package/package.json +3 -3
  149. package/dist/bin/chunk-08c0pzkb.js +0 -1
  150. package/dist/bin/chunk-12210qvj.js +0 -1
  151. package/dist/bin/chunk-3r3be05z.js +0 -1
  152. package/dist/bin/chunk-5rv31chh.js +0 -1
  153. package/dist/bin/chunk-6gktf2m2.js +0 -1
  154. package/dist/bin/chunk-ddmjjstg.js +0 -1
  155. package/dist/bin/chunk-dhhz4zyj.js +0 -1
  156. package/dist/bin/chunk-ds1z880f.js +0 -1
  157. package/dist/bin/chunk-g6a4n3rh.js +0 -1
  158. package/dist/bin/chunk-gs40j75w.js +0 -1
  159. package/dist/bin/chunk-jjjts1vt.js +0 -1
  160. package/dist/bin/chunk-qtdngvs8.js +0 -1
  161. package/dist/bin/chunk-tna7ay8d.js +0 -1
  162. package/dist/bin/chunk-tp4c2mv1.js +0 -1
  163. package/dist/bin/chunk-w5d6tr2x.js +0 -1
  164. package/dist/bin/chunk-xv4bscrm.js +0 -1
  165. package/dist/bin/chunk-y9eyc5pw.js +0 -1
  166. package/dist/chunk-as6by62d.js +0 -1
  167. package/dist/chunk-nrz6zypg.js +0 -1
  168. package/dist/chunk-q816js1y.js +0 -1
  169. package/dist/chunk-rg720cqg.js +0 -1
  170. package/dist/chunk-vq737g82.js +0 -1
package/dist/index.js CHANGED
@@ -1,14 +1,17 @@
1
- import{$ as Lg,$a as IC,$b as IS,$c as ZS,A as Pf,Aa as Xy,Ab as XC,B as If,Ba as eC,Bb as eS,Bc as gi,C as Df,Ca as tC,Cb as tS,Cc as hi,D as Ef,Da as rC,Db as rS,Dc as yi,E as pg,Ea as nC,Eb as nS,Ec as Ci,F as mg,Fa as iC,Fb as iS,Fc as Si,G as fg,Ga as oC,Gb as oS,Gc as Ai,H as gg,Ha as aC,Hb as aS,Hc as bi,I as hg,Ia as sC,Ib as sS,J as yg,Ja as cC,Jb as cS,K as Cg,Ka as lC,Kb as lS,L as Sg,La as dC,Lb as dS,M as Ag,Ma as uC,Mb as uS,N as bg,Na as pC,Nb as pS,O as Rg,Oa as mC,Ob as mS,P as Tg,Pa as fC,Pb as fS,Pc as LS,Q as $g,Qa as gC,Qb as gS,Qc as MS,R as Pg,Ra as hC,Rb as hS,Rc as FS,S as Ig,Sa as yC,Sb as yS,Sc as VS,T as Dg,Ta as CC,Tb as CS,Tc as _S,U as Eg,Ua as SC,Ub as SS,Uc as BS,V as wg,Va as AC,Vb as AS,Vc as WS,W as Og,Wa as bC,Wb as bS,Wc as zS,X as vg,Xa as RC,Xb as RS,Xc as HS,Y as Ng,Ya as TC,Yb as TS,Yc as GS,Z as kg,Za as $C,Zb as $S,Zc as KS,_ as xg,_a as PC,_b as PS,_c as US,a as Mm,aa as Mg,ab as DC,ac as DS,ad as qS,b as Fm,ba as Fg,bb as EC,bc as ES,bd as jS,c as Vm,ca as wy,cb as wC,cc as wS,cd as JS,d as _m,da as Oy,db as OC,dc as OS,dd as YS,e as Bm,ea as vy,eb as vC,ec as vS,ed as QS,f as Wm,fa as Ny,fb as NC,fc as NS,fd as XS,g as zm,ga as ky,gb as kC,gc as kS,gd as eA,h as Hm,ha as xy,hb as xC,hc as xS,hd as tA,i as Gm,ia as Ly,ib as LC,id as rA,j as Km,ja as My,jb as MC,jd as nA,k as Um,ka as Fy,kb as FC,kd as iA,l as Zm,la as Vy,lb as VC,ld as oA,m as qm,ma as _y,mb as _C,md as aA,n as jm,na as By,nb as BC,nd as sA,o as Jm,oa as Wy,ob as WC,od as Ri,p as Ym,pa as zy,pb as zC,pc as mi,pd as Ti,q as Qm,qa as Hy,qb as HC,qd as $i,r as Xm,ra as Gy,rb as GC,rd as Pi,s as ef,sa as Ky,sb as KC,t as tf,ta as Uy,tb as UC,u as rf,ua as Zy,ub as ZC,v as nf,va as qy,vb as qC,w as of,wa as jy,wb as jC,x as af,xa as Jy,xb as JC,y as Tf,ya as Yy,yb as YC,z as $f,za as Qy,zb as QC}from"./chunk-qh9ep11z.js";import{Ad as pi,sd as ii,td as oi,ud as ai,vd as si,wd as ci,xd as li,yd as di,zd as ui}from"./chunk-9a22225r.js";import{Id as fi}from"./chunk-0e16qt6k.js";import{$d as Pr,Be as xr,Fe as Lr,Jd as Mt,Ld as Ft,Le as Mr,Md as Vt,Nd as _t,Od as Bt,Oe as Fr,Pd as Wt,Pe as Vr,Qd as zt,Qe as _r,Re as Br,Sd as Gt,Td as gr,Ud as yr,Vd as Cr,Wd as Sr,We as Wr,Xd as Ar,Yd as br,Zd as Rr,_d as Tr,ae as Ir,be as Dr,ce as Er,de as wr,ef as zr,if as Hr,ke as Or,nf as Gr,pe as vr,te as Nr,xe as kr}from"./chunk-88z37ey4.js";import{of as Ct,pf as At,qf as bt}from"./chunk-13hxhzaz.js";import{sf as Le}from"./chunk-d67xbk4v.js";import{tf as fr}from"./chunk-dckz9xve.js";import{uf as $r}from"./chunk-8c4715hz.js";import{Af as Jt,Bf as Yt,Cf as Qt,Df as Xt,Ef as er,Ff as tr,Gf as rr,Hf as nr,If as ir,Jf as or,Kf as ar,Lf as sr,Mf as cr,Nf as j,Of as lr,Pf as dr,Qf as ur,Rf as pr,Sf as mr,vf as Kt,wf as Ut,xf as Zt,yf as qt,zf as jt}from"./chunk-2p89vt3b.js";import{Tf as q}from"./chunk-xd6w0c11.js";import{Bh as xn,Ch as Ln,Dg as un,Dh as Mn,Eg as pn,Eh as Fn,Fh as Vn,Gg as mn,Gh as _n,Hg as fn,Hh as Bn,Ig as gn,Jg as hn,Jh as Wn,Kg as yn,Kh as zn,Lh as Hn,Mh as Gn,Ng as Cn,Og as Sn,Pg as An,Tg as bn,Uf as Kr,Ug as Rn,Vf as Ur,Vg as Tn,Wf as Zr,Wg as $n,Xf as qr,Xg as Pn,Yf as ue,Yg as In,Zf as jr,_f as Jr,hg as Yr,ig as Qr,jg as Xr,kg as en,kh as Dn,lh as En,mg as tn,mh as wn,ng as rn,nh as On,rg as nn,sg as pe,vh as vn,wh as Nn,xh as kn}from"./chunk-hhdx5k96.js";import{Rh as Ht,Sh as hr}from"./chunk-zmxffmmq.js";import{Th as xe}from"./chunk-e1666vjv.js";import{Vh as St}from"./chunk-snak8s7m.js";import{Xh as yt}from"./chunk-cp54a0qn.js";import{$h as cf,$i as Bg,$j as Bh,Ai as Wf,Aj as mh,Ak as cy,Bi as zf,Bj as fh,Bk as ly,Ci as Hf,Cj as gh,Ck as dy,Di as Gf,Dj as hh,Dk as uy,Ei as Kf,Ej as yh,Ek as Dt,Fi as Uf,Fj as Ch,Fk as py,Gi as Zf,Gj as Sh,Gk as my,Hi as qf,Hj as Ah,Hk as fy,Ii as jf,Ij as bh,Ik as gy,Ji as Jf,Jj as Rh,Jk as hy,Ki as Yf,Kj as Th,Kk as yy,Li as Qf,Lj as $h,Lk as Cy,Mi as Xf,Mj as Ph,Mk as Sy,Ni as eg,Nj as Ih,Nk as Ay,Oi as tg,Oj as Dh,Ok as by,Pi as rg,Pj as Eh,Pk as Ry,Qi as ng,Qj as wh,Qk as Ty,Ri as ig,Rj as Oh,Rk as $y,Si as og,Sj as vh,Sk as Py,Ti as ag,Tj as Nh,Tk as Iy,Ui as sg,Uj as kh,Uk as Dy,Vi as cg,Vj as xh,Vk as Ey,Wi as lg,Wj as Lh,Xi as dg,Xj as Mh,Yi as ug,Yj as Fh,Zi as Vg,Zj as Vh,_h as sf,_i as _g,_j as _h,ai as lf,aj as Wg,ak as Wh,bi as df,bj as zg,bk as zh,ci as uf,cj as Hg,ck as Hh,di as pf,dj as Gg,dk as Gh,ei as mf,ej as Kg,ek as Kh,fi as ff,fj as Ug,fk as Uh,gi as gf,gj as Zg,gk as Zh,hi as hf,hj as qg,hk as qh,ii as yf,ij as jg,ik as jh,ji as Cf,jj as Jg,jk as Jh,ki as Sf,kj as Yg,kk as Yh,li as Af,lj as Qg,lk as Qh,mi as bf,mj as Xg,mk as Rt,ni as Rf,nj as eh,nk as Tt,oi as wf,oj as th,ok as $t,pi as Of,pj as rh,pk as Pt,qi as vf,qj as nh,qk as It,ri as Nf,rj as ih,rk as Xh,si as kf,sj as oh,sk as ey,ti as xf,tj as ah,tk as ty,ui as Lf,uj as sh,uk as ry,vi as Mf,vj as ch,vk as ny,wi as Ff,wj as lh,wk as iy,xi as Vf,xj as dh,xk as oy,yi as _f,yj as uh,yk as ay,zi as Bf,zj as ph,zk as sy}from"./chunk-kv2ztkp4.js";import{$k as Jn,Wk as Kn,Xk as Un,Yk as Zn,Zk as qn,_k as jn,al as Yn,cl as Qn,dl as Xn,el as ei,fl as ti,gl as ri,hl as ni}from"./chunk-y26yh5zp.js";import{jl as on,kl as an,ll as sn,ml as cn,nl as ln,ol as dn}from"./chunk-xtwjt370.js";import{pl as Et,ql as wt,rl as Ot,sl as vt,tl as Nt,ul as kt,vl as xt,wl as Lt}from"./chunk-cd0zpxhf.js";import{$l as Ba,$m as bs,$n as bc,$o as bl,$p as bd,$q as bu,$r as bp,$s as um,Al as ma,Am as K,An as qs,Ao as qc,Ap as ql,Aq as qd,Ar as qu,As as qp,Bl as fa,Bm as L,Bn as js,Bo as jc,Bp as jl,Bq as jd,Br as ju,Bs as jp,Cl as ga,Cm as as,Cn as Js,Co as Jc,Cp as Jl,Cq as Jd,Cr as Ju,Cs as Jp,Dl as ha,Dm as ss,Dn as Ys,Do as Yc,Dp as Yl,Dq as Yd,Dr as Yu,Ds as Yp,El as ya,Em as te,En as Qs,Eo as Qc,Ep as Ql,Eq as Qd,Er as Qu,Es as Qp,Fl as Ca,Fm as cs,Fn as Xs,Fo as Xc,Fp as Xl,Fq as Xd,Fr as Xu,Fs as Xp,Gl as Sa,Gm as ls,Gn as ec,Go as el,Gp as ed,Gq as eu,Gr as ep,Gs as em,Hl as Aa,Hm as ds,Hn as tc,Ho as tl,Hp as td,Hq as tu,Hr as tp,Hs as tm,Il as ba,Im as us,In as rc,Io as rl,Ip as rd,Iq as ru,Ir as rp,Is as rm,Jl as Ra,Jm as Te,Jn as nc,Jo as nl,Jp as nd,Jq as nu,Jr as np,Js as st,Kl as Ta,Km as M,Kn as ic,Ko as il,Kp as id,Kq as iu,Kr as ip,Ks as ct,Ll as $a,Lm as U,Ln as oc,Lo as ol,Lp as od,Lq as ou,Lr as op,Ls as lt,Ml as Pa,Mm as re,Mn as ac,Mo as al,Mp as ad,Mq as au,Mr as ap,Ms as dt,Nl as Ia,Nm as $e,Nn as sc,No as sl,Np as sd,Nq as su,Nr as sp,Ns as ut,Ol as Da,Om as Pe,On as cc,Oo as cl,Op as cd,Oq as cu,Or as cp,Os as pt,Pl as Ea,Pm as ps,Pn as lc,Po as ll,Pp as ld,Pq as lu,Pr as lp,Ps as mt,Ql as wa,Qm as ms,Qn as dc,Qo as dl,Qp as dd,Qq as du,Qr as dp,Qs as ft,Rl as Oa,Rm as Ie,Rn as uc,Ro as ul,Rp as ud,Rq as uu,Rr as up,Rs as gt,Sl as va,Sm as fs,Sn as pc,So as pl,Sp as pd,Sq as pu,Sr as pp,Ss as ht,Tl as Na,Tm as gs,Tn as mc,To as ml,Tp as md,Tq as mu,Tr as mp,Ts as nm,Ul as ka,Um as hs,Un as fc,Uo as fl,Up as fd,Uq as fu,Ur as fp,Us as im,Vl as xa,Vm as ys,Vn as gc,Vo as gl,Vp as gd,Vq as gu,Vr as gp,Vs as om,Wl as La,Wm as Cs,Wn as hc,Wo as hl,Wp as hd,Wq as hu,Wr as hp,Ws as am,Xl as Ma,Xm as De,Xn as yc,Xo as yl,Xp as yd,Xq as yu,Xr as yp,Xs as sm,Yl as Fa,Ym as Z,Yn as Cc,Yo as Cl,Yp as Cd,Yq as Cu,Yr as Cp,Ys as cm,Zl as Va,Zm as Ss,Zn as Sc,Zo as Sl,Zp as Sd,Zq as Su,Zr as Sp,Zs as lm,_l as _a,_m as As,_n as Ac,_o as Al,_p as Ad,_q as Au,_r as Ap,_s as dm,am as Wa,an as Rs,ao as Rc,ap as Rl,aq as Rd,ar as Ru,as as Rp,at as pm,bm as Se,bn as Ts,bo as Tc,bp as Tl,bq as Td,br as Tu,bs as Tp,bt as mm,cm as za,cn as $s,co as $c,cp as $l,cq as $d,cr as $u,cs as $p,ct as fm,dm as Ae,dn as Ps,do as Pc,dp as Pl,dq as Pd,dr as Pu,ds as Pp,dt as gm,em as be,en as Is,eo as Ic,ep as Il,eq as Id,er as Iu,es as Ip,et as hm,fm as Ha,fn as Ds,fo as Dc,fp as Dl,fq as Dd,fr as Du,fs as Dp,ft as ym,gm as Ga,gn as Es,go as Ec,gp as El,gq as Ed,gr as Eu,gs as Ep,gt as Cm,hm as Ka,hn as ws,ho as wc,hp as wl,hq as wd,hr as wu,hs as wp,ht as Sm,im as Ua,in as Os,io as Oc,ip as Ol,iq as Od,ir as Ou,is as Op,it as Am,jm as Za,jn as vs,jo as vc,jp as vl,jq as vd,jr as vu,js as vp,jt as bm,km as qa,kn as Ns,ko as Nc,kp as Nl,kq as Nd,kr as Nu,ks as Np,kt as Rm,lm as ja,ln as ks,lo as kc,lp as kl,lq as kd,lr as ku,ls as kp,lt as Tm,mm as Ja,mn as xs,mo as xc,mp as xl,mq as xd,mr as xu,ms as xp,mt as $m,nm as Ya,nn as Ls,no as Lc,np as Ll,nq as Ld,nr as Lu,ns as Lp,nt as Pm,om as Qa,on as Ms,oo as Mc,op as Ml,oq as Md,or as Mu,os as Mp,ot as Im,pm as Xa,pn as Fs,po as Fc,pp as Fl,pq as Fd,pr as Fu,ps as Fp,pt as Dm,qm as es,qn as Vs,qo as Vc,qp as Vl,qq as Vd,qr as Vu,qs as Vp,qt as Em,rm as ts,rn as _s,ro as _c,rp as _l,rq as _d,rr as _u,rs as _p,rt as wm,sm as rs,sn as Bs,so as Bc,sp as Bl,sq as Bd,sr as Bu,ss as Bp,st as Om,tm as X,tn as Ws,to as Wc,tp as Wl,tq as Wd,tr as Wu,ts as Wp,tt as vm,um as ns,un as zs,uo as zc,up as zl,uq as zd,ur as zu,us as zp,ut as Nm,vm as is,vn as Hs,vo as Hc,vp as Hl,vq as Hd,vr as Hu,vs as Hp,vt as km,wm as os,wn as Gs,wo as Gc,wp as Gl,wq as Gd,wr as Gu,ws as Gp,wt as xm,xl as da,xm as ee,xn as Ks,xo as Kc,xp as Kl,xq as Kd,xr as Ku,xs as Kp,xt as Lm,yl as ua,ym as w,yn as Us,yo as Uc,yp as Ul,yq as Ud,yr as Uu,ys as Up,zl as pa,zm as Re,zn as Zs,zo as Zc,zp as Zl,zq as Zd,zr as Zu,zs as Zp}from"./chunk-06jk7ba9.js";import{yt as je}from"./chunk-77t2ctwn.js";import{createHmac as fe,createSign as Ve,timingSafeEqual as _e}from"node:crypto";function B(e){let t=e instanceof Date?e.getTime():e;if(!Number.isFinite(t))throw TypeError("Media access timestamp must be finite");return Math.floor(t/1000)}function ge(e){return Buffer.from(e).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function Be(e){return Buffer.from(e).toString("base64url")}function he(e,t=!1){if(!e||/[\r\n]/.test(e))throw TypeError("Media resource is invalid");let r=t?e.replaceAll("*","wildcard"):e,n=new URL(r);if(!["http:","https:"].includes(n.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!t&&e.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function ye(e,t){let r=Ve("RSA-SHA1");return r.update(e),r.end(),ge(r.sign(t))}function Ce(e){he(e.resource,!0);let r={DateLessThan:{"AWS:EpochTime":B(e.expiresAt)}};if(e.activeAt!==void 0)r.DateGreaterThan={"AWS:EpochTime":B(e.activeAt)};if(e.ipAddress)r.IpAddress={"AWS:SourceIp":e.ipAddress};return JSON.stringify({Statement:[{Resource:e.resource,Condition:r}]})}function Di(e,t,r){he(e);let n=B(t),o=e.includes("?")?"&":"?",l=Ce({resource:e,expiresAt:t}),c=ye(l,r.privateKey);return`${e}${o}Expires=${n}&Signature=${encodeURIComponent(c)}&Key-Pair-Id=${encodeURIComponent(r.keyPairId)}`}function Ei(e,t){let r=Ce(e);return{"CloudFront-Key-Pair-Id":t.keyPairId,"CloudFront-Policy":ge(Buffer.from(r)),"CloudFront-Signature":ye(r,t.privateKey)}}function wi(e){if(!e.resource||/[\r\n]/.test(e.resource))throw TypeError("Media resource is invalid");let t=Be(Buffer.from(JSON.stringify({resource:e.resource,expiresAt:B(e.expiresAt),...e.keyId?{keyId:e.keyId}:{},...e.audience?{audience:e.audience}:{}}))),r=fe("sha256",e.secret).update(t).digest("base64url");return`${t}.${r}`}function Oi(e,t){let[r,n,o]=e.split(".");if(!r||!n||o)return null;let l=fe("sha256",t.secret).update(r).digest(),c;try{c=Buffer.from(n,"base64url")}catch{return null}if(l.length!==c.length||!_e(l,c))return null;try{let s=JSON.parse(Buffer.from(r,"base64url").toString("utf8")),d=B(t.now??Date.now());if(!s.resource||!Number.isSafeInteger(s.expiresAt)||s.expiresAt<=d)return null;if(t.resource&&s.resource!==t.resource)return null;if(t.audience&&s.audience!==t.audience)return null;return s}catch{return null}}function vi(e,t=!1){let r=new URL(e,"https://media.invalid").pathname.toLowerCase(),n=/\.(?:m3u8|mpd|vtt|json)$/.test(r),o=/\.(?:key|license)$/.test(r)||r.includes("/keys/")||r.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":t&&(n||o)?"private, no-store":n?"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 Ni(e){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(e.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(e.region))throw TypeError("Media bucket region is invalid");let t=e.prefix?`/${e.prefix.replace(/^\/+|\/+$/g,"")}`:"",r=e.protected??!1,n="public, max-age=31536000, immutable",o=r?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${e.bucket}.s3.${e.region}.amazonaws.com`,originPath:t,domain:e.domain,trustedKeyGroupIds:[...new Set(e.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:o,compress:!0,signed:r},{pathPattern:"*.mpd",cacheControl:o,compress:!0,signed:r},{pathPattern:"*.vtt",cacheControl:o,compress:!0,signed:r},{pathPattern:"*",cacheControl:n,compress:!1,signed:r}],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 We{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;constructor(e){this.config=e.config,this.environment=e.environment,this.builder=new Se(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let t=this.config.environments[this.environment]?.infrastructure;if(!t)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...t,compute:{...this.config.infrastructure?.compute,...t.compute},storage:{...this.config.infrastructure?.storage,...t.storage},functions:{...this.config.infrastructure?.functions,...t.functions},servers:{...this.config.infrastructure?.servers,...t.servers},databases:{...this.config.infrastructure?.databases,...t.databases},cdn:{...this.config.infrastructure?.cdn,...t.cdn},sftp:t.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...t.queues},redirects:{...this.config.infrastructure?.redirects,...t.redirects},realtime:{...this.config.infrastructure?.realtime,...t.realtime},cache:{...this.config.infrastructure?.cache,...t.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...t.fileSystem},email:{...this.config.infrastructure?.email,...t.email},search:{...this.config.infrastructure?.search,...t.search},ai:{...this.config.infrastructure?.ai,...t.ai}}}}shouldDeploy(e){if(e.environments&&!e.environments.includes(this.environment))return!1;if(e.requiresFeatures){let t=this.config.features||{};if(!e.requiresFeatures.every((n)=>t[n]===!0))return!1}if(e.regions){let t=this.config.environments[this.environment]?.region||this.config.project.region;if(!e.regions.includes(t))return!1}if(e.condition&&typeof e.condition==="function")return e.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let e=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,t=Number(e||3008);return Number.isFinite(t)&&t>0?t: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(e,t){return e==="public"||t.routeCompute===!0}storageBucketName(e,t,r){return this.mergedConfig.infrastructure?.storage?.[r]?.bucket??`${e}-${t}-${r}`}fileSystemLogicalId(e,t,r){return be(Ae({slug:`${e}-${r}`,environment:t,resourceType:"efs"}))}resolveSftpStorage(e,t,r){let n=e.storage;if(n?.type==="efs"&&n.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[n.fileSystem])throw Error(`sftp: storage.fileSystem "${n.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(t,r,n.fileSystem)},posixProfile:n.posixProfile}}if(n?.type==="s3"&&n.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[n.storageBucket])throw Error(`sftp: storage.storageBucket "${n.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(t,r,n.storageBucket)}}return}resolveComputeCachePathPatterns(e){if(e&&e.length>0)return e;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(e,t){return{PathPattern:e,TargetOriginId:t,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(e,t,r,n,o,l){let c=this.serverEipLogicalIds.get("app"),s=this.serverEipLogicalIds.get("appInstance");if(!c)return;let d=`EC2-${n}-${o}-api`,g=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",u=g==="us-east-1"?".compute-1.amazonaws.com":`.${g}.compute.amazonaws.com`,S={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:c}]}]},u]]},A=this.resolveApiOriginPort();if(e.push({Id:d,DomainName:S,CustomOriginConfig:{HTTPPort:A,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),r.push(c),s)r.push(s);for(let b of l)t.push(this.createComputeCacheBehavior(b,d))}buildCaddyfile(e){let t=e.filter(([,o])=>typeof o.domain==="string"&&o.domain&&typeof o.port==="number");if(t.length===0)return;let r=new Map;for(let[,o]of t){let l=r.get(o.domain)??[];l.push({port:o.port,path:o.path}),r.set(o.domain,l)}let n=[];for(let[o,l]of r){let s=[...l].sort((d,g)=>{let u=!d.path||d.path==="/",S=!g.path||g.path==="/";if(u&&!S)return 1;if(!u&&S)return-1;return(g.path?.length??0)-(d.path?.length??0)}).map((d)=>{let g=!d.path||d.path==="/",u=`reverse_proxy localhost:${d.port}`;return g?` handle {
1
+ import{$ as Fg,$a as EC,$b as ES,$c as jS,A as Df,Aa as tC,Ab as tS,B as Ef,Ba as rC,Bb as rS,Bc as hi,C as wf,Ca as nC,Cb as nS,Cc as yi,D as Of,Da as iC,Db as iS,Dc as Ci,E as fg,Ea as oC,Eb as oS,Ec as Si,F as gg,Fa as aC,Fb as aS,Fc as Ai,G as hg,Ga as sC,Gb as sS,Gc as bi,H as yg,Ha as cC,Hb as cS,Hc as Ri,I as Cg,Ia as lC,Ib as lS,J as Sg,Ja as dC,Jb as dS,K as Ag,Ka as uC,Kb as uS,L as bg,La as pC,Lb as pS,M as Rg,Ma as mC,Mb as mS,N as Tg,Na as fC,Nb as fS,O as $g,Oa as gC,Ob as gS,P as Pg,Pa as hC,Pb as hS,Pc as FS,Q as Ig,Qa as yC,Qb as yS,Qc as VS,R as Dg,Ra as CC,Rb as CS,Rc as _S,S as Eg,Sa as SC,Sb as SS,Sc as BS,T as wg,Ta as AC,Tb as AS,Tc as WS,U as Og,Ua as bC,Ub as bS,Uc as zS,V as vg,Va as RC,Vb as RS,Vc as HS,W as Ng,Wa as TC,Wb as TS,Wc as GS,X as kg,Xa as $C,Xb as $S,Xc as KS,Y as xg,Ya as PC,Yb as PS,Yc as US,Z as Lg,Za as IC,Zb as IS,Zc as ZS,_ as Mg,_a as DC,_b as DS,_c as qS,a as Vm,aa as Vg,ab as wC,ac as wS,ad as JS,b as _m,ba as _g,bb as OC,bc as OS,bd as YS,c as Bm,ca as vy,cb as vC,cc as vS,cd as QS,d as Wm,da as Ny,db as NC,dc as NS,dd as XS,e as zm,ea as ky,eb as kC,ec as kS,ed as eA,f as Hm,fa as xy,fb as xC,fc as xS,fd as tA,g as Gm,ga as Ly,gb as LC,gc as LS,gd as rA,h as Km,ha as My,hb as MC,hc as MS,hd as nA,i as Um,ia as Fy,ib as FC,id as iA,j as Zm,ja as Vy,jb as VC,jd as oA,k as qm,ka as _y,kb as _C,kd as aA,l as jm,la as By,lb as BC,ld as sA,m as Jm,ma as Wy,mb as WC,md as cA,n as Ym,na as zy,nb as zC,nd as lA,o as Qm,oa as Hy,ob as HC,od as Ti,p as Xm,pa as Gy,pb as GC,pc as fi,pd as $i,q as ef,qa as Ky,qb as KC,qd as Pi,r as tf,ra as Uy,rb as UC,rd as Ii,s as rf,sa as Zy,sb as ZC,t as nf,ta as qy,tb as qC,u as of,ua as jy,ub as jC,v as af,va as Jy,vb as JC,w as sf,wa as Yy,wb as YC,x as cf,xa as Qy,xb as QC,y as Pf,ya as Xy,yb as XC,z as If,za as eC,zb as eS}from"./chunk-rcxq9aaa.js";import{Ad as mi,sd as oi,td as ai,ud as si,vd as ci,wd as li,xd as di,yd as ui,zd as pi}from"./chunk-2m09t0c0.js";import{Id as gi}from"./chunk-1ypkh8g6.js";import{$d as Ir,Be as Lr,Fe as Mr,Jd as Ft,Ld as Vt,Le as Fr,Md as _t,Nd as Bt,Od as Wt,Oe as Vr,Pd as zt,Pe as _r,Qd as Ht,Qe as Br,Re as Wr,Sd as Kt,Td as hr,Ud as Cr,Vd as Sr,Wd as Ar,We as zr,Xd as br,Yd as Rr,Zd as Tr,_d as $r,ae as Dr,be as Er,ce as wr,de as Or,ef as Hr,if as Gr,ke as vr,nf as Kr,pe as Nr,te as kr,xe as xr}from"./chunk-h1rc94df.js";import{of as St,pf as bt,qf as Rt}from"./chunk-nnqxmh7f.js";import{sf as Me}from"./chunk-q2njk4hx.js";import{tf as gr}from"./chunk-ky5c6t5y.js";import{uf as Pr}from"./chunk-t0kh8haz.js";import{Af as Yt,Bf as Qt,Cf as Xt,Df as er,Ef as tr,Ff as rr,Gf as nr,Hf as ir,If as or,Jf as ar,Kf as sr,Lf as cr,Mf as lr,Nf as j,Of as dr,Pf as ur,Qf as pr,Rf as mr,Sf as fr,vf as Ut,wf as Zt,xf as qt,yf as jt,zf as Jt}from"./chunk-qtp90j44.js";import{Tf as q}from"./chunk-qjk1v1gs.js";import{Ch as Ln,Dh as Mn,Eg as pn,Eh as Fn,Fg as mn,Fh as Vn,Gh as _n,Hg as fn,Hh as Bn,Ig as gn,Ih as Wn,Jg as hn,Kg as yn,Kh as zn,Lg as Cn,Lh as Hn,Mh as Gn,Nh as Kn,Og as Sn,Pg as An,Qg as bn,Uf as Ur,Ug as Rn,Vf as Zr,Vg as Tn,Wf as qr,Wg as $n,Xf as jr,Xg as Pn,Yf as ue,Yg as In,Zf as Jr,Zg as Dn,_f as Yr,fg as Ee,ig as Qr,jg as Xr,kg as en,lg as tn,lh as En,mh as wn,ng as rn,nh as On,og as nn,oh as vn,sg as on,tg as pe,wh as Nn,xh as kn,yh as xn}from"./chunk-7xpxzbkr.js";import{Sh as Gt,Th as yr}from"./chunk-hbhxk5a0.js";import{Uh as Le}from"./chunk-8e0az001.js";import{Wh as At}from"./chunk-p6vszgc2.js";import{Yh as Ct}from"./chunk-gk58959n.js";import{$h as lf,$i as Wg,$j as Wh,Ai as zf,Aj as fh,Ak as ly,Bi as Hf,Bj as gh,Bk as dy,Ci as Gf,Cj as hh,Ck as uy,Di as Kf,Dj as yh,Dk as py,Ei as Uf,Ej as Ch,Ek as my,Fi as Zf,Fj as Sh,Fk as Et,Gi as qf,Gj as Ah,Gk as fy,Hi as jf,Hj as bh,Hk as gy,Ii as Jf,Ij as Rh,Ik as hy,Ji as Yf,Jj as Th,Jk as yy,Ki as Qf,Kj as $h,Kk as Cy,Li as Xf,Lj as Ph,Lk as Sy,Mi as eg,Mj as Ih,Mk as Ay,Ni as tg,Nj as Dh,Nk as by,Oi as rg,Oj as Eh,Ok as Ry,Pi as ng,Pj as wh,Pk as Ty,Qi as ig,Qj as Oh,Qk as $y,Ri as og,Rj as vh,Rk as Py,Si as ag,Sj as Nh,Sk as Iy,Ti as sg,Tj as kh,Tk as Dy,Ui as cg,Uj as xh,Uk as Ey,Vi as lg,Vj as Lh,Vk as wy,Wi as dg,Wj as Mh,Wk as Oy,Xi as ug,Xj as Fh,Yi as pg,Yj as Vh,Zi as mg,Zj as _h,_i as Bg,_j as Bh,ai as df,aj as zg,ak as zh,bi as uf,bj as Hg,bk as Hh,ci as pf,cj as Gg,ck as Gh,di as mf,dj as Kg,dk as Kh,ei as ff,ej as Ug,ek as Uh,fi as gf,fj as Zg,fk as Zh,gi as hf,gj as qg,gk as qh,hi as yf,hj as jg,hk as jh,ii as Cf,ij as Jg,ik as Jh,ji as Sf,jj as Yg,jk as Yh,ki as Af,kj as Qg,kk as Qh,li as bf,lj as Xg,lk as Xh,mi as Rf,mj as eh,mk as ey,ni as Tf,nj as th,nk as Tt,oi as $f,oj as rh,ok as $t,pi as vf,pj as nh,pk as Pt,qi as Nf,qj as ih,qk as It,ri as kf,rj as oh,rk as Dt,si as xf,sj as ah,sk as ty,ti as Lf,tj as sh,tk as ry,ui as Mf,uj as ch,uk as ny,vi as Ff,vj as lh,vk as iy,wi as Vf,wj as dh,wk as oy,xi as _f,xj as uh,xk as ay,yi as Bf,yj as ph,yk as sy,zi as Wf,zj as mh,zk as cy}from"./chunk-s3rpd72x.js";import{$k as Jn,Xk as Un,Yk as Zn,Zk as qn,_k as jn,al as Yn,bl as Qn,dl as Xn,el as ei,fl as ti,gl as ri,hl as ni,il as ii}from"./chunk-vz95qy3n.js";import{kl as an,ll as sn,ml as cn,nl as ln,ol as dn,pl as un}from"./chunk-r5natbed.js";import{ql as wt,rl as Ot,sl as vt,tl as Nt,ul as kt,vl as xt,wl as Lt,xl as Mt}from"./chunk-b10cbk8z.js";import{$l as Wa,$m as Rs,$n as Rc,$o as Rl,$p as Rd,$q as Ru,$r as Rp,$s as pm,Al as fa,Am as Re,An as js,Ao as jc,Ap as jl,Aq as jd,Ar as ju,As as jp,Bl as ga,Bm as K,Bn as Js,Bo as Jc,Bp as Jl,Bq as Jd,Br as Ju,Bs as Jp,Cl as ha,Cm as L,Cn as Ys,Co as Yc,Cp as Yl,Cq as Yd,Cr as Yu,Cs as Yp,Dl as ya,Dm as cs,Dn as Qs,Do as Qc,Dp as Ql,Dq as Qd,Dr as Qu,Ds as Qp,El as Ca,Em as ls,En as Xs,Eo as Xc,Ep as Xl,Eq as Xd,Er as Xu,Es as Xp,Fl as Sa,Fm as te,Fn as ec,Fo as el,Fp as ed,Fq as eu,Fr as ep,Fs as em,Gl as Aa,Gm as ds,Gn as tc,Go as tl,Gp as td,Gq as tu,Gr as tp,Gs as tm,Hl as ba,Hm as us,Hn as rc,Ho as rl,Hp as rd,Hq as ru,Hr as rp,Hs as rm,Il as Ra,Im as ps,In as nc,Io as nl,Ip as nd,Iq as nu,Ir as np,Is as nm,Jl as Ta,Jm as ms,Jn as ic,Jo as il,Jp as id,Jq as iu,Jr as ip,Js as im,Kl as $a,Km as Te,Kn as oc,Ko as ol,Kp as od,Kq as ou,Kr as op,Ks as ct,Ll as Pa,Lm as M,Ln as ac,Lo as al,Lp as ad,Lq as au,Lr as ap,Ls as lt,Ml as Ia,Mm as U,Mn as sc,Mo as sl,Mp as sd,Mq as su,Mr as sp,Ms as dt,Nl as Da,Nm as re,Nn as cc,No as cl,Np as cd,Nq as cu,Nr as cp,Ns as ut,Ol as Ea,Om as $e,On as lc,Oo as ll,Op as ld,Oq as lu,Or as lp,Os as pt,Pl as wa,Pm as Pe,Pn as dc,Po as dl,Pp as dd,Pq as du,Pr as dp,Ps as mt,Ql as Oa,Qm as fs,Qn as uc,Qo as ul,Qp as ud,Qq as uu,Qr as up,Qs as ft,Rl as va,Rm as gs,Rn as pc,Ro as pl,Rp as pd,Rq as pu,Rr as pp,Rs as gt,Sl as Na,Sm as Ie,Sn as mc,So as ml,Sp as md,Sq as mu,Sr as mp,Ss as ht,Tl as ka,Tm as hs,Tn as fc,To as fl,Tp as fd,Tq as fu,Tr as fp,Ts as yt,Ul as xa,Um as ys,Un as gc,Uo as gl,Up as gd,Uq as gu,Ur as gp,Us as om,Vl as La,Vm as Cs,Vn as hc,Vo as hl,Vp as hd,Vq as hu,Vr as hp,Vs as am,Wl as Ma,Wm as Ss,Wn as yc,Wo as yl,Wp as yd,Wq as yu,Wr as yp,Ws as sm,Xl as Fa,Xm as As,Xn as Cc,Xo as Cl,Xp as Cd,Xq as Cu,Xr as Cp,Xs as cm,Yl as Va,Ym as De,Yn as Sc,Yo as Sl,Yp as Sd,Yq as Su,Yr as Sp,Ys as lm,Zl as _a,Zm as Z,Zn as Ac,Zo as Al,Zp as Ad,Zq as Au,Zr as Ap,Zs as dm,_l as Ba,_m as bs,_n as bc,_o as bl,_p as bd,_q as bu,_r as bp,_s as um,am as za,an as Ts,ao as Tc,ap as Tl,aq as Td,ar as Tu,as as Tp,at as mm,bm as Ha,bn as $s,bo as $c,bp as $l,bq as $d,br as $u,bs as $p,bt as fm,cm as Se,cn as Ps,co as Pc,cp as Pl,cq as Pd,cr as Pu,cs as Pp,ct as gm,dm as Ga,dn as Is,do as Ic,dp as Il,dq as Id,dr as Iu,ds as Ip,dt as hm,em as Ae,en as Ds,eo as Dc,ep as Dl,eq as Dd,er as Du,es as Dp,et as ym,fm as be,fn as Es,fo as Ec,fp as El,fq as Ed,fr as Eu,fs as Ep,ft as Cm,gm as Ka,gn as ws,go as wc,gp as wl,gq as wd,gr as wu,gs as wp,gt as Sm,hm as Ua,hn as Os,ho as Oc,hp as Ol,hq as Od,hr as Ou,hs as Op,ht as Am,im as Za,in as vs,io as vc,ip as vl,iq as vd,ir as vu,is as vp,it as bm,jm as qa,jn as Ns,jo as Nc,jp as Nl,jq as Nd,jr as Nu,js as Np,jt as Rm,km as ja,kn as ks,ko as kc,kp as kl,kq as kd,kr as ku,ks as kp,kt as Tm,lm as Ja,ln as xs,lo as xc,lp as xl,lq as xd,lr as xu,ls as xp,lt as $m,mm as Ya,mn as Ls,mo as Lc,mp as Ll,mq as Ld,mr as Lu,ms as Lp,mt as Pm,nm as Qa,nn as Ms,no as Mc,np as Ml,nq as Md,nr as Mu,ns as Mp,nt as Im,om as Xa,on as Fs,oo as Fc,op as Fl,oq as Fd,or as Fu,os as Fp,ot as Dm,pm as es,pn as Vs,po as Vc,pp as Vl,pq as Vd,pr as Vu,ps as Vp,pt as Em,qm as ts,qn as _s,qo as _c,qp as _l,qq as _d,qr as _u,qs as _p,qt as wm,rm as rs,rn as Bs,ro as Bc,rp as Bl,rq as Bd,rr as Bu,rs as Bp,rt as Om,sm as ns,sn as Ws,so as Wc,sp as Wl,sq as Wd,sr as Wu,ss as Wp,st as vm,tm as is,tn as zs,to as zc,tp as zl,tq as zd,tr as zu,ts as zp,tt as Nm,um as X,un as Hs,uo as Hc,up as Hl,uq as Hd,ur as Hu,us as Hp,ut as km,vm as os,vn as Gs,vo as Gc,vp as Gl,vq as Gd,vr as Gu,vs as Gp,vt as xm,wm as as,wn as Ks,wo as Kc,wp as Kl,wq as Kd,wr as Ku,ws as Kp,wt as Lm,xm as ss,xn as Us,xo as Uc,xp as Ul,xq as Ud,xr as Uu,xs as Up,xt as Mm,yl as pa,ym as ee,yn as Zs,yo as Zc,yp as Zl,yq as Zd,yr as Zu,ys as Zp,yt as Fm,zl as ma,zm as w,zn as qs,zo as qc,zp as ql,zq as qd,zr as qu,zs as qp}from"./chunk-0hj552t7.js";import{zt as Je}from"./chunk-spx89gaw.js";import{createHmac as fe,createSign as _e,timingSafeEqual as Be}from"node:crypto";function B(e){let t=e instanceof Date?e.getTime():e;if(!Number.isFinite(t))throw TypeError("Media access timestamp must be finite");return Math.floor(t/1000)}function ge(e){return Buffer.from(e).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function We(e){return Buffer.from(e).toString("base64url")}function he(e,t=!1){if(!e||/[\r\n]/.test(e))throw TypeError("Media resource is invalid");let r=t?e.replaceAll("*","wildcard"):e,n=new URL(r);if(!["http:","https:"].includes(n.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!t&&e.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function ye(e,t){let r=_e("RSA-SHA1");return r.update(e),r.end(),ge(r.sign(t))}function Ce(e){he(e.resource,!0);let r={DateLessThan:{"AWS:EpochTime":B(e.expiresAt)}};if(e.activeAt!==void 0)r.DateGreaterThan={"AWS:EpochTime":B(e.activeAt)};if(e.ipAddress)r.IpAddress={"AWS:SourceIp":e.ipAddress};return JSON.stringify({Statement:[{Resource:e.resource,Condition:r}]})}function Ei(e,t,r){he(e);let n=B(t),i=e.includes("?")?"&":"?",l=Ce({resource:e,expiresAt:t}),c=ye(l,r.privateKey);return`${e}${i}Expires=${n}&Signature=${encodeURIComponent(c)}&Key-Pair-Id=${encodeURIComponent(r.keyPairId)}`}function wi(e,t){let r=Ce(e);return{"CloudFront-Key-Pair-Id":t.keyPairId,"CloudFront-Policy":ge(Buffer.from(r)),"CloudFront-Signature":ye(r,t.privateKey)}}function Oi(e){if(!e.resource||/[\r\n]/.test(e.resource))throw TypeError("Media resource is invalid");let t=We(Buffer.from(JSON.stringify({resource:e.resource,expiresAt:B(e.expiresAt),...e.keyId?{keyId:e.keyId}:{},...e.audience?{audience:e.audience}:{}}))),r=fe("sha256",e.secret).update(t).digest("base64url");return`${t}.${r}`}function vi(e,t){let[r,n,i]=e.split(".");if(!r||!n||i)return null;let l=fe("sha256",t.secret).update(r).digest(),c;try{c=Buffer.from(n,"base64url")}catch{return null}if(l.length!==c.length||!Be(l,c))return null;try{let s=JSON.parse(Buffer.from(r,"base64url").toString("utf8")),d=B(t.now??Date.now());if(!s.resource||!Number.isSafeInteger(s.expiresAt)||s.expiresAt<=d)return null;if(t.resource&&s.resource!==t.resource)return null;if(t.audience&&s.audience!==t.audience)return null;return s}catch{return null}}function Ni(e,t=!1){let r=new URL(e,"https://media.invalid").pathname.toLowerCase(),n=/\.(?:m3u8|mpd|vtt|json)$/.test(r),i=/\.(?:key|license)$/.test(r)||r.includes("/keys/")||r.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":t&&(n||i)?"private, no-store":n?"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 ki(e){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(e.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(e.region))throw TypeError("Media bucket region is invalid");let t=e.prefix?`/${e.prefix.replace(/^\/+|\/+$/g,"")}`:"",r=e.protected??!1,n="public, max-age=31536000, immutable",i=r?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${e.bucket}.s3.${e.region}.amazonaws.com`,originPath:t,domain:e.domain,trustedKeyGroupIds:[...new Set(e.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:i,compress:!0,signed:r},{pathPattern:"*.mpd",cacheControl:i,compress:!0,signed:r},{pathPattern:"*.vtt",cacheControl:i,compress:!0,signed:r},{pathPattern:"*",cacheControl:n,compress:!1,signed:r}],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 ze{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;constructor(e){this.config=e.config,this.environment=e.environment,this.builder=new Se(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let t=this.config.environments[this.environment]?.infrastructure;if(!t)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...t,compute:{...this.config.infrastructure?.compute,...t.compute},storage:{...this.config.infrastructure?.storage,...t.storage},functions:{...this.config.infrastructure?.functions,...t.functions},servers:{...this.config.infrastructure?.servers,...t.servers},databases:{...this.config.infrastructure?.databases,...t.databases},cdn:{...this.config.infrastructure?.cdn,...t.cdn},sftp:t.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...t.queues},redirects:{...this.config.infrastructure?.redirects,...t.redirects},realtime:{...this.config.infrastructure?.realtime,...t.realtime},cache:{...this.config.infrastructure?.cache,...t.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...t.fileSystem},email:{...this.config.infrastructure?.email,...t.email},search:{...this.config.infrastructure?.search,...t.search},ai:{...this.config.infrastructure?.ai,...t.ai}}}}shouldDeploy(e){if(e.environments&&!e.environments.includes(this.environment))return!1;if(e.requiresFeatures){let t=this.config.features||{};if(!e.requiresFeatures.every((n)=>t[n]===!0))return!1}if(e.regions){let t=this.config.environments[this.environment]?.region||this.config.project.region;if(!e.regions.includes(t))return!1}if(e.condition&&typeof e.condition==="function")return e.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let e=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,t=Number(e||3008);return Number.isFinite(t)&&t>0?t: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(e,t){return e==="public"||t.routeCompute===!0}storageBucketName(e,t,r){return this.mergedConfig.infrastructure?.storage?.[r]?.bucket??`${e}-${t}-${r}`}fileSystemLogicalId(e,t,r){return be(Ae({slug:`${e}-${r}`,environment:t,resourceType:"efs"}))}resolveSftpStorage(e,t,r){let n=e.storage;if(n?.type==="efs"&&n.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[n.fileSystem])throw Error(`sftp: storage.fileSystem "${n.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(t,r,n.fileSystem)},posixProfile:n.posixProfile}}if(n?.type==="s3"&&n.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[n.storageBucket])throw Error(`sftp: storage.storageBucket "${n.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(t,r,n.storageBucket)}}return}resolveComputeCachePathPatterns(e){if(e&&e.length>0)return e;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(e,t){return{PathPattern:e,TargetOriginId:t,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(e,t,r,n,i,l){let c=this.serverEipLogicalIds.get("app"),s=this.serverEipLogicalIds.get("appInstance");if(!c)return;let d=`EC2-${n}-${i}-api`,h=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",u=h==="us-east-1"?".compute-1.amazonaws.com":`.${h}.compute.amazonaws.com`,b={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:c}]}]},u]]},A=this.resolveApiOriginPort();if(e.push({Id:d,DomainName:b,CustomOriginConfig:{HTTPPort:A,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),r.push(c),s)r.push(s);for(let R of l)t.push(this.createComputeCacheBehavior(R,d))}buildCaddyfile(e){let t=e.filter(([,i])=>typeof i.domain==="string"&&i.domain&&typeof i.port==="number");if(t.length===0)return;let r=new Map;for(let[,i]of t){let l=r.get(i.domain)??[];l.push({port:i.port,path:i.path}),r.set(i.domain,l)}let n=[];for(let[i,l]of r){let s=[...l].sort((d,h)=>{let u=!d.path||d.path==="/",b=!h.path||h.path==="/";if(u&&!b)return 1;if(!u&&b)return-1;return(h.path?.length??0)-(d.path?.length??0)}).map((d)=>{let h=!d.path||d.path==="/",u=`reverse_proxy localhost:${d.port}`;return h?` handle {
2
2
  ${u}
3
3
  }`:` handle ${d.path} {
4
4
  ${u}
5
- }`});n.push(`${o} {
5
+ }`});n.push(`${i} {
6
6
  ${s.join(`
7
7
  `)}
8
8
  }`)}return n.join(`
9
9
 
10
- `)}normalizeMountPath(e){let t=e?.mountPath||e?.path;if(!t||t==="/")return;let r=`/${t}`.replace(/\/+/g,"/").replace(/\/$/,"");return r==="/"?void 0:r}storageBucketLogicalId(e,t,r){return`${e}-${t}-s3-${r}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}pathMountRewriteFunctionCode(e,t="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(e)}; var rewriteStyle = ${JSON.stringify(t)}; 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 e=this.mergedConfig.project.slug,t=this.environment,r=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),n=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),o=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(e,t),this.generateContainerInfrastructure(e,t);if(r)this.generateServerless(e,t);if(n)this.generateServer(e,t);if(o)this.generateComputeApp(e,t);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(e,t);if(this.generateSharedInfrastructure(e,t),this.config.tags)this.applyGlobalTags(this.config.tags);return this}applyGlobalTags(e){}generateNetworkInfrastructure(e,t){if(this.builder.hasResource("VPC"))return;let n=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:o,logicalId:l}=Re.createVpc({slug:e,environment:t,cidr:n,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",o);let c=`${e}${t}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(c,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${e}-${t}-igw`},{Key:"Environment",Value:t}]}});let s=`${e}${t}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(s,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:c}}});let d=`${e}${t}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(d,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${e}-${t}-public-rt`},{Key:"Environment",Value:t}]}}),this.builder.addResource(`${e}${t}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:d},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:c}},DependsOn:s});let g=this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1",u=["a","b"];for(let S=0;S<2;S++){let A=`PublicSubnet${S+1}`;this.builder.addResource(A,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${S}.0/24`,AvailabilityZone:`${g}${u[S]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${e}-${t}-public-${u[S]}`},{Key:"Environment",Value:t}]}}),this.builder.addResource(`${A}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:A},RouteTableId:{Ref:d}}})}}generateContainerInfrastructure(e,t){let r=this.mergedConfig.infrastructure?.containers;if(!r)return;let n=this.mergedConfig.infrastructure?.loadBalancer,o=this.mergedConfig.infrastructure?.ssl,l=this.mergedConfig.infrastructure?.dns,c;if(o?.enabled&&o.domains?.length)if(o.certificateArn);else{let u=o.domains[0],S=o.domains.slice(1).map((y)=>{if(y.includes(".")&&y.endsWith(u))return y.replace(`.${u}`,"");return y}),{certificate:A,logicalId:b}=ee.createCertificate({domain:u,subdomains:S,slug:e,environment:t,validationMethod:"DNS",hostedZoneId:l?.hostedZoneId});c=b,this.builder.addResource(b,A)}let s="ECSCluster";this.builder.addResource(s,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${e}-${t}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${e}-${t}`},{Key:"Environment",Value:t}]}});let d=`${e}${t}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(d,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${e}-${t}`,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:`${e}-${t}-alb-sg`},{Key:"Environment",Value:t}]}});let g=`${e}${t}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[u,S]of Object.entries(r)){let A=S.port||3000;this.builder.addResource(g,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${e}-${t}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:A,ToPort:A,SourceSecurityGroupId:{Ref:d},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${e}-${t}-ecs-sg`},{Key:"Environment",Value:t}]}});let b=`${e}${t}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(b,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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 y=`${e}${t}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(y,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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 f=`${e}${t}${u}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),i=`/ecs/${e}-${t}-${u}`;this.builder.addResource(f,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:i,RetentionInDays:30}});let m=`${e}${t}${u}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),a=String(S.cpu||512),h=String(S.memory||1024);this.builder.addResource(m,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${e}-${t}-${u}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a,Memory:h,ExecutionRoleArn:{"Fn::GetAtt":[b,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[y,"Arn"]},ContainerDefinitions:[{Name:u,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${e}:latest`},Essential:!0,PortMappings:[{ContainerPort:A,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":i,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":u}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${A}${S.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[b,y,f]});let p=`${e}${t}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(n?.enabled!==!1){this.builder.addResource(p,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${e}-${t}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:d}],Tags:[{Key:"Name",Value:`${e}-${t}-alb`},{Key:"Environment",Value:t}]}});let C=`${e}${t}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),R=n?.healthCheck?.path||S.healthCheck||"/health";this.builder.addResource(C,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${e}-${t}-tg`,Port:A,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:R,HealthCheckIntervalSeconds:n?.healthCheck?.interval||30,HealthyThresholdCount:n?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:n?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${e}-${t}-tg`},{Key:"Environment",Value:t}]}});let T=`${e}${t}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(o?.enabled&&o?.redirectHttp)this.builder.addResource(T,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(T,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:C}}]}});if(o?.enabled){let O=o.certificateArn||(c?{Ref:c}:void 0);if(O){let v=`${e}${t}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(v,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:O}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:C}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let I=`${e}${t}${u}Service`.replace(/[^a-zA-Z0-9]/g,""),D=S.desiredCount||1;this.builder.addResource(I,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-${u}`,Cluster:{Ref:s},TaskDefinition:{Ref:m},DesiredCount:D,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:g}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:u,ContainerPort:A,TargetGroupArn:{Ref:C}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[m,T,C]});let P=S.autoScaling;if(P){let O=`${e}${t}${u}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(O,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:P.max||10,MinCapacity:P.min||1,ResourceId:{"Fn::Sub":`service/\${${s}}/${e}-${t}-${u}`},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:I}),P.targetCpuUtilization)this.builder.addResource(`${e}${t}${u}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-${u}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:O},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:P.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(P.targetMemoryUtilization)this.builder.addResource(`${e}${t}${u}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-${u}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:O},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:P.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(l?.domain&&l?.hostedZoneId)this.builder.addResource(`${e}${t}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:l.hostedZoneId,Name:`api.${l.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[p,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[p,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[s,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${e}-${t}-${u}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[p,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let C=`${e}${t}${u}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(C,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-${u}`,Cluster:{Ref:s},TaskDefinition:{Ref:m},DesiredCount:S.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:g}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[m]})}break}}generateServerless(e,t){if(this.mergedConfig.infrastructure?.functions)for(let[r,n]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(n))continue;let{role:o,logicalId:l}=$e.createRole({slug:e,environment:t,roleName:`${e}-${t}-${r}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(l,o);let{lambdaFunction:c,logicalId:s}=w.createLambdaFunction({slug:e,environment:t,functionName:`${e}-${t}-${r}`,handler:n.handler||"index.handler",runtime:n.runtime||"nodejs20.x",code:{zipFile:n.code||"export const handler = async () => ({ statusCode: 200 });"},role:l,timeout:n.timeout,memorySize:n.memorySize});this.builder.addResource(s,c)}if(this.mergedConfig.infrastructure?.api){let{restApi:r,logicalId:n}=Pe.createRestApi({slug:e,environment:t,apiName:`${e}-${t}-api`});this.builder.addResource(n,r)}}generateServer(e,t){if(!this.mergedConfig.infrastructure?.servers)return;let r=this.mergedConfig.infrastructure.servers,n=this.mergedConfig.infrastructure?.compute,o=this.mergedConfig.infrastructure?.ssl;if(Object.values(r).some((c)=>!c.privateNetwork||c.privateNetwork==="create"))this.generateNetworkInfrastructure(e,t);for(let[c,s]of Object.entries(r)){let d=s.instanceType||s.size||n?.size,u=(d?w.InstanceSize.specs[d]:void 0)?.instanceType||d||"t3.micro",S=s.type||"app",A=s.userData||s.startupScript;if(!A)A=w.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:s.bunVersion||"latest",webServer:"none",domain:s.domain,enableSsl:!!o?.enabled,sslEmail:o?.letsEncrypt?.email,installRedis:S==="cache",installDatabaseClients:!!s.database});let b=s.privateNetwork&&s.privateNetwork!=="create"?s.privateNetwork:{Ref:"VPC"},y=s.subnet||{Ref:"PublicSubnet1"},i=!!this.mergedConfig.infrastructure?.email?.server?.enabled,m=[22,80,443,this.resolveApiOriginPort()];if(i)m.push(25,465,587,143,993);let a=w.createServerModeStack({slug:`${e}-${c}`,environment:t,vpcId:b,subnetId:y,instanceType:u,keyName:s.keyName||`${e}-${t}`,domain:s.domain,userData:A,volumeSize:s.diskSize||20,imageId:s.image,allowedPorts:m});for(let[h,p]of Object.entries(a.resources))this.builder.addResource(h,p);this.serverEipLogicalIds.set(c,a.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${c}Instance`,a.outputs.instanceLogicalId),this.builder.addOutput(`${c}InstanceId`,{Value:{Ref:a.outputs.instanceLogicalId},Description:`Instance ID for ${c} server`}),this.builder.addOutput(`${c}PublicIp`,{Value:{Ref:a.outputs.eipLogicalId},Description:`Public IP for ${c} server`})}}generateComputeApp(e,t){let r=this.mergedConfig.infrastructure?.compute;if(!r)return;let n=this.mergedConfig.sites||{},o=Object.entries(n),c=this.mergedConfig.infrastructure?.dns?.domain,s=this.mergedConfig.infrastructure?.database,d=r.size,u=(d?w.InstanceSize.specs[d]:void 0)?.instanceType||d||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(e,t);let S=this.buildCaddyfile(o),A=w.UserData.generateBunAppScript({runtime:r.runtime||"bun",runtimeVersion:r.runtimeVersion||"latest",systemPackages:r.systemPackages,database:s,caddyfile:S}),b=o.map(([,p])=>p.port).filter((p)=>typeof p==="number"&&![80,443].includes(p)),y=this.resolveApiOriginPort(),f=`${e}${t}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),i=`${e}-${t}-deploy`;this.builder.addResource(f,{Type:"AWS::S3::Bucket",Properties:{BucketName:i,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:e},{Key:"Environment",Value:t},{Key:"ManagedBy",Value:"ts-cloud"}]}});let m=w.createServerModeStack({slug:`${e}-app`,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:u,keyName:r.allowSsh?`${e}-${t}`:void 0,domain:c,userData:A,volumeSize:r.disk?.size||20,imageId:r.image,allowedPorts:[...r.allowSsh?[22]:[],80,443,y,...b]}),a=m.resources[m.outputs.instanceLogicalId];if(a?.Properties){let p=a.Properties.Tags||[];a.Properties.Tags=[...p,{Key:"Project",Value:e},{Key:"Environment",Value:t},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let h=m.resources[m.outputs.roleLogicalId];if(h?.Properties)h.Properties.Policies=h.Properties.Policies||[],h.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${i}`,`arn:aws:s3:::${i}/*`]}]}});for(let[p,C]of Object.entries(m.resources))this.builder.addResource(p,C);this.builder.addOutput("deployBucketName",{Value:{Ref:f},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:m.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:m.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",m.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",m.outputs.instanceLogicalId)}generateJumpBox(e,t){let r=this.mergedConfig.infrastructure?.jumpBox;if(!r)return;let n=r===!0?{}:r;if(n.enabled===!1)return;this.generateNetworkInfrastructure(e,t);let o=n.size||"micro",c=w.InstanceSize.specs[o]?.instanceType||o||"t3.micro",s;if(n.mountEfs)s={fileSystemId:typeof n.mountEfs==="string"?n.mountEfs:{Ref:"FileSystem"},mountPath:n.mountPath||"/mnt/efs"};let d;if(n.databaseTools)d=w.JumpBox.withDatabaseTools({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,allowedCidrs:n.allowedCidrs});else if(s)d=w.JumpBox.withEfsMount({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,fileSystemId:s.fileSystemId,mountPath:s.mountPath,allowedCidrs:n.allowedCidrs});else d=w.createJumpBox({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,instanceType:c,allowedCidrs:n.allowedCidrs,mountEfs:s});for(let[g,u]of Object.entries(d.resources))this.builder.addResource(g,u);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:d.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(e,t){let r=this.mergedConfig.infrastructure?.ssl,n=this.mergedConfig.infrastructure?.dns,o=n?.domain,l=n?.hostedZoneId,c=[],s,d;if(r?.certificateArn)d=r.certificateArn;else if(r?.enabled&&o&&l){let f=r.domains||[o],i=f[0],m=f.slice(1).map((p)=>{if(p.includes(".")&&p.endsWith(i))return p.replace(`.${i}`,"");return p}),{certificate:a,logicalId:h}=ee.createCertificate({domain:i,subdomains:m,slug:e,environment:t,validationMethod:"DNS",hostedZoneId:l});s=h,this.builder.addResource(h,a)}if(this.mergedConfig.infrastructure?.storage){let f=Object.entries(this.mergedConfig.infrastructure.storage).some(([,a])=>a.website),i;if(f&&(s||d))i=`${e}${t}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(i,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${e}-${t}-s3-oac`,Description:`OAC for ${e} ${t} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let m=Object.entries(this.mergedConfig.infrastructure.storage).map(([a,h])=>({name:a,config:h,mountPath:this.normalizeMountPath(h),rewriteStyle:h.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(e,t,a)})).filter((a)=>a.name!=="public"&&a.config.website&&a.mountPath);for(let[a,h]of Object.entries(this.mergedConfig.infrastructure.storage)){let p=!!(h.website&&i),C=this.storageBucketName(e,t,a),{bucket:R,logicalId:T}=X.createBucket({slug:e,name:a,environment:t,bucketName:C,versioning:h.versioning,encryption:h.encryption,public:p?!1:h.public});if(p&&R.Properties)R.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(T,R),h.website){let D=typeof h.website==="object"?h.website:{},P=X.enableWebsiteHosting(R,D.indexDocument||"index.html",D.errorDocument);this.builder.addResource(T,P)}let I=this.normalizeMountPath(h);if(p&&i&&o&&!(I&&a!=="public")){let D=`${e}${t}${a}CDN`.replace(/[^a-zA-Z0-9]/g,""),P=[];if(h.aliases&&h.aliases.length>0)P.push(...h.aliases);else if(a==="public"){if(P.push(o),r?.domains?.includes(`www.${o}`))P.push(`www.${o}`)}else if(a==="docs")P.push(`docs.${o}`);else if(a==="blog")P.push(`blog.${o}`);let O=typeof h.website==="object"?h.website:{},v=h.spa===!0,F=O.errorDocument||(v?"index.html":"404.html"),V=[];if(v)V.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else V.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${F}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${F}`,ErrorCachingMinTTL:300});let z=d&&P.length>0?{AcmCertificateArn:d,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:s&&P.length>0?{AcmCertificateArn:{Ref:s},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},_=`S3-${e}-${t}-${a}`,N=this.mergedConfig.project.region||"us-east-1",x;if(!v)x=`${e}${t}${a}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(x,{Type:"AWS::CloudFront::Function",Properties:{Name:`${e}-${t}-${a}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${e} ${t} ${a} - 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'; }
11
- else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`}});let J=[{Id:_,DomainName:{"Fn::Sub":`\${${T}}.s3.${N}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:i}}],H=[],Y=[];if(this.shouldRouteStorageBucketToCompute(a,h)){this.appendComputeAppOrigin(J,H,Y,e,t,this.resolveComputeCachePathPatterns(h.computeRoutes));for(let E of m){let G=`S3-${e}-${t}-${E.name}`,Q=`${e}${t}${E.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Q,{Type:"AWS::CloudFront::Function",Properties:{Name:`${e}-${t}-${E.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${e} ${t} ${E.name} at ${E.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(E.mountPath,E.rewriteStyle)}}),J.push({Id:G,DomainName:{"Fn::Sub":`\${${E.logicalId}}.s3.${N}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:i}}),Y.push(E.logicalId,Q);for(let Fe of[E.mountPath,`${E.mountPath}/*`])H.push({PathPattern:Fe,TargetOriginId:G,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":[Q,"FunctionARN"]}}]})}}let me={Type:"AWS::CloudFront::Distribution",DependsOn:[T,i,...x?[x]:[],...Y],Properties:{DistributionConfig:{Enabled:!0,Comment:`${e} ${t} ${a} site`,DefaultRootObject:"index.html",Origins:J,DefaultCacheBehavior:{TargetOriginId:_,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...x?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[x,"FunctionARN"]}}]}:{}},...H.length>0?{CacheBehaviors:H}:{},...P.length>0?{Aliases:P}:{},ViewerCertificate:z,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:V}}};if(s)me.DependsOn.push(s);this.builder.addResource(D,me);let Me=`${T}CloudFrontPolicy`;if(this.builder.addResource(Me,{Type:"AWS::S3::BucketPolicy",DependsOn:[T,D],Properties:{Bucket:{Ref:T},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${T}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${D}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(a,h))for(let E of m){let G=`${E.logicalId}CloudFrontPolicy`;this.builder.addResource(G,{Type:"AWS::S3::BucketPolicy",DependsOn:[E.logicalId,D],Properties:{Bucket:{Ref:E.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:::\${${E.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${D}}`}}}}]}}})}if(P.length>0)c.push({name:a,bucketLogicalId:T,distLogicalId:D,oacLogicalId:i,aliases:P});this.builder.addOutput(`${a}CloudFrontDomain`,{Value:{"Fn::GetAtt":[D,"DomainName"]},Description:`CloudFront domain for ${a}`}),this.builder.addOutput(`${a}CloudFrontDistributionId`,{Value:{Ref:D},Description:`CloudFront distribution ID for ${a}`})}if(this.builder.addOutput(`${a}BucketName`,{Value:{Ref:T},Description:`S3 bucket name for ${a}`}),a==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:T},Description:"Frontend S3 bucket name"});if(a==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:T},Description:"Documentation S3 bucket name"});if(a==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:T},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let f=this.mergedConfig.infrastructure.sftp,i=Te.create({...f,storage:this.resolveSftpStorage(f,e,t)??f.storage,slug:e,environment:t});for(let[m,a]of Object.entries(i.resources))this.builder.addResource(m,a);this.builder.addOutput("SftpServerId",{Value:{Ref:i.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${i.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:i.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(l&&c.length>0)for(let{name:f,distLogicalId:i,aliases:m}of c)for(let a of m){let h=a.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${h}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[i],Properties:{HostedZoneId:l,Name:a,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[i,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${h}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[i],Properties:{HostedZoneId:l,Name:a,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[i,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[f,i]of Object.entries(this.mergedConfig.infrastructure.databases))if(i.engine==="dynamodb"){let{table:m,logicalId:a}=U.createTable({slug:e,environment:t,tableName:`${e}-${t}-${f}`,partitionKey:i.partitionKey||{name:"id",type:"S"},sortKey:i.sortKey});this.builder.addResource(a,m)}else if(i.engine==="postgres"){let{dbInstance:m,logicalId:a}=U.createPostgres({slug:e,environment:t,dbInstanceIdentifier:`${e}-${t}-${f}`,masterUsername:i.username||"admin",masterUserPassword:i.password||"changeme123",allocatedStorage:i.storage||20,dbInstanceClass:i.instanceClass||"db.t3.micro"});this.builder.addResource(a,m)}else if(i.engine==="mysql"){let{dbInstance:m,logicalId:a}=U.createMysql({slug:e,environment:t,dbInstanceIdentifier:`${e}-${t}-${f}`,masterUsername:i.username||"admin",masterUserPassword:i.password||"changeme123",allocatedStorage:i.storage||20,dbInstanceClass:i.instanceClass||"db.t3.micro"});this.builder.addResource(a,m)}}if(this.mergedConfig.infrastructure?.cdn)for(let[f,i]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!i.origin)continue;let m=typeof i.customDomain==="string"?i.customDomain:i.customDomain?.domain||i.domain,a=typeof i.customDomain==="object"?i.customDomain?.certificateArn:i.certificateArn,h=a||d,p=`${e}${t}${f}CDN`.replace(/[^a-zA-Z0-9]/g,""),C=`S3-${e}-${t}-${f}-cdn`,R=[{Id:C,DomainName:i.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:i.originShield?{Enabled:!0,OriginShieldRegion:i.originShieldRegion||this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1}}],T=[],I=[];if(i.routeCompute)this.appendComputeAppOrigin(R,T,I,e,t,this.resolveComputeCachePathPatterns(i.computeRoutes));let D=h&&m?{AcmCertificateArn:s&&!a?{Ref:s}:h,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},P=[...I];if(s&&!a&&m)P.push(s);let O={Type:"AWS::CloudFront::Distribution",...P.length>0?{DependsOn:P}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${e} ${t} ${f} CDN`,DefaultRootObject:"index.html",Origins:R,DefaultCacheBehavior:{TargetOriginId:C,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:i.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...T.length>0?{CacheBehaviors:T}:{},...m&&h?{Aliases:[m]}:{},ViewerCertificate:D,PriceClass:"PriceClass_100",HttpVersion:i.http3?"http2and3":"http2"}}};if(this.builder.addResource(p,O),l&&m&&h){let v=m.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${v}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[p,...s&&!a?[s]:[]],Properties:{HostedZoneId:l,Name:m,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[p,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[f,i]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(i))continue;let{queue:m,logicalId:a}=te.createQueue({slug:e,environment:t,name:`${e}-${t}-${f}`,fifo:i.fifo,visibilityTimeout:i.visibilityTimeout,messageRetentionPeriod:i.messageRetentionPeriod,delaySeconds:i.delaySeconds,maxMessageSize:i.maxMessageSize,receiveMessageWaitTime:i.receiveMessageWaitTime,contentBasedDeduplication:i.contentBasedDeduplication,encrypted:i.encrypted,kmsKeyId:i.kmsKeyId});this.builder.addResource(a,m);let h;if(i.deadLetterQueue){let{deadLetterQueue:p,updatedSourceQueue:C,deadLetterLogicalId:R}=te.createDeadLetterQueue(a,{slug:e,environment:t,maxReceiveCount:i.maxReceiveCount});h=R,this.builder.addResource(R,p);let I=this.builder.getResources()[a];if(I?.Properties)I.Properties.RedrivePolicy=C.Properties?.RedrivePolicy}if(i.trigger){let p=i.trigger,C=`${e}${t}${p.functionName}`.replace(/[^a-zA-Z0-9]/g,""),R={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[a,"Arn"]},FunctionName:{Ref:C},BatchSize:p.batchSize||10,MaximumBatchingWindowInSeconds:p.batchWindow||0,Enabled:!0,...p.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...p.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:p.maxConcurrency}},...p.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(p.filterPattern)}]}}},DependsOn:[a,C]};this.builder.addResource(`${a}Trigger`,R)}if(i.alarms?.enabled){let p=i.alarms,C=p.notificationTopicArn;if(!C&&p.notificationEmails?.length){let I=`${a}AlarmTopic`;this.builder.addResource(I,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-${f}-alarms`,DisplayName:`${f} Queue Alarms`}}),p.notificationEmails.forEach((D,P)=>{this.builder.addResource(`${I}Sub${P}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:I},Protocol:"email",Endpoint:D}})}),C={Ref:I}}let R=p.queueDepthThreshold||1000;this.builder.addResource(`${a}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${f}-queue-depth`,AlarmDescription:`Queue ${f} depth exceeds ${R} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:R,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[a,"QueueName"]}}],...C&&{AlarmActions:[C],OKActions:[C]}}});let T=p.messageAgeThreshold||3600;if(this.builder.addResource(`${a}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${f}-message-age`,AlarmDescription:`Queue ${f} oldest message exceeds ${T} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:T,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[a,"QueueName"]}}],...C&&{AlarmActions:[C],OKActions:[C]}}}),h&&p.dlqAlarm!==!1)this.builder.addResource(`${h}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${f}-dlq-messages`,AlarmDescription:`Dead letter queue for ${f} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[h,"QueueName"]}}],...C&&{AlarmActions:[C]}}})}if(i.subscribe){let p=i.subscribe,C=p.topicArn;if(!C&&p.topicName)C={Ref:p.topicName};if(C){this.builder.addResource(`${a}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:a}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[a,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":C}}}]}}});let R={TopicArn:C,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[a,"Arn"]},RawMessageDelivery:p.rawMessageDelivery||!1};if(p.filterPolicy)R.FilterPolicy=p.filterPolicy,R.FilterPolicyScope=p.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${a}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:R,DependsOn:`${a}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(e,t);else this.generateRealtimeResources(e,t);let g=this.mergedConfig.infrastructure?.redirects;if(g){let f=g.target||this.mergedConfig.infrastructure?.dns?.domain||"",i=g.protocol||"https";if(g.domains?.length&&f)for(let m of g.domains){let{bucket:a,bucketPolicy:h,logicalId:p,policyLogicalId:C}=Z.createDomainRedirectBucket({slug:e,environment:t,sourceDomain:m,targetDomain:f,protocol:i});this.builder.addResource(p,a),this.builder.addResource(C,h)}if(g.paths&&Object.keys(g.paths).length>0){let m=Z.fromMapping(g.paths,{statusCode:g.statusCode||301}),{function:a,logicalId:h}=Z.createPathRedirectFunction({slug:e,environment:t,rules:m});this.builder.addResource(h,a)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[f,i]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:m,logicalId:a}=Ie.createAlarm({slug:e,environment:t,alarmName:`${e}-${t}-${f}`,metricName:i.metricName||"Errors",namespace:i.namespace||"AWS/Lambda",threshold:i.threshold||1,comparisonOperator:i.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(a,m)}let u=this.mergedConfig.infrastructure?.cache;if(u){let f=u.type||"redis";if(f==="redis"){this.generateNetworkInfrastructure(e,t);let i=u.redis||{},{replicationGroup:m,subnetGroup:a,logicalId:h,subnetGroupId:p}=re.createRedis({slug:e,environment:t,nodeType:i.nodeType||u.nodeType||"cache.t3.micro",engineVersion:i.engineVersion||"7.1",port:i.port||6379,numCacheClusters:i.numCacheNodes||2,automaticFailover:i.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:i.snapshotRetentionLimit||7,snapshotWindow:i.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(h,m),a&&p)this.builder.addResource(p,a);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[h,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[h,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(f==="memcached"){this.generateNetworkInfrastructure(e,t);let i=u.elasticache||{},{cluster:m,subnetGroup:a,logicalId:h,subnetGroupId:p}=re.createMemcached({slug:e,environment:t,nodeType:i.nodeType||u.nodeType||"cache.t3.micro",engineVersion:i.engineVersion||"1.6.22",numCacheNodes:i.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(h,m),a&&p)this.builder.addResource(p,a);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[h,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let S=this.mergedConfig.infrastructure?.email;if(S){let f=S.domain||this.mergedConfig.infrastructure?.dns?.domain;if(f){let{emailIdentity:i,logicalId:m}=L.verifyDomain({domain:f,slug:e,environment:t,enableDkim:S.enableDkim!==!1,dkimKeyLength:S.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(m,i),S.configurationSet!==!1){let{configurationSet:p,logicalId:C}=L.createConfigurationSet({slug:e,environment:t});this.builder.addResource(C,p)}let a=S.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(a){if(S.enableDkim!==!1)for(let I=1;I<=3;I++){let D=`DkimRecord${I}${f.replace(/\./g,"")}`;this.builder.addResource(D,{Type:"AWS::Route53::RecordSet",DependsOn:[m],Properties:{HostedZoneId:a,Name:{"Fn::GetAtt":[m,`DkimDNSTokenName${I}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[m,`DkimDNSTokenValue${I}`]}]}})}let{record:p,logicalId:C}=L.createSpfRecord(f,a);this.builder.addResource(C,p);let{record:R,logicalId:T}=L.createDmarcRecord(f,a,{policy:"none",reportingEmail:S.dmarcReportingEmail||`dmarc-reports@${f}`});this.builder.addResource(T,R)}this.builder.addOutput("EmailDomain",{Value:f,Description:"SES verified email domain"});let h=S.server;if(h?.enabled&&a){let p=this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1",C=`${e}-${t}-email`,{role:R,policy:T,roleLogicalId:I,policyLogicalId:D}=L.createEmailLambdaRole({slug:e,environment:t,s3BucketArn:`arn:aws:s3:::${C}`,sesIdentityArn:`arn:aws:ses:${p}:*:identity/${f}`});this.builder.addResource(I,R),this.builder.addResource(D,T);let{function:P,permission:O,logicalId:v,permissionLogicalId:F}=L.createInboundEmailLambda({slug:e,environment:t,roleArn:{"Fn::GetAtt":[I,"Arn"]},s3BucketName:C,organizedPrefix:"mailboxes/"});this.builder.addResource(v,P),this.builder.addResource(F,O);let V=L.createInboundEmailSetup({slug:e,environment:t,domain:f,s3BucketName:C,s3KeyPrefix:"inbox/",region:p,hostedZoneId:a,lambdaFunctionArn:{"Fn::GetAtt":[v,"Arn"]}});for(let[_,N]of Object.entries(V.resources)){if(N.Type==="AWS::SES::ReceiptRule")N.DependsOn=[F,v];this.builder.addResource(_,N)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:v},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:C,Description:"S3 bucket for email storage"});let z=this.serverEipLogicalIds.get("app");if(z&&a){let N=`${h?.subdomain||"mail"}.${f}`,x=N.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${x}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:N,Type:"A",TTL:"300",ResourceRecords:[{Ref:z}]}})}this.builder.addOutput("MailHost",{Value:`mail.${f}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let A=this.mergedConfig.infrastructure?.search;if(A){let f=A.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(f)this.generateNetworkInfrastructure(e,t);let{domain:i,logicalId:m}=De.createDomain({slug:e,environment:t,engineVersion:A.engineVersion||"OpenSearch_2.11",instanceType:A.instanceType||"t3.small.search",instanceCount:A.instanceCount||1,volumeSize:A.volumeSize||10,volumeType:A.volumeType||"gp3",dedicatedMaster:A.dedicatedMaster||!1,dedicatedMasterType:A.dedicatedMasterType,dedicatedMasterCount:A.dedicatedMasterCount||3,multiAz:A.multiAz||!1,encryption:A.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:A.advancedSecurity,autoTune:A.autoTune!==!1,vpc:f});this.builder.addResource(m,i),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[m,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[m,"Arn"]},Description:"OpenSearch domain ARN"})}let b=this.mergedConfig.infrastructure?.fileSystem;if(b&&Object.keys(b).length>0){this.generateNetworkInfrastructure(e,t);for(let[f,i]of Object.entries(b)){let{fileSystem:m,logicalId:a}=K.createFileSystem({slug:`${e}-${f}`,environment:t,encrypted:i.encrypted!==!1,performanceMode:i.performanceMode||"generalPurpose",throughputMode:i.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(a,m);let{securityGroup:h,logicalId:p}=K.createEfsSecurityGroup({slug:`${e}-${f}`,environment:t,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(p,h);let{mountTargets:C,logicalIds:R}=K.createMultiAzMountTargets(a,{slug:`${e}-${f}`,environment:t,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:p}});for(let T=0;T<C.length;T++)this.builder.addResource(R[T],C[T]);this.builder.addOutput(`${f}FileSystemId`,{Value:{Ref:a},Description:`EFS file system ID for ${f}`})}}let y=this.mergedConfig.infrastructure?.ai;if(y){let f=y.service||"ecs",i=y.models||["*"],m=y.allowStreaming!==!1,a;if(f==="ecs")a=M.enableBedrockForEcs({slug:e,environment:t,models:i,allowStreaming:m});else if(f==="ec2")a=M.enableBedrockForEc2({slug:e,environment:t,models:i,allowStreaming:m});else if(f==="lambda")a=M.enableBedrockForLambda({slug:e,environment:t,models:i,allowStreaming:m});else a=M.createBedrockRole(f,{slug:e,environment:t,models:i,allowStreaming:m});if(this.builder.addResource(a.logicalId,a.role),y.allowAsync){let{policy:h,logicalId:p}=M.createBedrockPolicy({slug:e,environment:t,models:i,allowStreaming:m,allowAsync:!0});this.builder.addResource(p,h)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[a.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(e,t){let r=this.mergedConfig.infrastructure?.realtime;if(!r)return;let n=r.name||`${e}-${t}-realtime`,o=r.scaling||{},l=r.storage||{type:"dynamodb"},c=o.handlerMemory||256,s=o.handlerTimeout||30,d=`${e}${t}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),g=`${e}${t}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(l.type==="dynamodb"){let R=l.dynamodb||{},T=R.billingMode||"PAY_PER_REQUEST";this.builder.addResource(d,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e}-${t}-realtime-connections`,BillingMode:T,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"},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:R.readCapacity||5,WriteCapacityUnits:R.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:R.readCapacity||5,WriteCapacityUnits:R.writeCapacity||5}},...R.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${e}-${t}-realtime-connections`},{Key:"Environment",Value:t}]}}),this.builder.addResource(g,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e}-${t}-realtime-channels`,BillingMode:T,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"},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:R.readCapacity||5,WriteCapacityUnits:R.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:R.readCapacity||5,WriteCapacityUnits:R.writeCapacity||5}},Tags:[{Key:"Name",Value:`${e}-${t}-realtime-channels`},{Key:"Environment",Value:t}]}})}let u=`${e}${t}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(u,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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":[d,"Arn"]},{"Fn::Sub":`\${${d}.Arn}/index/*`},{"Fn::GetAtt":[g,"Arn"]},{"Fn::Sub":`\${${g}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let S=`${e}${t}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),A=`${e}${t}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),b=`${e}${t}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(S,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:g},ENVIRONMENT:t}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[u,d]}),this.builder.addResource(A,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:g},ENVIRONMENT:t}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[u,d,g]}),this.builder.addResource(b,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:g},ENVIRONMENT:t}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[u,d,g]});let y=`${e}${t}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(y,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:n,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:n,Environment:t}}});let f=`${S}Permission`,i=`${A}Permission`,m=`${b}Permission`;this.builder.addResource(f,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:S},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$connect`}}}),this.builder.addResource(i,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:A},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$disconnect`}}}),this.builder.addResource(m,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:b},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$default`}}});let a=`${y}ConnectInteg`,h=`${y}DisconnectInteg`,p=`${y}MessageInteg`;this.builder.addResource(a,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${S}.Arn}/invocations`}}}),this.builder.addResource(h,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${A}.Arn}/invocations`}}}),this.builder.addResource(p,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${b}.Arn}/invocations`}}}),this.builder.addResource(`${y}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${a}}`}}}),this.builder.addResource(`${y}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${h}}`}}}),this.builder.addResource(`${y}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${p}}`}}});let C=`${y}Stage`;if(this.builder.addResource(C,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:y},StageName:t,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:o.messagesPerSecond||1000,ThrottlingRateLimit:o.messagesPerSecond||1000}}}),r.monitoring?.enabled){let R=r.monitoring,T=R.notificationTopicArn;if(!T&&R.notificationEmails?.length){let I=`${y}AlarmTopic`;this.builder.addResource(I,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),R.notificationEmails.forEach((D,P)=>{this.builder.addResource(`${I}Sub${P}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:I},Protocol:"email",Endpoint:D}})}),T={Ref:I}}if(R.connectionThreshold)this.builder.addResource(`${y}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${R.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:R.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:y}}],...T&&{AlarmActions:[T]}}});if(R.errorThreshold)this.builder.addResource(`${y}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${R.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:R.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:y}}],...T&&{AlarmActions:[T]}}})}this.builder.addOutput(`${y}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${y}}.execute-api.\${AWS::Region}.amazonaws.com/${t}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${y}Id`,{Description:"WebSocket API ID",Value:{Ref:y},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
10
+ `)}normalizeMountPath(e){let t=e?.mountPath||e?.path;if(!t||t==="/")return;let r=`/${t}`.replace(/\/+/g,"/").replace(/\/$/,"");return r==="/"?void 0:r}storageBucketLogicalId(e,t,r){return`${e}-${t}-s3-${r}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}pathMountRewriteFunctionCode(e,t="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(e)}; var rewriteStyle = ${JSON.stringify(t)}; 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 e=this.mergedConfig.project.slug,t=this.environment,r=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),n=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),i=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(e,t),this.generateContainerInfrastructure(e,t);if(r)this.generateServerless(e,t);if(n)this.generateServer(e,t);if(i)this.generateComputeApp(e,t);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(e,t);if(this.generateSharedInfrastructure(e,t),this.config.tags)this.applyGlobalTags(this.config.tags);return this}applyGlobalTags(e){}generateNetworkInfrastructure(e,t){if(this.builder.hasResource("VPC"))return;let n=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:i,logicalId:l}=Re.createVpc({slug:e,environment:t,cidr:n,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",i);let c=`${e}${t}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(c,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${e}-${t}-igw`},{Key:"Environment",Value:t}]}});let s=`${e}${t}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(s,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:c}}});let d=`${e}${t}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(d,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${e}-${t}-public-rt`},{Key:"Environment",Value:t}]}}),this.builder.addResource(`${e}${t}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:d},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:c}},DependsOn:s});let h=this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1",u=["a","b"];for(let b=0;b<2;b++){let A=`PublicSubnet${b+1}`;this.builder.addResource(A,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${b}.0/24`,AvailabilityZone:`${h}${u[b]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${e}-${t}-public-${u[b]}`},{Key:"Environment",Value:t}]}}),this.builder.addResource(`${A}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:A},RouteTableId:{Ref:d}}})}}generateContainerInfrastructure(e,t){let r=this.mergedConfig.infrastructure?.containers;if(!r)return;let n=this.mergedConfig.infrastructure?.loadBalancer,i=this.mergedConfig.infrastructure?.ssl,l=this.mergedConfig.infrastructure?.dns,c;if(i?.enabled&&i.domains?.length)if(i.certificateArn);else{let u=i.domains[0],b=i.domains.slice(1).map((y)=>{if(y.includes(".")&&y.endsWith(u))return y.replace(`.${u}`,"");return y}),{certificate:A,logicalId:R}=ee.createCertificate({domain:u,subdomains:b,slug:e,environment:t,validationMethod:"DNS",hostedZoneId:l?.hostedZoneId});c=R,this.builder.addResource(R,A)}let s="ECSCluster";this.builder.addResource(s,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${e}-${t}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${e}-${t}`},{Key:"Environment",Value:t}]}});let d=`${e}${t}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(d,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${e}-${t}`,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:`${e}-${t}-alb-sg`},{Key:"Environment",Value:t}]}});let h=`${e}${t}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[u,b]of Object.entries(r)){let A=b.port||3000;this.builder.addResource(h,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${e}-${t}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:A,ToPort:A,SourceSecurityGroupId:{Ref:d},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${e}-${t}-ecs-sg`},{Key:"Environment",Value:t}]}});let R=`${e}${t}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(R,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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 y=`${e}${t}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(y,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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 m=`${e}${t}${u}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),o=`/ecs/${e}-${t}-${u}`;this.builder.addResource(m,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:o,RetentionInDays:30}});let g=`${e}${t}${u}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),a=String(b.cpu||512),f=String(b.memory||1024);this.builder.addResource(g,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${e}-${t}-${u}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a,Memory:f,ExecutionRoleArn:{"Fn::GetAtt":[R,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[y,"Arn"]},ContainerDefinitions:[{Name:u,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${e}:latest`},Essential:!0,PortMappings:[{ContainerPort:A,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":o,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":u}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${A}${b.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[R,y,m]});let p=`${e}${t}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(n?.enabled!==!1){this.builder.addResource(p,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${e}-${t}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:d}],Tags:[{Key:"Name",Value:`${e}-${t}-alb`},{Key:"Environment",Value:t}]}});let C=`${e}${t}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),S=n?.healthCheck?.path||b.healthCheck||"/health";this.builder.addResource(C,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${e}-${t}-tg`,Port:A,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:S,HealthCheckIntervalSeconds:n?.healthCheck?.interval||30,HealthyThresholdCount:n?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:n?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${e}-${t}-tg`},{Key:"Environment",Value:t}]}});let T=`${e}${t}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(i?.enabled&&i?.redirectHttp)this.builder.addResource(T,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(T,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:C}}]}});if(i?.enabled){let O=i.certificateArn||(c?{Ref:c}:void 0);if(O){let v=`${e}${t}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(v,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:O}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:C}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let I=`${e}${t}${u}Service`.replace(/[^a-zA-Z0-9]/g,""),D=b.desiredCount||1;this.builder.addResource(I,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-${u}`,Cluster:{Ref:s},TaskDefinition:{Ref:g},DesiredCount:D,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:h}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:u,ContainerPort:A,TargetGroupArn:{Ref:C}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[g,T,C]});let P=b.autoScaling;if(P){let O=`${e}${t}${u}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(O,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:P.max||10,MinCapacity:P.min||1,ResourceId:{"Fn::Sub":`service/\${${s}}/${e}-${t}-${u}`},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:I}),P.targetCpuUtilization)this.builder.addResource(`${e}${t}${u}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-${u}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:O},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:P.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(P.targetMemoryUtilization)this.builder.addResource(`${e}${t}${u}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-${u}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:O},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:P.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(l?.domain&&l?.hostedZoneId)this.builder.addResource(`${e}${t}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:l.hostedZoneId,Name:`api.${l.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[p,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[p,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[s,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${e}-${t}-${u}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[p,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let C=`${e}${t}${u}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(C,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-${u}`,Cluster:{Ref:s},TaskDefinition:{Ref:g},DesiredCount:b.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:h}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[g]})}break}}generateServerless(e,t){if(this.mergedConfig.infrastructure?.functions)for(let[r,n]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(n))continue;let{role:i,logicalId:l}=$e.createRole({slug:e,environment:t,roleName:`${e}-${t}-${r}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(l,i);let{lambdaFunction:c,logicalId:s}=w.createLambdaFunction({slug:e,environment:t,functionName:`${e}-${t}-${r}`,handler:n.handler||"index.handler",runtime:n.runtime||"nodejs20.x",code:{zipFile:n.code||"export const handler = async () => ({ statusCode: 200 });"},role:l,timeout:n.timeout,memorySize:n.memorySize});this.builder.addResource(s,c)}if(this.mergedConfig.infrastructure?.api){let{restApi:r,logicalId:n}=Pe.createRestApi({slug:e,environment:t,apiName:`${e}-${t}-api`});this.builder.addResource(n,r)}}generateServer(e,t){if(!this.mergedConfig.infrastructure?.servers)return;let r=this.mergedConfig.infrastructure.servers,n=this.mergedConfig.infrastructure?.compute,i=this.mergedConfig.infrastructure?.ssl;if(Object.values(r).some((c)=>!c.privateNetwork||c.privateNetwork==="create"))this.generateNetworkInfrastructure(e,t);for(let[c,s]of Object.entries(r)){let d=s.instanceType||s.size||n?.size,u=(d?w.InstanceSize.specs[d]:void 0)?.instanceType||d||"t3.micro",b=s.type||"app",A=s.userData||s.startupScript;if(!A)A=w.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:s.bunVersion||"latest",webServer:"none",domain:s.domain,enableSsl:!!i?.enabled,sslEmail:i?.letsEncrypt?.email,installRedis:b==="cache",installDatabaseClients:!!s.database});let R=s.privateNetwork&&s.privateNetwork!=="create"?s.privateNetwork:{Ref:"VPC"},y=s.subnet||{Ref:"PublicSubnet1"},o=!!this.mergedConfig.infrastructure?.email?.server?.enabled,g=[22,80,443,this.resolveApiOriginPort()];if(o)g.push(25,465,587,143,993);let a=w.createServerModeStack({slug:`${e}-${c}`,environment:t,vpcId:R,subnetId:y,instanceType:u,keyName:s.keyName||`${e}-${t}`,domain:s.domain,userData:A,volumeSize:s.diskSize||20,imageId:s.image,allowedPorts:g});for(let[f,p]of Object.entries(a.resources))this.builder.addResource(f,p);this.serverEipLogicalIds.set(c,a.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${c}Instance`,a.outputs.instanceLogicalId),this.builder.addOutput(`${c}InstanceId`,{Value:{Ref:a.outputs.instanceLogicalId},Description:`Instance ID for ${c} server`}),this.builder.addOutput(`${c}PublicIp`,{Value:{Ref:a.outputs.eipLogicalId},Description:`Public IP for ${c} server`})}}generateComputeApp(e,t){let r=this.mergedConfig.infrastructure?.compute;if(!r)return;let n=this.mergedConfig.sites||{},i=Object.entries(n),c=this.mergedConfig.infrastructure?.dns?.domain,s=this.mergedConfig.infrastructure?.database,d=r.size,u=(d?w.InstanceSize.specs[d]:void 0)?.instanceType||d||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(e,t);let b=this.buildCaddyfile(i),A=w.UserData.generateBunAppScript({runtime:r.runtime||"bun",runtimeVersion:r.runtimeVersion||"latest",systemPackages:r.systemPackages,database:s,caddyfile:b}),R=Ee(r.appUpdates),y=R.length>0?`${A}
11
+ ${R.join(`
12
+ `)}
13
+ `:A,m=i.map(([,S])=>S.port).filter((S)=>typeof S==="number"&&![80,443].includes(S)),o=this.resolveApiOriginPort(),g=`${e}${t}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),a=`${e}-${t}-deploy`;this.builder.addResource(g,{Type:"AWS::S3::Bucket",Properties:{BucketName:a,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:e},{Key:"Environment",Value:t},{Key:"ManagedBy",Value:"ts-cloud"}]}});let f=w.createServerModeStack({slug:`${e}-app`,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:u,keyName:r.allowSsh?`${e}-${t}`:void 0,domain:c,userData:y,volumeSize:r.disk?.size||20,imageId:r.image,allowedPorts:[...r.allowSsh?[22]:[],80,443,o,...m]}),p=f.resources[f.outputs.instanceLogicalId];if(p?.Properties){let S=p.Properties.Tags||[];p.Properties.Tags=[...S,{Key:"Project",Value:e},{Key:"Environment",Value:t},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let C=f.resources[f.outputs.roleLogicalId];if(C?.Properties)C.Properties.Policies=C.Properties.Policies||[],C.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${a}`,`arn:aws:s3:::${a}/*`]}]}});for(let[S,T]of Object.entries(f.resources))this.builder.addResource(S,T);this.builder.addOutput("deployBucketName",{Value:{Ref:g},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:f.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:f.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",f.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",f.outputs.instanceLogicalId)}generateJumpBox(e,t){let r=this.mergedConfig.infrastructure?.jumpBox;if(!r)return;let n=r===!0?{}:r;if(n.enabled===!1)return;this.generateNetworkInfrastructure(e,t);let i=n.size||"micro",c=w.InstanceSize.specs[i]?.instanceType||i||"t3.micro",s;if(n.mountEfs)s={fileSystemId:typeof n.mountEfs==="string"?n.mountEfs:{Ref:"FileSystem"},mountPath:n.mountPath||"/mnt/efs"};let d;if(n.databaseTools)d=w.JumpBox.withDatabaseTools({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,allowedCidrs:n.allowedCidrs});else if(s)d=w.JumpBox.withEfsMount({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,fileSystemId:s.fileSystemId,mountPath:s.mountPath,allowedCidrs:n.allowedCidrs});else d=w.createJumpBox({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,instanceType:c,allowedCidrs:n.allowedCidrs,mountEfs:s});for(let[h,u]of Object.entries(d.resources))this.builder.addResource(h,u);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:d.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(e,t){let r=this.mergedConfig.infrastructure?.ssl,n=this.mergedConfig.infrastructure?.dns,i=n?.domain,l=n?.hostedZoneId,c=[],s,d;if(r?.certificateArn)d=r.certificateArn;else if(r?.enabled&&i&&l){let m=r.domains||[i],o=m[0],g=m.slice(1).map((p)=>{if(p.includes(".")&&p.endsWith(o))return p.replace(`.${o}`,"");return p}),{certificate:a,logicalId:f}=ee.createCertificate({domain:o,subdomains:g,slug:e,environment:t,validationMethod:"DNS",hostedZoneId:l});s=f,this.builder.addResource(f,a)}if(this.mergedConfig.infrastructure?.storage){let m=Object.entries(this.mergedConfig.infrastructure.storage).some(([,a])=>a.website),o;if(m&&(s||d))o=`${e}${t}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(o,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${e}-${t}-s3-oac`,Description:`OAC for ${e} ${t} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let g=Object.entries(this.mergedConfig.infrastructure.storage).map(([a,f])=>({name:a,config:f,mountPath:this.normalizeMountPath(f),rewriteStyle:f.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(e,t,a)})).filter((a)=>a.name!=="public"&&a.config.website&&a.mountPath);for(let[a,f]of Object.entries(this.mergedConfig.infrastructure.storage)){let p=!!(f.website&&o),C=this.storageBucketName(e,t,a),{bucket:S,logicalId:T}=X.createBucket({slug:e,name:a,environment:t,bucketName:C,versioning:f.versioning,encryption:f.encryption,public:p?!1:f.public});if(p&&S.Properties)S.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(T,S),f.website){let D=typeof f.website==="object"?f.website:{},P=X.enableWebsiteHosting(S,D.indexDocument||"index.html",D.errorDocument);this.builder.addResource(T,P)}let I=this.normalizeMountPath(f);if(p&&o&&i&&!(I&&a!=="public")){let D=`${e}${t}${a}CDN`.replace(/[^a-zA-Z0-9]/g,""),P=[];if(f.aliases&&f.aliases.length>0)P.push(...f.aliases);else if(a==="public"){if(P.push(i),r?.domains?.includes(`www.${i}`))P.push(`www.${i}`)}else if(a==="docs")P.push(`docs.${i}`);else if(a==="blog")P.push(`blog.${i}`);let O=typeof f.website==="object"?f.website:{},v=f.spa===!0,F=O.errorDocument||(v?"index.html":"404.html"),V=[];if(v)V.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else V.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${F}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${F}`,ErrorCachingMinTTL:300});let z=d&&P.length>0?{AcmCertificateArn:d,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:s&&P.length>0?{AcmCertificateArn:{Ref:s},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},_=`S3-${e}-${t}-${a}`,N=this.mergedConfig.project.region||"us-east-1",x;if(!v)x=`${e}${t}${a}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(x,{Type:"AWS::CloudFront::Function",Properties:{Name:`${e}-${t}-${a}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${e} ${t} ${a} - 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 J=[{Id:_,DomainName:{"Fn::Sub":`\${${T}}.s3.${N}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:o}}],H=[],Y=[];if(this.shouldRouteStorageBucketToCompute(a,f)){this.appendComputeAppOrigin(J,H,Y,e,t,this.resolveComputeCachePathPatterns(f.computeRoutes));for(let E of g){let G=`S3-${e}-${t}-${E.name}`,Q=`${e}${t}${E.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Q,{Type:"AWS::CloudFront::Function",Properties:{Name:`${e}-${t}-${E.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${e} ${t} ${E.name} at ${E.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(E.mountPath,E.rewriteStyle)}}),J.push({Id:G,DomainName:{"Fn::Sub":`\${${E.logicalId}}.s3.${N}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:o}}),Y.push(E.logicalId,Q);for(let Ve of[E.mountPath,`${E.mountPath}/*`])H.push({PathPattern:Ve,TargetOriginId:G,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":[Q,"FunctionARN"]}}]})}}let me={Type:"AWS::CloudFront::Distribution",DependsOn:[T,o,...x?[x]:[],...Y],Properties:{DistributionConfig:{Enabled:!0,Comment:`${e} ${t} ${a} site`,DefaultRootObject:"index.html",Origins:J,DefaultCacheBehavior:{TargetOriginId:_,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...x?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[x,"FunctionARN"]}}]}:{}},...H.length>0?{CacheBehaviors:H}:{},...P.length>0?{Aliases:P}:{},ViewerCertificate:z,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:V}}};if(s)me.DependsOn.push(s);this.builder.addResource(D,me);let Fe=`${T}CloudFrontPolicy`;if(this.builder.addResource(Fe,{Type:"AWS::S3::BucketPolicy",DependsOn:[T,D],Properties:{Bucket:{Ref:T},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${T}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${D}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(a,f))for(let E of g){let G=`${E.logicalId}CloudFrontPolicy`;this.builder.addResource(G,{Type:"AWS::S3::BucketPolicy",DependsOn:[E.logicalId,D],Properties:{Bucket:{Ref:E.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:::\${${E.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${D}}`}}}}]}}})}if(P.length>0)c.push({name:a,bucketLogicalId:T,distLogicalId:D,oacLogicalId:o,aliases:P});this.builder.addOutput(`${a}CloudFrontDomain`,{Value:{"Fn::GetAtt":[D,"DomainName"]},Description:`CloudFront domain for ${a}`}),this.builder.addOutput(`${a}CloudFrontDistributionId`,{Value:{Ref:D},Description:`CloudFront distribution ID for ${a}`})}if(this.builder.addOutput(`${a}BucketName`,{Value:{Ref:T},Description:`S3 bucket name for ${a}`}),a==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:T},Description:"Frontend S3 bucket name"});if(a==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:T},Description:"Documentation S3 bucket name"});if(a==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:T},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let m=this.mergedConfig.infrastructure.sftp,o=Te.create({...m,storage:this.resolveSftpStorage(m,e,t)??m.storage,slug:e,environment:t});for(let[g,a]of Object.entries(o.resources))this.builder.addResource(g,a);this.builder.addOutput("SftpServerId",{Value:{Ref:o.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${o.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:o.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(l&&c.length>0)for(let{name:m,distLogicalId:o,aliases:g}of c)for(let a of g){let f=a.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${f}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[o],Properties:{HostedZoneId:l,Name:a,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[o,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${f}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[o],Properties:{HostedZoneId:l,Name:a,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[o,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[m,o]of Object.entries(this.mergedConfig.infrastructure.databases))if(o.engine==="dynamodb"){let{table:g,logicalId:a}=U.createTable({slug:e,environment:t,tableName:`${e}-${t}-${m}`,partitionKey:o.partitionKey||{name:"id",type:"S"},sortKey:o.sortKey});this.builder.addResource(a,g)}else if(o.engine==="postgres"){let{dbInstance:g,logicalId:a}=U.createPostgres({slug:e,environment:t,dbInstanceIdentifier:`${e}-${t}-${m}`,masterUsername:o.username||"admin",masterUserPassword:o.password||"changeme123",allocatedStorage:o.storage||20,dbInstanceClass:o.instanceClass||"db.t3.micro"});this.builder.addResource(a,g)}else if(o.engine==="mysql"){let{dbInstance:g,logicalId:a}=U.createMysql({slug:e,environment:t,dbInstanceIdentifier:`${e}-${t}-${m}`,masterUsername:o.username||"admin",masterUserPassword:o.password||"changeme123",allocatedStorage:o.storage||20,dbInstanceClass:o.instanceClass||"db.t3.micro"});this.builder.addResource(a,g)}}if(this.mergedConfig.infrastructure?.cdn)for(let[m,o]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!o.origin)continue;let g=typeof o.customDomain==="string"?o.customDomain:o.customDomain?.domain||o.domain,a=typeof o.customDomain==="object"?o.customDomain?.certificateArn:o.certificateArn,f=a||d,p=`${e}${t}${m}CDN`.replace(/[^a-zA-Z0-9]/g,""),C=`S3-${e}-${t}-${m}-cdn`,S=[{Id:C,DomainName:o.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:o.originShield?{Enabled:!0,OriginShieldRegion:o.originShieldRegion||this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1}}],T=[],I=[];if(o.routeCompute)this.appendComputeAppOrigin(S,T,I,e,t,this.resolveComputeCachePathPatterns(o.computeRoutes));let D=f&&g?{AcmCertificateArn:s&&!a?{Ref:s}:f,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},P=[...I];if(s&&!a&&g)P.push(s);let O={Type:"AWS::CloudFront::Distribution",...P.length>0?{DependsOn:P}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${e} ${t} ${m} CDN`,DefaultRootObject:"index.html",Origins:S,DefaultCacheBehavior:{TargetOriginId:C,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:o.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...T.length>0?{CacheBehaviors:T}:{},...g&&f?{Aliases:[g]}:{},ViewerCertificate:D,PriceClass:"PriceClass_100",HttpVersion:o.http3?"http2and3":"http2"}}};if(this.builder.addResource(p,O),l&&g&&f){let v=g.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${v}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[p,...s&&!a?[s]:[]],Properties:{HostedZoneId:l,Name:g,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[p,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[m,o]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(o))continue;let{queue:g,logicalId:a}=te.createQueue({slug:e,environment:t,name:`${e}-${t}-${m}`,fifo:o.fifo,visibilityTimeout:o.visibilityTimeout,messageRetentionPeriod:o.messageRetentionPeriod,delaySeconds:o.delaySeconds,maxMessageSize:o.maxMessageSize,receiveMessageWaitTime:o.receiveMessageWaitTime,contentBasedDeduplication:o.contentBasedDeduplication,encrypted:o.encrypted,kmsKeyId:o.kmsKeyId});this.builder.addResource(a,g);let f;if(o.deadLetterQueue){let{deadLetterQueue:p,updatedSourceQueue:C,deadLetterLogicalId:S}=te.createDeadLetterQueue(a,{slug:e,environment:t,maxReceiveCount:o.maxReceiveCount});f=S,this.builder.addResource(S,p);let I=this.builder.getResources()[a];if(I?.Properties)I.Properties.RedrivePolicy=C.Properties?.RedrivePolicy}if(o.trigger){let p=o.trigger,C=`${e}${t}${p.functionName}`.replace(/[^a-zA-Z0-9]/g,""),S={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[a,"Arn"]},FunctionName:{Ref:C},BatchSize:p.batchSize||10,MaximumBatchingWindowInSeconds:p.batchWindow||0,Enabled:!0,...p.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...p.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:p.maxConcurrency}},...p.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(p.filterPattern)}]}}},DependsOn:[a,C]};this.builder.addResource(`${a}Trigger`,S)}if(o.alarms?.enabled){let p=o.alarms,C=p.notificationTopicArn;if(!C&&p.notificationEmails?.length){let I=`${a}AlarmTopic`;this.builder.addResource(I,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-${m}-alarms`,DisplayName:`${m} Queue Alarms`}}),p.notificationEmails.forEach((D,P)=>{this.builder.addResource(`${I}Sub${P}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:I},Protocol:"email",Endpoint:D}})}),C={Ref:I}}let S=p.queueDepthThreshold||1000;this.builder.addResource(`${a}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${m}-queue-depth`,AlarmDescription:`Queue ${m} depth exceeds ${S} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:S,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[a,"QueueName"]}}],...C&&{AlarmActions:[C],OKActions:[C]}}});let T=p.messageAgeThreshold||3600;if(this.builder.addResource(`${a}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${m}-message-age`,AlarmDescription:`Queue ${m} oldest message exceeds ${T} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:T,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[a,"QueueName"]}}],...C&&{AlarmActions:[C],OKActions:[C]}}}),f&&p.dlqAlarm!==!1)this.builder.addResource(`${f}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${m}-dlq-messages`,AlarmDescription:`Dead letter queue for ${m} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[f,"QueueName"]}}],...C&&{AlarmActions:[C]}}})}if(o.subscribe){let p=o.subscribe,C=p.topicArn;if(!C&&p.topicName)C={Ref:p.topicName};if(C){this.builder.addResource(`${a}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:a}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[a,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":C}}}]}}});let S={TopicArn:C,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[a,"Arn"]},RawMessageDelivery:p.rawMessageDelivery||!1};if(p.filterPolicy)S.FilterPolicy=p.filterPolicy,S.FilterPolicyScope=p.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${a}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:S,DependsOn:`${a}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(e,t);else this.generateRealtimeResources(e,t);let h=this.mergedConfig.infrastructure?.redirects;if(h){let m=h.target||this.mergedConfig.infrastructure?.dns?.domain||"",o=h.protocol||"https";if(h.domains?.length&&m)for(let g of h.domains){let{bucket:a,bucketPolicy:f,logicalId:p,policyLogicalId:C}=Z.createDomainRedirectBucket({slug:e,environment:t,sourceDomain:g,targetDomain:m,protocol:o});this.builder.addResource(p,a),this.builder.addResource(C,f)}if(h.paths&&Object.keys(h.paths).length>0){let g=Z.fromMapping(h.paths,{statusCode:h.statusCode||301}),{function:a,logicalId:f}=Z.createPathRedirectFunction({slug:e,environment:t,rules:g});this.builder.addResource(f,a)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[m,o]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:g,logicalId:a}=Ie.createAlarm({slug:e,environment:t,alarmName:`${e}-${t}-${m}`,metricName:o.metricName||"Errors",namespace:o.namespace||"AWS/Lambda",threshold:o.threshold||1,comparisonOperator:o.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(a,g)}let u=this.mergedConfig.infrastructure?.cache;if(u){let m=u.type||"redis";if(m==="redis"){this.generateNetworkInfrastructure(e,t);let o=u.redis||{},{replicationGroup:g,subnetGroup:a,logicalId:f,subnetGroupId:p}=re.createRedis({slug:e,environment:t,nodeType:o.nodeType||u.nodeType||"cache.t3.micro",engineVersion:o.engineVersion||"7.1",port:o.port||6379,numCacheClusters:o.numCacheNodes||2,automaticFailover:o.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:o.snapshotRetentionLimit||7,snapshotWindow:o.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(f,g),a&&p)this.builder.addResource(p,a);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[f,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[f,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(m==="memcached"){this.generateNetworkInfrastructure(e,t);let o=u.elasticache||{},{cluster:g,subnetGroup:a,logicalId:f,subnetGroupId:p}=re.createMemcached({slug:e,environment:t,nodeType:o.nodeType||u.nodeType||"cache.t3.micro",engineVersion:o.engineVersion||"1.6.22",numCacheNodes:o.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(f,g),a&&p)this.builder.addResource(p,a);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[f,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let b=this.mergedConfig.infrastructure?.email;if(b){let m=b.domain||this.mergedConfig.infrastructure?.dns?.domain;if(m){let{emailIdentity:o,logicalId:g}=L.verifyDomain({domain:m,slug:e,environment:t,enableDkim:b.enableDkim!==!1,dkimKeyLength:b.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(g,o),b.configurationSet!==!1){let{configurationSet:p,logicalId:C}=L.createConfigurationSet({slug:e,environment:t});this.builder.addResource(C,p)}let a=b.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(a){if(b.enableDkim!==!1)for(let I=1;I<=3;I++){let D=`DkimRecord${I}${m.replace(/\./g,"")}`;this.builder.addResource(D,{Type:"AWS::Route53::RecordSet",DependsOn:[g],Properties:{HostedZoneId:a,Name:{"Fn::GetAtt":[g,`DkimDNSTokenName${I}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[g,`DkimDNSTokenValue${I}`]}]}})}let{record:p,logicalId:C}=L.createSpfRecord(m,a);this.builder.addResource(C,p);let{record:S,logicalId:T}=L.createDmarcRecord(m,a,{policy:"none",reportingEmail:b.dmarcReportingEmail||`dmarc-reports@${m}`});this.builder.addResource(T,S)}this.builder.addOutput("EmailDomain",{Value:m,Description:"SES verified email domain"});let f=b.server;if(f?.enabled&&a){let p=this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1",C=`${e}-${t}-email`,{role:S,policy:T,roleLogicalId:I,policyLogicalId:D}=L.createEmailLambdaRole({slug:e,environment:t,s3BucketArn:`arn:aws:s3:::${C}`,sesIdentityArn:`arn:aws:ses:${p}:*:identity/${m}`});this.builder.addResource(I,S),this.builder.addResource(D,T);let{function:P,permission:O,logicalId:v,permissionLogicalId:F}=L.createInboundEmailLambda({slug:e,environment:t,roleArn:{"Fn::GetAtt":[I,"Arn"]},s3BucketName:C,organizedPrefix:"mailboxes/"});this.builder.addResource(v,P),this.builder.addResource(F,O);let V=L.createInboundEmailSetup({slug:e,environment:t,domain:m,s3BucketName:C,s3KeyPrefix:"inbox/",region:p,hostedZoneId:a,lambdaFunctionArn:{"Fn::GetAtt":[v,"Arn"]}});for(let[_,N]of Object.entries(V.resources)){if(N.Type==="AWS::SES::ReceiptRule")N.DependsOn=[F,v];this.builder.addResource(_,N)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:v},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:C,Description:"S3 bucket for email storage"});let z=this.serverEipLogicalIds.get("app");if(z&&a){let N=`${f?.subdomain||"mail"}.${m}`,x=N.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${x}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:N,Type:"A",TTL:"300",ResourceRecords:[{Ref:z}]}})}this.builder.addOutput("MailHost",{Value:`mail.${m}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let A=this.mergedConfig.infrastructure?.search;if(A){let m=A.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(m)this.generateNetworkInfrastructure(e,t);let{domain:o,logicalId:g}=De.createDomain({slug:e,environment:t,engineVersion:A.engineVersion||"OpenSearch_2.11",instanceType:A.instanceType||"t3.small.search",instanceCount:A.instanceCount||1,volumeSize:A.volumeSize||10,volumeType:A.volumeType||"gp3",dedicatedMaster:A.dedicatedMaster||!1,dedicatedMasterType:A.dedicatedMasterType,dedicatedMasterCount:A.dedicatedMasterCount||3,multiAz:A.multiAz||!1,encryption:A.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:A.advancedSecurity,autoTune:A.autoTune!==!1,vpc:m});this.builder.addResource(g,o),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[g,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[g,"Arn"]},Description:"OpenSearch domain ARN"})}let R=this.mergedConfig.infrastructure?.fileSystem;if(R&&Object.keys(R).length>0){this.generateNetworkInfrastructure(e,t);for(let[m,o]of Object.entries(R)){let{fileSystem:g,logicalId:a}=K.createFileSystem({slug:`${e}-${m}`,environment:t,encrypted:o.encrypted!==!1,performanceMode:o.performanceMode||"generalPurpose",throughputMode:o.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(a,g);let{securityGroup:f,logicalId:p}=K.createEfsSecurityGroup({slug:`${e}-${m}`,environment:t,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(p,f);let{mountTargets:C,logicalIds:S}=K.createMultiAzMountTargets(a,{slug:`${e}-${m}`,environment:t,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:p}});for(let T=0;T<C.length;T++)this.builder.addResource(S[T],C[T]);this.builder.addOutput(`${m}FileSystemId`,{Value:{Ref:a},Description:`EFS file system ID for ${m}`})}}let y=this.mergedConfig.infrastructure?.ai;if(y){let m=y.service||"ecs",o=y.models||["*"],g=y.allowStreaming!==!1,a;if(m==="ecs")a=M.enableBedrockForEcs({slug:e,environment:t,models:o,allowStreaming:g});else if(m==="ec2")a=M.enableBedrockForEc2({slug:e,environment:t,models:o,allowStreaming:g});else if(m==="lambda")a=M.enableBedrockForLambda({slug:e,environment:t,models:o,allowStreaming:g});else a=M.createBedrockRole(m,{slug:e,environment:t,models:o,allowStreaming:g});if(this.builder.addResource(a.logicalId,a.role),y.allowAsync){let{policy:f,logicalId:p}=M.createBedrockPolicy({slug:e,environment:t,models:o,allowStreaming:g,allowAsync:!0});this.builder.addResource(p,f)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[a.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(e,t){let r=this.mergedConfig.infrastructure?.realtime;if(!r)return;let n=r.name||`${e}-${t}-realtime`,i=r.scaling||{},l=r.storage||{type:"dynamodb"},c=i.handlerMemory||256,s=i.handlerTimeout||30,d=`${e}${t}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),h=`${e}${t}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(l.type==="dynamodb"){let S=l.dynamodb||{},T=S.billingMode||"PAY_PER_REQUEST";this.builder.addResource(d,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e}-${t}-realtime-connections`,BillingMode:T,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"},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:S.readCapacity||5,WriteCapacityUnits:S.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:S.readCapacity||5,WriteCapacityUnits:S.writeCapacity||5}},...S.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${e}-${t}-realtime-connections`},{Key:"Environment",Value:t}]}}),this.builder.addResource(h,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e}-${t}-realtime-channels`,BillingMode:T,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"},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:S.readCapacity||5,WriteCapacityUnits:S.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:S.readCapacity||5,WriteCapacityUnits:S.writeCapacity||5}},Tags:[{Key:"Name",Value:`${e}-${t}-realtime-channels`},{Key:"Environment",Value:t}]}})}let u=`${e}${t}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(u,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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":[d,"Arn"]},{"Fn::Sub":`\${${d}.Arn}/index/*`},{"Fn::GetAtt":[h,"Arn"]},{"Fn::Sub":`\${${h}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let b=`${e}${t}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),A=`${e}${t}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),R=`${e}${t}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(b,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:h},ENVIRONMENT:t}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[u,d]}),this.builder.addResource(A,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:h},ENVIRONMENT:t}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[u,d,h]}),this.builder.addResource(R,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:h},ENVIRONMENT:t}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[u,d,h]});let y=`${e}${t}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(y,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:n,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:n,Environment:t}}});let m=`${b}Permission`,o=`${A}Permission`,g=`${R}Permission`;this.builder.addResource(m,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:b},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$connect`}}}),this.builder.addResource(o,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:A},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$disconnect`}}}),this.builder.addResource(g,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:R},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$default`}}});let a=`${y}ConnectInteg`,f=`${y}DisconnectInteg`,p=`${y}MessageInteg`;this.builder.addResource(a,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${b}.Arn}/invocations`}}}),this.builder.addResource(f,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${A}.Arn}/invocations`}}}),this.builder.addResource(p,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${R}.Arn}/invocations`}}}),this.builder.addResource(`${y}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${a}}`}}}),this.builder.addResource(`${y}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${f}}`}}}),this.builder.addResource(`${y}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${p}}`}}});let C=`${y}Stage`;if(this.builder.addResource(C,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:y},StageName:t,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:i.messagesPerSecond||1000,ThrottlingRateLimit:i.messagesPerSecond||1000}}}),r.monitoring?.enabled){let S=r.monitoring,T=S.notificationTopicArn;if(!T&&S.notificationEmails?.length){let I=`${y}AlarmTopic`;this.builder.addResource(I,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),S.notificationEmails.forEach((D,P)=>{this.builder.addResource(`${I}Sub${P}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:I},Protocol:"email",Endpoint:D}})}),T={Ref:I}}if(S.connectionThreshold)this.builder.addResource(`${y}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${S.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:S.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:y}}],...T&&{AlarmActions:[T]}}});if(S.errorThreshold)this.builder.addResource(`${y}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${S.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:S.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:y}}],...T&&{AlarmActions:[T]}}})}this.builder.addOutput(`${y}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${y}}.execute-api.\${AWS::Region}.amazonaws.com/${t}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${y}Id`,{Description:"WebSocket API ID",Value:{Ref:y},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
12
15
  const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
13
16
  const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb');
14
17
 
@@ -167,7 +170,7 @@ catch (error) {
167
170
  return { statusCode: 500, body: JSON.stringify({ error: 'Internal error' }) };
168
171
  }
169
172
  };
170
- `.trim()}generateRealtimeServerResources(e,t){let r=this.mergedConfig.infrastructure?.realtime;if(!r)return;let n=r.server||{},o=n.port||6001,l=n.instances||1,c=`${e}${t}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(c,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${e} realtime WebSocket server`,GroupName:`${e}-${t}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:o,ToPort:o,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:`${e}-${t}-realtime-sg`},{Key:"Environment",Value:t}]}});let s=`${e}${t}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),d=`${e}${t}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),g=`${e}${t}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(g,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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(d,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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:"*"},...n.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let u=[{Name:"BROADCAST_HOST",Value:n.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(o)},{Name:"NODE_ENV",Value:t==="production"?"production":"development"}];if(n.redis?.enabled){if(n.redis.useElastiCache)u.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),u.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else u.push({Name:"REDIS_HOST",Value:n.redis.host||"localhost"}),u.push({Name:"REDIS_PORT",Value:String(n.redis.port||6379)});if(n.redis.keyPrefix)u.push({Name:"REDIS_KEY_PREFIX",Value:n.redis.keyPrefix})}this.builder.addResource(s,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${e}-${t}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[g,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[d,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${e}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:o,Protocol:"tcp"}],Environment:u,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${e}-${t}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${o}${n.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${e}-${t}-realtime`},{Key:"Environment",Value:t}]},DependsOn:[g,d]});let S=`${e}${t}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(S,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${e}-${t}-realtime`,RetentionInDays:30}});let A=`${e}${t}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(A,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:s},DesiredCount:l,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:c}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${e}-${t}-realtime`},{Key:"Environment",Value:t}]},DependsOn:[s,c,S]}),n.autoScaling){let b=n.autoScaling,y=`${e}${t}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(y,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:b.max||10,MinCapacity:b.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${e}-${t}-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:A}),b.targetCPU)this.builder.addResource(`${e}${t}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:y},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:b.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(r.monitoring?.enabled){let b=r.monitoring,y=b.notificationTopicArn;if(!y&&b.notificationEmails?.length){let f=`${e}${t}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(f,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),b.notificationEmails.forEach((i,m)=>{this.builder.addResource(`${f}Sub${m}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:f},Protocol:"email",Endpoint:i}})}),y={Ref:f}}this.builder.addResource(`${e}${t}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-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:`${e}-${t}-realtime`}],...y&&{AlarmActions:[y]}},DependsOn:A}),this.builder.addResource(`${e}${t}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-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:`${e}-${t}-realtime`}],...y&&{AlarmActions:[y]}},DependsOn:A})}this.builder.addOutput(`${e}${t}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${e}-${t}-realtime.\${AWS::Region}.elb.amazonaws.com:${o}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let e=this.mergedConfig.infrastructure?.realtime;if(!e||e.mode!=="server")return"";let t=e.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
173
+ `.trim()}generateRealtimeServerResources(e,t){let r=this.mergedConfig.infrastructure?.realtime;if(!r)return;let n=r.server||{},i=n.port||6001,l=n.instances||1,c=`${e}${t}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(c,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${e} realtime WebSocket server`,GroupName:`${e}-${t}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:i,ToPort:i,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:`${e}-${t}-realtime-sg`},{Key:"Environment",Value:t}]}});let s=`${e}${t}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),d=`${e}${t}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),h=`${e}${t}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(h,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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(d,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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:"*"},...n.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let u=[{Name:"BROADCAST_HOST",Value:n.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(i)},{Name:"NODE_ENV",Value:t==="production"?"production":"development"}];if(n.redis?.enabled){if(n.redis.useElastiCache)u.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),u.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else u.push({Name:"REDIS_HOST",Value:n.redis.host||"localhost"}),u.push({Name:"REDIS_PORT",Value:String(n.redis.port||6379)});if(n.redis.keyPrefix)u.push({Name:"REDIS_KEY_PREFIX",Value:n.redis.keyPrefix})}this.builder.addResource(s,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${e}-${t}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[h,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[d,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${e}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:i,Protocol:"tcp"}],Environment:u,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${e}-${t}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${i}${n.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${e}-${t}-realtime`},{Key:"Environment",Value:t}]},DependsOn:[h,d]});let b=`${e}${t}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(b,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${e}-${t}-realtime`,RetentionInDays:30}});let A=`${e}${t}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(A,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:s},DesiredCount:l,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:c}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${e}-${t}-realtime`},{Key:"Environment",Value:t}]},DependsOn:[s,c,b]}),n.autoScaling){let R=n.autoScaling,y=`${e}${t}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(y,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:R.max||10,MinCapacity:R.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${e}-${t}-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:A}),R.targetCPU)this.builder.addResource(`${e}${t}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:y},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:R.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(r.monitoring?.enabled){let R=r.monitoring,y=R.notificationTopicArn;if(!y&&R.notificationEmails?.length){let m=`${e}${t}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(m,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),R.notificationEmails.forEach((o,g)=>{this.builder.addResource(`${m}Sub${g}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:m},Protocol:"email",Endpoint:o}})}),y={Ref:m}}this.builder.addResource(`${e}${t}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-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:`${e}-${t}-realtime`}],...y&&{AlarmActions:[y]}},DependsOn:A}),this.builder.addResource(`${e}${t}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-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:`${e}-${t}-realtime`}],...y&&{AlarmActions:[y]}},DependsOn:A})}this.builder.addOutput(`${e}${t}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${e}-${t}-realtime.\${AWS::Region}.elb.amazonaws.com:${i}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let e=this.mergedConfig.infrastructure?.realtime;if(!e||e.mode!=="server")return"";let t=e.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
171
174
 
172
175
  export default {
173
176
  verbose: ${this.environment!=="production"},
@@ -216,7 +219,7 @@ ${t.loadManagement?.enabled?`
216
219
  },
217
220
  `:""}
218
221
  } satisfies BroadcastConfig
219
- `}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function ze(e){let t=[],r=[];if(!e.AWSTemplateFormatVersion)t.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")r.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!e.Resources||Object.keys(e.Resources).length===0)t.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[n,o]of Object.entries(e.Resources))He(n,o,t,r);if(e.Resources){let n=Ue(e.Resources);if(n.length>0)t.push({path:"Resources",message:`Circular dependencies detected: ${n.join(" -> ")}`,severity:"error"})}if(e.Parameters)for(let[n,o]of Object.entries(e.Parameters))Ge(n,o,t,r);if(e.Outputs)for(let[n,o]of Object.entries(e.Outputs))Ke(n,o,t,r);return{valid:t.length===0,errors:t,warnings:r}}function He(e,t,r,n){if(!t.Type)r.push({path:`Resources.${e}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(e))n.push({path:`Resources.${e}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(t.Type&&!t.Type.startsWith("AWS::")&&!t.Type.startsWith("Custom::"))r.push({path:`Resources.${e}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(t.Properties){for(let[o,l]of Object.entries(t.Properties))if(l===void 0||l===null)n.push({path:`Resources.${e}.Properties.${o}`,message:"Property has undefined or null value",severity:"warning"})}if(t.DependsOn){if(typeof t.DependsOn==="string"){if(t.DependsOn===e)r.push({path:`Resources.${e}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(t.DependsOn)){if(t.DependsOn.includes(e))r.push({path:`Resources.${e}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function Ge(e,t,r,n){if(!t.Type)r.push({path:`Parameters.${e}.Type`,message:"Parameter Type is required",severity:"error"});let o=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(t.Type&&!o.includes(t.Type)&&!t.Type.startsWith("AWS::"))n.push({path:`Parameters.${e}.Type`,message:`Uncommon parameter type: ${t.Type}`,severity:"warning"});if(t.NoEcho&&t.Default)n.push({path:`Parameters.${e}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function Ke(e,t,r,n){if(!t.Value)r.push({path:`Outputs.${e}.Value`,message:"Output Value is required",severity:"error"})}function Ue(e){let t={};for(let[c,s]of Object.entries(e)){if(t[c]=[],s.DependsOn){if(typeof s.DependsOn==="string")t[c].push(s.DependsOn);else if(Array.isArray(s.DependsOn))t[c].push(...s.DependsOn)}let d=ne(s);t[c].push(...d)}let r=new Set,n=new Set,o=[];function l(c,s){r.add(c),n.add(c),s.push(c);let d=t[c]||[];for(let g of d)if(!r.has(g)){if(l(g,s))return!0}else if(n.has(g)){let u=s.indexOf(g);return o.push(...s.slice(u),g),!0}return s.pop(),n.delete(c),!1}for(let c of Object.keys(t))if(!r.has(c)){if(l(c,[]))return o}return[]}function ne(e,t=[]){if(typeof e!=="object"||e===null)return t;if(Array.isArray(e)){for(let r of e)ne(r,t);return t}if(e.Ref&&typeof e.Ref==="string"&&!e.Ref.startsWith("AWS::"))t.push(e.Ref);if(e["Fn::GetAtt"]){let r=e["Fn::GetAtt"];if(Array.isArray(r)&&r.length>0)t.push(r[0])}for(let r of Object.values(e))ne(r,t);return t}function Ze(e){let t=[],r=[],n=new TextEncoder().encode(e).length,o=51200,l=460800;if(n>51200)if(n>460800)t.push({path:"template",message:`Template size (${n} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else r.push({path:"template",message:`Template size (${n} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:t.length===0,errors:t,warnings:r}}function qe(e){let t=[],r=[],n=e.Resources?Object.keys(e.Resources).length:0,o=e.Parameters?Object.keys(e.Parameters).length:0,l=e.Outputs?Object.keys(e.Outputs).length:0;if(n>500)t.push({path:"Resources",message:`Template has ${n} resources, exceeding the limit of 500`,severity:"error"});else if(n>200)r.push({path:"Resources",message:`Template has ${n} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(o>200)t.push({path:"Parameters",message:`Template has ${o} parameters, exceeding the limit of 200`,severity:"error"});if(l>200)t.push({path:"Outputs",message:`Template has ${l} outputs, exceeding the limit of 200`,severity:"error"});return{valid:t.length===0,errors:t,warnings:r}}function Ki(e){let{domains:t,email:r,staging:n=!1,challengeType:o="http-01",certPath:l="/etc/letsencrypt/live",autoRenew:c=!0}=e,s=t[0],d=t.map((u)=>`-d ${u}`).join(" "),g=n?"--staging":"";if(o==="http-01")return Je({domains:t,email:r,staging:n,certPath:l,autoRenew:c,domainFlags:d,stagingFlag:g,primaryDomain:s});else{let u=e.dnsProvider?.provider||(e.hostedZoneId?"route53":void 0);return Ye({domains:t,email:r,staging:n,certPath:l,autoRenew:c,domainFlags:d,stagingFlag:g,primaryDomain:s,hostedZoneId:e.hostedZoneId,dnsProvider:e.dnsProvider,dnsProviderType:u})}}function Je(e){let{email:t,certPath:r,autoRenew:n,domainFlags:o,stagingFlag:l,primaryDomain:c}=e;return`
222
+ `}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function He(e){let t=[],r=[];if(!e.AWSTemplateFormatVersion)t.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")r.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!e.Resources||Object.keys(e.Resources).length===0)t.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[n,i]of Object.entries(e.Resources))Ge(n,i,t,r);if(e.Resources){let n=Ze(e.Resources);if(n.length>0)t.push({path:"Resources",message:`Circular dependencies detected: ${n.join(" -> ")}`,severity:"error"})}if(e.Parameters)for(let[n,i]of Object.entries(e.Parameters))Ke(n,i,t,r);if(e.Outputs)for(let[n,i]of Object.entries(e.Outputs))Ue(n,i,t,r);return{valid:t.length===0,errors:t,warnings:r}}function Ge(e,t,r,n){if(!t.Type)r.push({path:`Resources.${e}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(e))n.push({path:`Resources.${e}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(t.Type&&!t.Type.startsWith("AWS::")&&!t.Type.startsWith("Custom::"))r.push({path:`Resources.${e}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(t.Properties){for(let[i,l]of Object.entries(t.Properties))if(l===void 0||l===null)n.push({path:`Resources.${e}.Properties.${i}`,message:"Property has undefined or null value",severity:"warning"})}if(t.DependsOn){if(typeof t.DependsOn==="string"){if(t.DependsOn===e)r.push({path:`Resources.${e}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(t.DependsOn)){if(t.DependsOn.includes(e))r.push({path:`Resources.${e}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function Ke(e,t,r,n){if(!t.Type)r.push({path:`Parameters.${e}.Type`,message:"Parameter Type is required",severity:"error"});let i=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(t.Type&&!i.includes(t.Type)&&!t.Type.startsWith("AWS::"))n.push({path:`Parameters.${e}.Type`,message:`Uncommon parameter type: ${t.Type}`,severity:"warning"});if(t.NoEcho&&t.Default)n.push({path:`Parameters.${e}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function Ue(e,t,r,n){if(!t.Value)r.push({path:`Outputs.${e}.Value`,message:"Output Value is required",severity:"error"})}function Ze(e){let t={};for(let[c,s]of Object.entries(e)){if(t[c]=[],s.DependsOn){if(typeof s.DependsOn==="string")t[c].push(s.DependsOn);else if(Array.isArray(s.DependsOn))t[c].push(...s.DependsOn)}let d=ne(s);t[c].push(...d)}let r=new Set,n=new Set,i=[];function l(c,s){r.add(c),n.add(c),s.push(c);let d=t[c]||[];for(let h of d)if(!r.has(h)){if(l(h,s))return!0}else if(n.has(h)){let u=s.indexOf(h);return i.push(...s.slice(u),h),!0}return s.pop(),n.delete(c),!1}for(let c of Object.keys(t))if(!r.has(c)){if(l(c,[]))return i}return[]}function ne(e,t=[]){if(typeof e!=="object"||e===null)return t;if(Array.isArray(e)){for(let r of e)ne(r,t);return t}if(e.Ref&&typeof e.Ref==="string"&&!e.Ref.startsWith("AWS::"))t.push(e.Ref);if(e["Fn::GetAtt"]){let r=e["Fn::GetAtt"];if(Array.isArray(r)&&r.length>0)t.push(r[0])}for(let r of Object.values(e))ne(r,t);return t}function qe(e){let t=[],r=[],n=new TextEncoder().encode(e).length,i=51200,l=460800;if(n>51200)if(n>460800)t.push({path:"template",message:`Template size (${n} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else r.push({path:"template",message:`Template size (${n} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:t.length===0,errors:t,warnings:r}}function je(e){let t=[],r=[],n=e.Resources?Object.keys(e.Resources).length:0,i=e.Parameters?Object.keys(e.Parameters).length:0,l=e.Outputs?Object.keys(e.Outputs).length:0;if(n>500)t.push({path:"Resources",message:`Template has ${n} resources, exceeding the limit of 500`,severity:"error"});else if(n>200)r.push({path:"Resources",message:`Template has ${n} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(i>200)t.push({path:"Parameters",message:`Template has ${i} parameters, exceeding the limit of 200`,severity:"error"});if(l>200)t.push({path:"Outputs",message:`Template has ${l} outputs, exceeding the limit of 200`,severity:"error"});return{valid:t.length===0,errors:t,warnings:r}}function Zi(e){let{domains:t,email:r,staging:n=!1,challengeType:i="http-01",certPath:l="/etc/letsencrypt/live",autoRenew:c=!0}=e,s=t[0],d=t.map((u)=>`-d ${u}`).join(" "),h=n?"--staging":"";if(i==="http-01")return Ye({domains:t,email:r,staging:n,certPath:l,autoRenew:c,domainFlags:d,stagingFlag:h,primaryDomain:s});else{let u=e.dnsProvider?.provider||(e.hostedZoneId?"route53":void 0);return Qe({domains:t,email:r,staging:n,certPath:l,autoRenew:c,domainFlags:d,stagingFlag:h,primaryDomain:s,hostedZoneId:e.hostedZoneId,dnsProvider:e.dnsProvider,dnsProviderType:u})}}function Ye(e){let{email:t,certPath:r,autoRenew:n,domainFlags:i,stagingFlag:l,primaryDomain:c}=e;return`
220
223
  # ==========================================
221
224
  # Let's Encrypt Certificate Setup (HTTP-01)
222
225
  # ==========================================
@@ -234,7 +237,7 @@ certbot certonly \\
234
237
  --agree-tos \\
235
238
  --email ${t} \\
236
239
  ${l} \\
237
- ${o}
240
+ ${i}
238
241
 
239
242
  # Check if certificate was obtained
240
243
  if [ -f "${r}/${c}/fullchain.pem" ]; then
@@ -254,7 +257,7 @@ ${n?ie(c):"# Auto-renewal disabled"}
254
257
 
255
258
  # Restart the application
256
259
  systemctl start stacks
257
- `}function Ye(e){let{email:t,certPath:r,autoRenew:n,domainFlags:o,stagingFlag:l,primaryDomain:c,hostedZoneId:s,dnsProvider:d,dnsProviderType:g}=e;if(g==="route53"||s){if(!s)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
260
+ `}function Qe(e){let{email:t,certPath:r,autoRenew:n,domainFlags:i,stagingFlag:l,primaryDomain:c,hostedZoneId:s,dnsProvider:d,dnsProviderType:h}=e;if(h==="route53"||s){if(!s)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
258
261
  # ==========================================
259
262
  # Let's Encrypt Certificate Setup (DNS-01 via Route53)
260
263
  # ==========================================
@@ -269,7 +272,7 @@ certbot certonly \\
269
272
  --agree-tos \\
270
273
  --email ${t} \\
271
274
  ${l} \\
272
- ${o}
275
+ ${i}
273
276
 
274
277
  # Check if certificate was obtained
275
278
  if [ -f "${r}/${c}/fullchain.pem" ]; then
@@ -286,7 +289,7 @@ else
286
289
  fi
287
290
 
288
291
  ${n?ie(c):"# Auto-renewal disabled"}
289
- `}if(!d)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let u=d.provider.toUpperCase(),S=Qe(d);return`
292
+ `}if(!d)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let u=d.provider.toUpperCase(),b=Xe(d);return`
290
293
  # ==========================================
291
294
  # Let's Encrypt Certificate Setup (DNS-01 via ${u})
292
295
  # ==========================================
@@ -294,7 +297,7 @@ ${n?ie(c):"# Auto-renewal disabled"}
294
297
  # Install certbot
295
298
  dnf install -y certbot jq curl
296
299
 
297
- ${S}
300
+ ${b}
298
301
 
299
302
  # Create DNS challenge hook scripts directory
300
303
  mkdir -p /etc/letsencrypt/hooks
@@ -309,7 +312,7 @@ DOMAIN="$CERTBOT_DOMAIN"
309
312
  VALIDATION="$CERTBOT_VALIDATION"
310
313
  RECORD_NAME="_acme-challenge.$DOMAIN"
311
314
 
312
- ${Xe(d)}
315
+ ${et(d)}
313
316
 
314
317
  # Wait for DNS propagation
315
318
  echo "Waiting 60 seconds for DNS propagation..."
@@ -328,7 +331,7 @@ DOMAIN="$CERTBOT_DOMAIN"
328
331
  VALIDATION="$CERTBOT_VALIDATION"
329
332
  RECORD_NAME="_acme-challenge.$DOMAIN"
330
333
 
331
- ${et(d)}
334
+ ${tt(d)}
332
335
  CLEANUPHOOK
333
336
 
334
337
  chmod +x /etc/letsencrypt/hooks/cleanup-hook.sh
@@ -343,7 +346,7 @@ certbot certonly \\
343
346
  --agree-tos \\
344
347
  --email ${t} \\
345
348
  ${l} \\
346
- ${o}
349
+ ${i}
347
350
 
348
351
  # Check if certificate was obtained
349
352
  if [ -f "${r}/${c}/fullchain.pem" ]; then
@@ -360,7 +363,7 @@ else
360
363
  fi
361
364
 
362
365
  ${n?ie(c):"# Auto-renewal disabled"}
363
- `}function Qe(e){switch(e.provider){case"porkbun":return`
366
+ `}function Xe(e){switch(e.provider){case"porkbun":return`
364
367
  # Porkbun API credentials
365
368
  export PORKBUN_API_KEY="${e.apiKey}"
366
369
  export PORKBUN_SECRET_KEY="${e.secretKey}"
@@ -371,7 +374,7 @@ export GODADDY_API_SECRET="${e.apiSecret}"
371
374
  export GODADDY_ENV="${e.environment||"production"}"
372
375
  `;case"route53":return`
373
376
  # Route53 uses IAM role credentials
374
- `;default:return""}}function Xe(e){switch(e.provider){case"porkbun":return`
377
+ `;default:return""}}function et(e){switch(e.provider){case"porkbun":return`
375
378
  # Extract root domain (last two parts)
376
379
  ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
377
380
  SUBDOMAIN="_acme-challenge"
@@ -415,7 +418,7 @@ curl -s -X PATCH "$API_URL/v1/domains/$ROOT_DOMAIN/records" \\
415
418
  "data": "'"$VALIDATION"'",
416
419
  "ttl": 600
417
420
  }]'
418
- `;default:return'echo "Unsupported DNS provider"'}}function et(e){switch(e.provider){case"porkbun":return`
421
+ `;default:return'echo "Unsupported DNS provider"'}}function tt(e){switch(e.provider){case"porkbun":return`
419
422
  # Extract root domain
420
423
  ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
421
424
 
@@ -503,7 +506,7 @@ systemctl enable certbot-renewal.timer
503
506
  systemctl start certbot-renewal.timer
504
507
 
505
508
  echo "Certificate auto-renewal configured"
506
- `}function Ui(e){let{httpPort:t=80,httpsPort:r=443,certPath:n="/etc/ssl/stacks",redirectHttp:o=!0}=e;return`
509
+ `}function qi(e){let{httpPort:t=80,httpsPort:r=443,certPath:n="/etc/ssl/stacks",redirectHttp:i=!0}=e;return`
507
510
  // HTTPS Server with Let's Encrypt certificates
508
511
  import { readFileSync, existsSync } from 'node:fs'
509
512
 
@@ -529,7 +532,7 @@ if (hasCerts) {
529
532
  })
530
533
  console.log(\`HTTPS server running on port \${HTTPS_PORT}\`)
531
534
 
532
- ${o?`
535
+ ${i?`
533
536
  // Start HTTP server for redirect
534
537
  const httpServer = Bun.serve({
535
538
  port: HTTP_PORT,
@@ -589,5 +592,5 @@ async function handleRequest(request: Request): Promise<Response> {
589
592
  // Implement your request handling here
590
593
  return new Response('Hello from Stacks!')
591
594
  }
592
- `}async function Zi(e){let{domain:t,challengeValue:r,hostedZoneId:n,dnsProvider:o,region:l="us-east-1"}=e;if(o){let s=await j(o).upsertRecord(t,{name:`_acme-challenge.${t}`,type:"TXT",content:r,ttl:60});if(!s.success)throw Error(`Failed to create DNS challenge record: ${s.message}`);return}if(n){await new q(l).changeResourceRecordSets({HostedZoneId:n,ChangeBatch:{Comment:"ACME DNS-01 challenge",Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:`_acme-challenge.${t}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${r}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}async function qi(e){let{domain:t,challengeValue:r,hostedZoneId:n,dnsProvider:o,region:l="us-east-1"}=e;if(o){let s=await j(o).deleteRecord(t,{name:`_acme-challenge.${t}`,type:"TXT",content:r});if(!s.success)console.warn(`Failed to delete DNS challenge record: ${s.message}`);return}if(n){await new q(l).changeResourceRecordSets({HostedZoneId:n,ChangeBatch:{Comment:"Remove ACME DNS-01 challenge",Changes:[{Action:"DELETE",ResourceRecordSet:{Name:`_acme-challenge.${t}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${r}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}function ji(e){try{let{execSync:t}=je("node:child_process"),r=t(`openssl x509 -checkend 2592000 -noout -in ${e}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as Ee,createSign as tt,generateKeyPairSync as we}from"node:crypto";var Oe={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class rt{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(e){this.directoryUrl=e.staging?Oe.staging:Oe.production,this.email=e.email,this.accountKey=e.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:e}=we("ec",{namedCurve:"P-256"});return e.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let e=await fetch(this.directoryUrl);if(!e.ok)throw Error(`Failed to fetch ACME directory: ${e.status}`);return this.directory=await e.json(),this.directory}async getNonce(){if(this.nonce){let n=this.nonce;return this.nonce=null,n}let e=await this.getDirectory(),r=(await fetch(e.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!r)throw Error("Failed to get nonce from ACME server");return r}getJwk(){let e=this.accountKey.split(`
593
- `).filter((l)=>!l.startsWith("-----")).join(""),t=Buffer.from(e,"base64"),r=t.length-65,n=t.subarray(r+1,r+33),o=t.subarray(r+33,r+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(n),y:this.base64UrlEncode(o)}}getJwkThumbprint(){let e=this.getJwk(),t=JSON.stringify({crv:e.crv,kty:e.kty,x:e.x,y:e.y}),r=Ee("sha256").update(t).digest();return this.base64UrlEncode(r)}base64UrlEncode(e){return(typeof e==="string"?Buffer.from(e):e).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(e,t){let r=await this.getNonce(),n=this.getJwk(),o={alg:"ES256",nonce:r,url:e};if(this.accountUrl)o.kid=this.accountUrl;else o.jwk=n;let l=this.base64UrlEncode(JSON.stringify(o)),c=t===""?"":this.base64UrlEncode(JSON.stringify(t)),s=`${l}.${c}`,d=tt("SHA256");d.update(s);let g=d.sign(this.accountKey),u=g.subarray(4,4+g[3]),S=4+g[3]+2,A=g.subarray(S,S+g[S-1]),b=Buffer.alloc(32),y=Buffer.alloc(32);u.copy(b,32-u.length),A.copy(y,32-A.length);let f=Buffer.concat([b,y]);return JSON.stringify({protected:l,payload:c,signature:this.base64UrlEncode(f)})}async acmeRequest(e,t){let r=await this.signPayload(e,t),n=await fetch(e,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:r}),o=n.headers.get("replay-nonce");if(o)this.nonce=o;let l,c=n.headers.get("content-type");if(c?.includes("application/json")||c?.includes("application/problem+json"))l=await n.json();else l=await n.text();if(!n.ok)throw Error(`ACME request failed: ${JSON.stringify(l)}`);return{body:l,headers:n.headers}}async registerAccount(){let e=await this.getDirectory(),{body:t,headers:r}=await this.acmeRequest(e.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),n=r.get("location");if(!n)throw Error("No account URL returned");return this.accountUrl=n,n}async createOrder(e){if(!this.accountUrl)await this.registerAccount();let t=await this.getDirectory(),{body:r,headers:n}=await this.acmeRequest(t.newOrder,{identifiers:e.map((l)=>({type:"dns",value:l}))}),o=n.get("location");if(!o)throw Error("No order URL returned");return{orderUrl:o,authorizations:r.authorizations,finalize:r.finalize}}async getAuthorization(e){let{body:t}=await this.acmeRequest(e,""),r=t.identifier.value,n=this.getJwkThumbprint(),o=t.challenges.filter((l)=>l.type==="http-01"||l.type==="dns-01").map((l)=>{let c=`${l.token}.${n}`;if(l.type==="http-01")return{type:"http-01",token:l.token,keyAuthorization:c,identifier:`/.well-known/acme-challenge/${l.token}`};else{let s=this.base64UrlEncode(Ee("sha256").update(c).digest());return{type:"dns-01",token:l.token,keyAuthorization:c,identifier:`_acme-challenge.${r}`,dnsValue:s}}});return{domain:r,challenges:o}}async respondToChallenge(e){await this.acmeRequest(e,{})}async waitForAuthorization(e,t=30){for(let r=0;r<t;r++){let{body:n}=await this.acmeRequest(e,"");if(n.status==="valid")return;if(n.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(n)}`);await new Promise((o)=>setTimeout(o,2000))}throw Error("Authorization timed out")}generateCsr(e){let{privateKey:t}=we("rsa",{modulusLength:2048}),r=t.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(e,t),privateKey:r}}createSimpleCsr(e,t){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(e,t){let{csr:r,privateKey:n}=this.generateCsr(t),{body:o}=await this.acmeRequest(e,{csr:this.base64UrlEncode(Buffer.from(r,"base64"))}),l=o.certificate;if(!l)throw Error("Certificate not immediately available - polling not implemented");let s=await(await fetch(l)).text(),d=s.split(/(?=-----BEGIN CERTIFICATE-----)/g),g=d[0],u=d.slice(1).join("");return{certificate:g,privateKey:n,chain:u,fullchain:s,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var ve=["js","mjs","cjs","css","map","woff","woff2","ttf","otf","eot","png","jpg","jpeg","gif","webp","avif","svg","ico","mp4","webm","ogg","mp3","wav","pdf","wasm"];function oe(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`}function Ne(e){return`{${e.map(oe).join(" ")}}`}function ae(e){if(e.length===1)return`http.host eq ${oe(e[0])}`;return`http.host in ${Ne(e)}`}function se(e,t={}){if(t.enabled===!1||e.length===0)return[];let r=ae(e),n=[],o=t.bypassPaths??[],l=o.length>0?`(${o.map((g)=>`starts_with(http.request.uri.path, ${oe(g)})`).join(" or ")})`:void 0;if(l)n.push({action:"set_cache_settings",description:"bypass cache",expression:`(${r} and ${l})`,enabled:!0,action_parameters:{cache:!1}});let c=l?`${r} and not ${l}`:r,s=t.assetExtensions??ve,d=s.length>0?`lower(http.request.uri.path.extension) in ${Ne([...s])}`:void 0;if(d)n.push({action:"set_cache_settings",description:"cache fingerprinted assets",expression:`(${c} and ${d})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:t.assetEdgeTtl??2592000},browser_ttl:{mode:"override_origin",default:t.assetBrowserTtl??31536000}}});return n.push({action:"set_cache_settings",description:"cache documents",expression:d?`(${c} and not ${d})`:`(${c})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:t.documentEdgeTtl??3600},browser_ttl:{mode:"override_origin",default:t.documentBrowserTtl??0}}}),n}function ce(e,t,r){if(e.length===0||!t||!r)return[];return[{action:"rewrite",description:"origin guard header",expression:`(${ae(e)})`,enabled:!0,action_parameters:{headers:{[t]:{operation:"set",value:r}}}}]}var k=(e)=>e===void 0?void 0:e?"on":"off";function le(e){let t={ssl:e.ssl,always_use_https:k(e.alwaysUseHttps),automatic_https_rewrites:k(e.automaticHttpsRewrites),min_tls_version:e.minTlsVersion,tls_1_3:k(e.tls13),brotli:k(e.brotli),http3:k(e.http3),"0rtt":k(e.zeroRtt),early_hints:k(e.earlyHints),browser_cache_ttl:e.browserCacheTtl,always_online:k(e.alwaysOnline),websockets:k(e.websockets)};if(e.hsts)t.security_header={strict_transport_security:{enabled:e.hsts.enabled,max_age:e.hsts.maxAge??31536000,include_subdomains:e.hsts.includeSubdomains??!1,preload:e.hsts.preload??!1,nosniff:e.hsts.noSniff??!0}};for(let r of Object.keys(t))if(t[r]===void 0)delete t[r];return{...t,...e.raw??{}}}var W={ssl:"strict",alwaysUseHttps:!0,automaticHttpsRewrites:!0,minTlsVersion:"1.2",tls13:!0,brotli:!0,http3:!0,earlyHints:!0,alwaysOnline:!0,browserCacheTtl:0};import{connect as nt}from"node:tls";async function de(e){let{address:t,serverName:r,port:n=443,timeoutMs:o=5000}=e;return new Promise((l)=>{let c=!1,s=(g)=>{if(c)return;c=!0;try{d.destroy()}catch{}l(g)},d=nt({host:t,port:n,servername:r,rejectUnauthorized:!1,timeout:o});d.once("secureConnect",()=>{if(d.authorized){s({reachable:!0,trusted:!0});return}s({reachable:!0,trusted:!1,reason:d.authorizationError?String(d.authorizationError):"origin certificate is not trusted for this hostname"})}),d.once("timeout",()=>{s({reachable:!1,trusted:!1,reason:`no TLS handshake within ${o}ms`})}),d.once("error",(g)=>{s({reachable:!1,trusted:!1,reason:g.message})})})}async function it(e){let{provider:t,zone:r,hosts:n,ipv4:o,ipv6:l,proxied:c=!0,settings:s=W,cache:d,originGuard:g,purge:u=!0,ttl:S=300,skipOriginProbe:A=!1}=e,b={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(n.length===0)return b;let y=[];for(let i of n){let m=c;if(c&&!A){let h=await de({address:o,serverName:i});if(!h.trusted){m=!1;let p=h.reason||"origin is not serving a trusted certificate";b.deferredProxy.push({host:i,reason:p}),b.warnings.push(`${i}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${p}). 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(m)y.push(i);let a=[{type:"A",content:o}];if(l&&ue(i))a.push({type:"AAAA",content:l});for(let{type:h,content:p}of a){let C=await t.upsertRecord(r,{name:i,type:h,content:p,ttl:S,proxied:m});if(C.success)b.records.push({host:i,type:h,content:p,proxied:m});else b.warnings.push(`${i} ${h} → ${p} failed: ${C.message||"unknown provider error"}`)}}if(y.length===0){if(c)b.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return b}try{let i=le(s),m=await t.applyZoneSettings(r,i);b.settingsChanged=m.changed;for(let a of m.failed)b.warnings.push(`zone setting '${a.id}' could not be applied: ${a.error}`)}catch(i){b.warnings.push(`zone settings could not be read: ${i instanceof Error?i.message:String(i)}`)}let f=se(y,d);if(f.length>0){let i=await t.putManagedPhaseRules(r,"http_request_cache_settings",f);if(i.success)b.cacheRules=f.length;else b.warnings.push(`cache rules could not be written: ${i.message}`)}if(g){let i=ce(y,g.header,g.value);if(i.length>0){let m=await t.putManagedPhaseRules(r,"http_request_late_transform",i);if(m.success)b.originGuard=!0;else b.warnings.push(`origin guard header could not be written: ${m.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(u){if(b.purged=await t.purgeCache(r,{hosts:y}),!b.purged)b.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return b}var ot=(e)=>process.env[e];function ke(e,t){let r=e.replace(/\.$/,"").toLowerCase();if(t){let n=t.replace(/\.$/,"").toLowerCase();if(r===n||r.endsWith(`.${n}`))return n}return r.split(".").slice(-2).join(".")}function at(e,t={}){let r=t.env??ot,n=e.infrastructure?.compute?.proxy?.cdn,o=[];if(!n||n.provider!=="cloudflare")return{plan:null,errors:o};if(n.originDomain)o.push(`compute.proxy.cdn.originDomain (${n.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 l=r("CLOUDFLARE_API_TOKEN");if(!l)return o.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:o};let c=e.sites??{},s=n.frontedHosts?.length?[...new Set(n.frontedHosts.map((A)=>A.toLowerCase()))]:pe(c,{autoWww:e.infrastructure?.compute?.proxy?.autoWww!==!1});if(s.length===0)return o.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:o};let d=e.infrastructure?.dns?.domain,g=new Set(s.map((A)=>ke(A,d)));if(g.size>1)return o.push(`Fronted hosts span more than one zone (${[...g].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:o};let u=n.cloudflare??{},S=n.secret?{header:n.secretHeader??"X-Origin-Verify",value:n.secret}:void 0;return{plan:{zone:[...g][0],hosts:s,apiToken:l,zoneId:u.zoneId??r("CLOUDFLARE_ZONE_ID"),accountId:u.accountId??r("CLOUDFLARE_ACCOUNT_ID"),proxied:u.proxied!==!1,settings:u.settings??W,cache:u.cache,originGuard:S,purge:u.purgeOnDeploy!==!1,skipOriginProbe:u.skipOriginProbe===!0},errors:o}}export{Cu as ABTestManager,pr as ACMClient,mr as ACMDnsValidator,Oe as ACME_DIRECTORIES,M as AI,Pf as API_IDEMPOTENCY_TTL_MS,Tf as API_TOKEN_DEFAULT_TTL_MS,$f as API_TOKEN_MAX_TTL_MS,wy as API_VERSION,lf as AUTHORIZATION_CAPABILITIES,jm as AUTH_ACTION_TOKEN_TTL_MS,Jm as AUTH_MFA_CHALLENGE_TTL_MS,Ym as AUTH_OIDC_TRANSACTION_TTL_MS,qm as AUTH_SESSION_ABSOLUTE_TTL_MS,Zm as AUTH_SESSION_IDLE_TTL_MS,Ec as AWSAPIError,yt as AWSClient,xe as AWSCloudFormationClient,Le as AWSCloudFrontClient,au as AWSConfigManager,Rs as AWS_PSEUDO_PARAMETERS,yd as AWS_REGIONS,rt as AcmeClient,Tt as AlertEvaluator,Rt as AlertStore,Lh as AnomalyConfigStore,Pe as ApiGateway,$y as ApiServiceError,Br as ApplicationAutoScalingClient,bs as Arn,hs as AssetHasher,fs as Auth,Qm as AuthenticationStore,Iy as AutomationApiService,If as AutomationIdentityStore,UC as AwsAuroraDataAdapter,YC as AwsAuroraTransport,HS as AwsDatabaseBackupSource,pn as AwsDriver,ZC as AwsElastiCacheDataAdapter,QC as AwsElastiCacheTransport,By as AwsIamCapabilityScanner,QS as AwsInfrastructureBackupSource,KC as AwsRdsDataAdapter,JC as AwsRdsTransport,AS as AwsRegionalDriver,nA as AwsSecretsManagerConfigurationBackend,by as AwsSpendTransport,iA as AwsSsmConfigurationBackend,WS as BackupCoordinator,ru as BackupManager,MS as BackupStore,xp as BatchProcessingManager,wr as BedrockClient,Er as BedrockRuntimeClient,Pg as BitbucketSourceAdapter,fu as BlueGreenManager,Cp as BounceComplaintHandler,qu as BuildOptimizationManager,XC as BunDockerRuntime,jS as BunDockerVolumeRuntime,US as BunFilesystemArchiveRuntime,is as CDN,ct as CHAIN_HEADER,qt as CLOUDFLARE_MANAGED_RULE_PREFIX,Md as COMMON_CROSS_ACCOUNT_ROLES,sf as CONTROL_PLANE_SCHEMA_VERSION,re as Cache,hu as CanaryManager,zu as CertificateManager,sg as CloudBlockVolumeDriver,Sn as CloudDriverFactory,Tc as CloudError,Ts as CloudFormationBuilder,xe as CloudFormationClient,Le as CloudFrontClient,cu as CloudTrailManager,br as CloudWatchLogsClient,jt as CloudflareProvider,id as CommandHistory,Ss as Communication,ug as ComposeApplicationService,dg as ComposeApplicationStore,Or as ComprehendClient,w as Compute,Ry as ComputeSpendTransport,$c as ConfigurationError,aA as ConfigurationService,XS as ConfigurationStore,Rr as ConnectClient,jC as ContainerDataAdapter,Ju as ContainerRegistryManager,YS as ControlPlaneBackupSource,kS as ControlPlaneCleanupDriver,bf as ControlPlaneStore,sh as CounterTracker,Pc as CredentialError,ld as CrossRegionReferenceManager,Hs as DASHBOARD_ENTRY,Gs as DASHBOARD_PORT_BASE,Ks as DASHBOARD_PORT_SPAN,zs as DASHBOARD_STATE_DIR,Xn as DEFAULT_ATTACK_MODE_HOURS,Et as DEFAULT_DDOS_THRESHOLDS,ih as DEFAULT_METER_MAPPINGS,jg as DEFAULT_PRICE_BOOK,ut as DEFAULT_RECURSION_LIMITS,_c as DEFAULT_SERVICE_LIMITS,Ia as DEFAULT_STATE_DIR,ve as DEFAULT_STATIC_ASSET_EXTENSIONS,Xh as DEFAULT_TELEMETRY_POLICY,uh as DEFAULT_THRESHOLDS,jf as DEPLOYMENT_QUEUE_KINDS,st as DEPTH_HEADER,Mh as DETECTABLE_SIGNALS,RC as DIAGNOSTIC_PRESETS,Np as DLQMonitoringManager,os as DNS,fp as DNSSECManager,HC as DataServiceLifecycle,WC as DataServiceStore,U as Database,Mu as DatabaseUserManager,Nc as DebugLogger,es as DependencyGraph,gs as Deployment,Ic as DeploymentError,iu as DisasterRecoveryManager,dr as DnsProviderFactory,eS as DockerDataTransport,mC as DockerDiscoveryAdapter,og as DockerNamedVolumeDriver,JS as DockerVolumeBackupSource,Kf as DurableOperationQueue,Uf as DurableQueueWorker,Pr as DynamoDBClient,Ht as EC2Client,fr as ECRClient,gr as ECSClient,Gr as EFSClient,Tr as ELBv2Client,Bg as ENFORCEMENT_ACTIONS,Ah as ENFORCEMENT_DESCRIPTIONS,Wg as ENFORCEMENT_SEVERITY,yC as EcsRuntimeAdapter,jn as EdgeRateLimiter,Vr as ElastiCacheClient,L as Email,Ip as EmailAdvanced,Ap as EmailAnalyticsManager,bt as EmailClient,Dp as EmailHandlers,$p as EmailTemplateManager,tS as EncryptedDataSecretStore,wc as ErrorCodes,Fr as EventBridgeClient,LC as EventBridgeJobAdapter,oA as ExternalConfigurationBackend,Op as FIFOQueueManager,Wh as FOCUS_VERSION,Hc as FileCache,K as FileSystem,ZS as FilesystemBackupSource,aS as FleetService,oS as FleetStore,As as Fn,Ig as GiteaSourceAdapter,Tg as GithubSourceAdapter,$g as GitlabSourceAdapter,dd as GlobalResourceManager,Zt as GoDaddyProvider,du as GuardDutyManager,Xc as HashCache,Om as HealthCheckManager,It as HealthCheckRunner,mn as HetznerClient,yn as HetznerDriver,Ct as IAMClient,qr as IPV6_EXCLUDED_HOST_LABELS,Uu as ImageScanningManager,We as InfrastructureGenerator,gf as InvalidOperationTransitionError,cs as JobLoader,MC as JobProviderReconciler,VC as JobService,NC as JobStore,Mr as KendraClient,Am as LARAVEL_SERVERLESS_BUILD_STEPS,Ar as LambdaClient,ip as LambdaConcurrencyManager,dp as LambdaDLQManager,ap as LambdaDestinationsManager,ep as LambdaLayersManager,CC as LambdaRuntimeAdapter,cp as LambdaVPCManager,rp as LambdaVersionsManager,rA as LocalEncryptedConfigurationBackend,qS as LogicalDatabaseBackupSource,Iu as LogsManager,Gp as MANAGED_NODE_VERSIONS,Ln as MANAGEMENT_DASHBOARD_SITE,Js as MANAGEMENT_DASHBOARD_SITE_PREFIX,Qn as MAX_CONTROL_HOURS,Sf as MAX_CONTROL_PLANE_ERROR_BYTES,Cf as MAX_CONTROL_PLANE_JSON_BYTES,_g as METERS,Vg as METER_KEYS,zg as MICRO_CENTS,hh as MIN_PROJECTION_CONFIDENCE,OS as MaintenanceService,ES as MaintenanceStore,ps as Messaging,$u as MetricsManager,Ou as MigrationManager,Tl as MockCloudFormation,Pl as MockDynamoDB,$l as MockS3,Ie as Monitoring,Od as MultiAccountManager,sd as MultiRegionManager,zl as MultiStepProgress,Re as Network,Nm as NetworkSecurityManager,Pt as NotificationRouter,Ir as OpenSearchClient,ff as OptimisticConcurrencyError,vd as OrganizationManager,Rm as PHP_DEFAULT_EXCLUDES,jp as PHP_LAYER_EXTENSIONS,Kt as PROXIABLE_RECORD_TYPES,Cs as ParameterStore,xu as PerformanceManager,$e as Permissions,Lr as PersonalizeClient,ss as Phone,Ep as PhoneAdvanced,as as PhoneHandlers,dS as PlacementService,lS as PlacementStore,kr as PollyClient,Ut as PorkbunProvider,xy as PreDeployScanner,Dl as PreviewEnvironmentManager,qf as PreviewEnvironmentService,Zf as PreviewEnvironmentStore,Nl as PreviewNotificationService,Wl as ProgressBar,Au as ProgressiveDeploymentManager,ei as ProtectionControlStore,za as Pseudo,te as Queue,zf as QueueCancellationError,Mp as QueueManagementManager,$a as QueuePresets,Hf as QueueTimeoutError,Kn as RATE_LIMIT_KEY_SEPARATOR,$r as RDSClient,xd as RECOMMENDED_ACCOUNT_STRUCTURES,Ld as RECOMMENDED_SCPS,Sg as RELEASE_QUEUE_KINDS,td as REPL,nd as REPLCommandBuilder,rd as REPLContext,al as RateLimiter,Pa as RealtimePresets,Qh as RecordingSpendTransport,ft as RecursionGuard,Z as Redirects,ud as RegionPairManager,CS as RegionService,yS as RegionStore,ns as Registry,vr as RekognitionClient,gg as ReleaseService,fg as ReleaseStore,uS as RemoteBuildService,Nu as ReplicaManager,xm as ResourceManagementManager,Gf as RetryableOperationError,q as Route53Client,Gt as Route53DomainsClient,er as Route53Provider,hp as Route53ResolverManager,pp as Route53RoutingManager,TC as RuntimeOperationService,$C as RuntimeStreamRegistry,BS as S3BackupDestinationAdapter,St as S3Client,bc as S3Error,ky as SECRET_PATTERNS,kh as SENSITIVITY_THRESHOLDS,At as SESClient,us as SMS,Cr as SNSClient,Sy as SPEND_CYCLE_SECONDS,Zh as SPEND_GATE_SETTING,hy as SPEND_LEASE_SETTING,Sr as SQSClient,hr as SSMClient,Da as STATE_DIR_ENV_VAR,W as STATIC_SITE_ZONE_SETTINGS,Mt as STSClient,_r as SchedulerClient,De as Search,Vy as SecretFindingScanner,ys as Secrets,Bu as SecretsManager,yr as SecretsManagerClient,Vu as SecretsRotationManager,ee as Security,pu as SecurityHubManager,Ny as SecurityPostureStore,Fy as SecurityScannerRunner,Gu as SecurityScanningManager,Rp as SenderReputationManager,xC as ServerCronJobAdapter,qC as ServerDataAdapter,ag as ServerPathVolumeDriver,Qu as ServiceMeshManager,Te as Sftp,Vh as SignalSource,wp as SmsAdvanced,Wr as SmsClient,ds as SmsHandlers,bg as SourceConnectionStore,Rg as SourceProviderError,jh as SpendCapError,qh as SpendGate,yy as SpendLoopLease,gy as SpendNotificationRouter,Cy as SpendRunner,Kh as SpendService,ph as SpendStore,Hl as Spinner,nS as SshFleetDriver,pd as StackDependencyManager,ls as StacksIntegration,Im as StaticSiteManager,X as Storage,Em as StorageAdvancedManager,Hr as SupportClient,Eu as SyntheticsManager,rS as SystemFleetSshTransport,hC as SystemdDiscoveryAdapter,lt as TRACE_HEADER,Gl as TaskList,uy as TelemetryStore,Se as TemplateBuilder,Gc as TemplateCache,Nr as TextractClient,Dr as TranscribeClient,xr as TranslateClient,xS as TransportDisasterRecoveryDriver,NS as TransportPlatformMaintenanceDriver,mS as TransportRemoteBuildDriver,_y as TrivyImageScanner,Df as TsCloudApiError,Ef as TsCloudClient,py as URGENT_SPEND_EVENTS,bh as USER_VISIBLE_ACTIONS,bS as UnavailableRegionalDriver,or as UnifiedDnsValidator,hf as UnsupportedSchemaVersionError,Dc as ValidationError,zr as VoiceClient,ng as VolumeService,Qf as VolumeStore,ms as Workflow,Ru as XRayManager,Su as abTestManager,yg as activateImmutableRelease,aC as ageSeconds,lh as aggregateDeltas,ts as analyzeStackDiff,Nh as anomalyOptionsForSignal,ni as applyControlsToDdos,ri as applyControlsToRateLimits,Lt as applyMitigationFactor,nr as applyZoneMigration,zp as artifactKey,mg as assertReleaseStrategy,Jh as assertSpendAllows,Uy as attachProvenanceToRelease,Hy as attachSbomToRelease,Gy as attachVulnerabilitySummary,ef as authEncryptionKeyFile,pf as authorizeOrganization,bC as authorizeRuntimePath,Jl as autocomplete,su as awsConfigManager,_S as backupCredentialStatus,nu as backupManager,tl as batch,Lp as batchProcessingManager,of as beginOidcAuthorization,gu as blueGreenManager,Sp as bounceComplaintHandler,eh as budgetWindow,fi as buildAndPushServerlessImage,rm as buildBunRuntimeLayerZip,$s as buildCloudFormationTemplate,Bf as buildComposeLogsCommand,Vf as buildComposeRuntimeCommand,_f as buildComposeScaleCommand,Wf as buildComposeShellCommand,hi as buildFunctionEnv,xn as buildHostCleanupScript,Ba as buildMailEnv,Bn as buildManagementDashboardArtifact,Ni as buildMediaCdnPlan,tm as buildNodeRuntimeLayerZip,ju as buildOptimizationManager,ce as buildOriginGuardRule,bm as buildPhpRuntimeLayerZip,Nn as buildSiteDeployScript,bn as buildSshArgs,se as buildStaticSiteCacheRules,kn as buildStaticSiteDeployScript,sC as bytes,yu as canaryManager,RS as canonicalJson,nC as capabilities,cS as capacity,pl as categorizeChanges,Hu as certificateManager,Mc as checkIAMPermissions,cm as checkInvocation,Bc as checkServiceQuotas,sl as chunk,qi as cleanupDns01Challenge,Aa as clearSigningKeyCache,Ng as cloneSourceBinding,gl as cloudConfigSchema,An as cloudDrivers,lu as cloudTrailManager,$m as collectPhpAppEntries,Kr as collectServerDnsDomains,lg as completeComposeVolumeDeletion,af as completeOidcAuthorization,rc as composePresets,Ff as composeProjectName,qp as composeServerlessAppTemplate,Ty as compositeSpendTransport,GS as compressBackup,_m as config,zC as connectionGuidance,Yu as containerRegistryManager,yf as controlPlaneDatabaseFile,cf as controlPlaneMigrations,vs as createApiBackendPreset,vy as createApiV1Handler,hS as createAsgBuildDriver,zS as createBackupQueueHandlers,gm as createCliHandler,Cn as createCloudDriver,Ce as createCloudFrontPolicy,yc as createCredentialProvider,Ws as createDashboardSite,Ms as createDataPipelinePreset,GC as createDataServiceQueueHandlers,Yf as createDeploymentQueueHandlers,j as createDnsProvider,gS as createEcsBuildDriver,Yh as createEnforcementHandlers,vc as createError,ws as createExistingStaticFullStackPreset,iS as createFleetQueueHandlers,Os as createFullStackAppPreset,sr as createGoDaddyValidator,hm as createHandlers,mm as createHttpHandler,ks as createJamstackPreset,_C as createJobQueueHandlers,_s as createLaravelPreset,Fs as createMLApiPreset,vS as createMaintenanceQueueHandlers,wi as createMediaAccessToken,xs as createMicroservicesPreset,Il as createMockAWS,Is as createNodeJsServerPreset,Ds as createNodeJsServerlessPreset,zt as createObjectStorageClient,ar as createPorkbunValidator,nc as createPreset,ma as createPresignedUrl,fa as createPresignedUrlAsync,fm as createQueueHandler,Ls as createRealtimeAppPreset,SS as createRegionQueueHandlers,Ky as createReleaseProvenance,Ag as createReleaseQueueHandlers,pS as createRemoteBuildQueueHandlers,cr as createRoute53Validator,SC as createRuntimeAdapters,Rc as createS3Client,fS as createServerBuildDriver,Bs as createServerlessLaravelPreset,Es as createServerlessNodePreset,Dg as createSourceAdapter,Ps as createStaticSitePreset,Vs as createTraditionalWebAppPreset,ig as createVolumeQueueHandlers,Ns as createWordPressPreset,Vp as createZip,md as crossRegionReferenceManager,Ti as dashboardActions,Mn as dashboardCredentialsFile,BC as dataServiceCapabilities,Fu as databaseUserManager,Wm as decodeBase32,KS as decompressBackup,VS as decryptBackup,Mm as defaultConfig,yl as defaultLocalConfig,Yn as defaultRateLimitRules,ui as deleteStaticSite,zn as deployAllComputeSites,yi as deployServerlessApp,mi as deploySite,Wn as deploySiteRelease,ci as deployStaticSite,pi as deployStaticSiteFull,oi as deployStaticSiteWithExternalDns,ai as deployStaticSiteWithExternalDnsFull,La as deploymentCoexistenceError,Us as deriveManagementDashboardPort,ti as describePosture,kC as desiredJobProviderState,Oh as detectAnomalies,ka as detectDeploymentTargets,lr as detectDnsProvider,vh as detectLatestAnomaly,xc as detectMisconfigurations,da as detectServiceRegion,vf as diffCompose,ll as diffTemplates,vg as discoverGitRefs,nf as discoverOidcProvider,cC as discoverRuntimeInventory,kp as dlqMonitoringManager,ur as dnsProviders,gp as dnssecManager,pC as dockerWorkloads,$S as documentDigest,ou as drManager,lC as ecsWorkloads,mf as effectiveCapabilities,bp as emailAnalyticsManager,Pp as emailTemplateManager,Bm as encodeBase32,FS as encryptBackup,jy as ensureDefaultSecurityPolicies,En as ensureFirewall,_n as ensureManagementDashboard,wn as ensureServer,Dn as ensureSshKey,on as escapeSecLang,Ch as evaluateBudget,Dt as evaluateTelemetryAlertRules,OC as eventBridgeScheduleInput,um as eventToRequest,wh as ewma,Of as exportCompose,tr as exportRoute53Zone,tc as extendPreset,vp as fifoQueueManager,Qc as findChangedFiles,oh as findMapping,Gg as findPriceEntry,Bd as formatAccountStructure,Fl as formatBytes,my as formatCents,rs as formatDiff,Vl as formatDuration,Ql as formatFlagSuggestions,od as formatHistory,ad as formatHistoryStats,Bl as formatKeyValue,_l as formatList,Ml as formatProgressBar,Dd as formatRegion,Ed as formatRegionList,My as formatScanResults,Ul as formatSuggestion,xl as formatTable,gh as formatTimeToExhaustion,Ll as formatTree,mc as fromEC2Metadata,fc as fromECSMetadata,uc as fromEnvironment,pc as fromSharedCredentials,gc as fromWebIdentity,dt as functionFingerprint,pe as gatewayHostnames,Xp as generateAppImageDockerfile,eu as generateApprovalConfig,_p as generateBootstrap,Ol as generateCleanupWorkflow,vl as generateCostReportWorkflow,Vd as generateCrossAccountRoleCF,Wy as generateCycloneDxSbom,Yd as generateDeploymentConfig,Ud as generateDeploymentPipeline,Wd as generateDeploymentWorkflow,ii as generateExternalDnsStaticSiteTemplate,Ui as generateHttpsServerCode,zy as generateImageSbom,Ki as generateLetsEncryptUserData,be as generateLogicalId,Jd as generateManualPipeline,Kd as generateMatrixWorkflow,Qd as generateMultiEnvConfig,Zd as generateMultiEnvPipeline,zd as generateMultiEnvWorkflow,Hd as generatePRPreviewWorkflow,tu as generateParallelConfig,ym as generatePhpFpmConfig,Qp as generatePhpLayerDockerfile,qd as generatePreviewPipeline,wl as generatePreviewWorkflow,Ae as generateResourceName,Xd as generateScheduledConfig,jd as generateScheduledPipeline,Gd as generateScheduledWorkflow,si as generateStaticSiteTemplate,un as generateUbuntuAppCloudInit,Ac as getAccountId,Sd as getAllRegions,$d as getClosestRegion,Xl as getCommandUsage,kf as getComposeTemplate,Fm as getConfig,ql as getContextualHelp,hc as getCredentials,ml as getDeploymentStrategy,fl as getDiffStats,dl as getDiffSummary,Oc as getErrorDetails,Cl as getLocalConfig,bl as getLocalCredentials,Al as getLocalEndpoint,Rl as getLocalEnvVars,Wc as getQuotaUsageSummary,Fd as getRecommendedStructure,Cd as getRegion,wd as getRegionStats,bd as getRegionsByCompliance,Ad as getRegionsByLocation,Rd as getRegionsByPricingTier,Fc as getRequiredPermissions,ba as getSigningKeyCacheSize,Ha as getTimestamp,Un as globMatches,sn as globToRegex,fd as globalResourceManager,yh as governingLimitCents,uu as guardDutyManager,Dy as handleSpendRequest,nn as hasAutoWwwVariant,js as hasManagementDashboardSite,Qr as hasProxyUpstream,qc as hashBuffer,jc as hashDirectory,Uc as hashFile,Jc as hashManifest,Zc as hashString,vm as healthCheckManager,ue as hostAcceptsIpv6,ae as hostCondition,zm as hotp,rh as hourBucket,nh as hourBucketsBetween,Zu as imageScanningManager,gi as infraEnvFromOutputs,mt as inspectInvocation,om as installRecursionFetch,di as invalidateCache,nm as invocationContext,Zl as isLikelyTypo,Sl as isLocalDevelopment,Qs as isManagementDashboardSiteName,Ra as isNodeCryptoAvailable,Ph as isOperationAllowed,$t as isQuietHours,an as isSafePattern,Na as isStatePath,wt as isValidCidr,Td as isValidRegion,Jg as isValidTimeZone,Ta as isWebCryptoAvailable,EC as jobProviderCapability,Vt as keyMatchesFilters,op as lambdaConcurrencyManager,up as lambdaDLQManager,sp as lambdaDestinationsManager,tp as lambdaLayersManager,lp as lambdaVPCManager,np as lambdaVersionsManager,dC as lambdaWorkloads,Sm as laravelServerlessEnvDefaults,Nf as listComposeTemplates,Lg as listSourceReferences,Vm as loadCloudConfig,ry as loadTelemetryPolicy,Du as logsManager,Bh as lookbackHoursForSignal,Fa as mailEnabled,_a as mailFirewallPorts,wS as maintenanceWindowOpen,ga as makeAWSRequest,ya as makeAWSRequestAsync,ha as makeAWSRequestOnce,Ys as managementDashboardSiteName,TS as manifestDigest,Km as matchTotpCounter,vi as mediaObjectHeaders,Ih as median,Dh as medianAbsoluteDeviation,Sh as mergeDecisions,ic as mergeInfrastructure,qg as mergePriceBooks,ch as meterTelemetry,Pu as metricsManager,_t as migrateObjectStorage,vu as migrationManager,Nd as multiAccountManager,cd as multiRegionManager,ji as needsRenewal,km as networkSecurityManager,IC as nextScheduleRuns,Zr as normalizePublicIpv6,iC as normalizeRuntimeStatus,PC as normalizeScheduleExpression,Eg as normalizeSourceEvent,gn as normalizeSshPublicKey,ey as normalizeTelemetryPolicy,Oy as openApiDocument,_h as optionsForSignal,kd as organizationManager,Pm as packagePhpApp,Hp as packageServerlessApp,el as parallel,rl as parallelMap,nl as parallelWithRetry,pt as parseChain,wf as parseCompose,Lf as parseComposeCatalog,uC as parseDockerInspect,eA as parseDotenv,Sa as parseJSONResponse,fC as parseSystemdRecords,Ca as parseXMLResponse,sy as pathTemplate,fh as percentOfLimit,Lu as performanceManager,Yp as phpLayerBuildStage,Jp as phpLayerPackages,Cm as phpRuntimeLayerAssets,Mf as planComposeTemplateUpgrade,Rh as planEnforcement,xt as planMitigation,rr as planZoneMigration,Jt as policyTag,El as previewManager,kl as previewNotifications,DC as previewSchedule,th as previousBudgetWindow,Kg as priceUsage,Ug as priceUsageLines,de as probeOriginTls,cl as processInChunks,wg as processSourceWebhook,Xy as productionChangeReview,bu as progressiveDeploymentManager,mh as projectSpend,gt as propagationHeaders,Bt as providerEndpoint,PS as publicKeyFingerprint,Yt as qualifyName,Fp as queueManagementManager,Yc as quickHash,Jn as rateLimitHeaders,qn as rateLimitKey,jr as reconcileAddressRecords,it as reconcileCloudflareCdn,Xt as reconcileDeclaredRecords,vC as reconcileJobObservation,Mg as reconcileSourceWebhook,Qy as recordDashboardHostPosture,Jy as recordPreDeploySecretScan,Yy as recordSkippedSecretScan,ht as recursionBlockedResponse,oC as redactRuntimeConfig,oy as redactTelemetryText,ay as redactTelemetryValue,Ci as redeployServerlessApp,gd as regionPairManager,pg as releaseStrategyCapabilities,hg as releaseTrafficPlan,Hn as reloadRpxGateway,Ft as remapKey,Fg as removeSourceWebhook,Ur as removeStaleServerAddressRecords,xf as renderComposeTemplate,kt as renderDdosInstallScript,Nt as renderNftablesRuleset,wC as renderServerCron,vt as renderSysctlFile,cn as renderWafConfig,ln as renderWafInstallScript,Gn as renewRpxCertificates,ku as replicaManager,Py as requestHash,ul as requiresReplacement,sm as resetRecursionRuntime,dm as resolveApp,Ma as resolveAppDatabase,tf as resolveAuthEncryptionKey,Wa as resolveCloudProvider,at as resolveCloudflareCdnPlan,Cc as resolveCredentials,$i as resolveDashboardAction,Fn as resolveDashboardAuth,Zs as resolveDashboardDomain,qs as resolveDashboardDomains,Qt as resolveDeclaredRecords,Ja as resolveDeployBucketName,xa as resolveDeploymentMode,vn as resolveExecStart,fn as resolveHetznerApiToken,Va as resolveMailService,ec as resolveManagementDashboardSite,Xs as resolveManagementDashboardSites,Wt as resolveObjectStorage,Ka as resolveProjectStackName,Yr as resolveProxyUpstreams,Zp as resolveQueueNames,Jf as resolveQueuedDeploymentCommand,Up as resolveQueues,im as resolveRecursionConfig,Sc as resolveRegion,AC as resolveRuntimeInventory,Ya as resolveServerlessAppStackName,Qa as resolveServerlessArtifactBucketName,Xa as resolveServerlessAssetBucketName,Kp as resolveServerlessRuntime,qa as resolveSiteBucketName,Xr as resolveSiteDeployTarget,en as resolveSiteKind,Za as resolveSiteResourceName,Ua as resolveSiteStackName,va as resolveStatePath,ja as resolveStorageBucketName,Vn as resolveUiSource,ke as resolveZoneApex,Lm as resourceManagementManager,pm as responseToResult,Eh as robustZScore,df as roleCapabilities,Cg as rollbackImmutableRelease,Si as rollbackServerlessApp,Zg as roundCents,yp as route53ResolverManager,mp as route53RoutingManager,xh as routeMatches,Zn as ruleMatches,Bp as runBuildHooks,Th as runEnforcement,Tm as runPhpBuildHooks,bi as runRemoteCommand,tC as runtimeId,Ri as sanitizeCloudConfig,Af as sanitizeControlPlaneValue,Ga as sanitizeName,rf as sanitizeOidcReturnPath,ny as saveTelemetryPolicy,Ly as scanForSecrets,uf as scopeContains,dh as scopeKey,$n as scpUpload,jl as searchCommands,Rf as searchControlPlane,Wu as secretsManager,_u as secretsRotationManager,eC as secureContainerRelease,mu as securityHubManager,Ku as securityScanningManager,qy as securityScope,Xm as sendAuthenticationEmail,Tp as senderReputationManager,il as sequence,tA as serializeDotenv,On as serverPublicIpv4,Xu as serviceMeshManager,Ai as setMaintenance,Ea as setStateDir,Zi as setupDns01Challenge,Wp as sha256,am as sharedRecursionGuard,em as sharedRuntimeLoop,rn as shipsARelease,Ei as signCloudFrontCookies,Di as signCloudFrontUrl,ua as signRequest,pa as signRequestAsync,Fh as signalDefinition,fy as spendNotificationText,Ey as spendOpenApiPaths,Rn as sshExec,Tn as sshExecOrThrow,hd as stackDependencyManager,Pi as startLocalDashboardServer,Ay as startSpendLoop,wa as stateDir,Oa as statePath,Dm as staticSiteManager,wm as storageAdvancedManager,Gh as streamFocusJsonl,$h as strongestActiveAction,Kl as suggestCommand,Yl as suggestFlags,Vc as suggestIAMPolicy,zc as suggestQuotaIncrease,Id as suggestRegionPairs,Pd as suggestRegions,xg as syncSourceRepositories,cg as synchronizeComposeVolumes,sA as synchronizeConfiguredConfiguration,FC as synchronizeConfiguredJobs,wu as syntheticsManager,Ot as sysctlHardening,gC as systemdWorkloads,dy as telemetryBucketLabel,cy as telemetryCursor,iy as telemetryEstimatedMonthlyCost,ly as telemetryPercentile,ty as telemetryPolicyKey,Kc as templateCache,kg as testSourceConnection,Hg as tieredMicroCents,le as toCloudflareZoneSettings,Hh as toFocusJsonl,zh as toFocusRecords,Hm as totp,Um as totpUri,rC as unsupportedCapabilities,Xf as unsupportedVolumeCapabilities,DS as updateCompatibility,li as uploadStaticFiles,ah as usageDeltaKey,Xg as utcInstantOfLocal,_d as validateAccountStructure,hl as validateAgainstSchema,rg as validateAttachment,LS as validateBackupDestination,ed as validateCommand,kc as validateConfiguration,Lc as validateCredentials,tn as validateDeploymentConfig,tg as validateMountPath,qe as validateResourceLimits,ze as validateTemplate,Ze as validateTemplateSize,Jr as verifyAddressRecord,Zy as verifyArtifactSignature,Oi as verifyMediaAccessToken,Gm as verifyTotp,IS as verifyUpdateSignature,ir as verifyZoneParity,eg as volumeCapabilities,dn as wafEventTelemetry,In as waitForCloudInit,Pn as waitForSsh,Og as webhookEndpoint,lc as withCDN,cc as withCache,sc as withDatabase,lm as withInvocation,oc as withMonitoring,dc as withQueue,ac as withSecurity,ol as withTimeout,hn as wrapCloudInitUserData,Tu as xrayManager,sS as zeroCapacity,Uh as zeroFill,Qg as zoneOffsetMs,Yg as zonedParts};
595
+ `}async function ji(e){let{domain:t,challengeValue:r,hostedZoneId:n,dnsProvider:i,region:l="us-east-1"}=e;if(i){let s=await j(i).upsertRecord(t,{name:`_acme-challenge.${t}`,type:"TXT",content:r,ttl:60});if(!s.success)throw Error(`Failed to create DNS challenge record: ${s.message}`);return}if(n){await new q(l).changeResourceRecordSets({HostedZoneId:n,ChangeBatch:{Comment:"ACME DNS-01 challenge",Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:`_acme-challenge.${t}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${r}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}async function Ji(e){let{domain:t,challengeValue:r,hostedZoneId:n,dnsProvider:i,region:l="us-east-1"}=e;if(i){let s=await j(i).deleteRecord(t,{name:`_acme-challenge.${t}`,type:"TXT",content:r});if(!s.success)console.warn(`Failed to delete DNS challenge record: ${s.message}`);return}if(n){await new q(l).changeResourceRecordSets({HostedZoneId:n,ChangeBatch:{Comment:"Remove ACME DNS-01 challenge",Changes:[{Action:"DELETE",ResourceRecordSet:{Name:`_acme-challenge.${t}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${r}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}function Yi(e){try{let{execSync:t}=Je("node:child_process"),r=t(`openssl x509 -checkend 2592000 -noout -in ${e}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as we,createSign as rt,generateKeyPairSync as Oe}from"node:crypto";var ve={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class nt{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(e){this.directoryUrl=e.staging?ve.staging:ve.production,this.email=e.email,this.accountKey=e.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:e}=Oe("ec",{namedCurve:"P-256"});return e.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let e=await fetch(this.directoryUrl);if(!e.ok)throw Error(`Failed to fetch ACME directory: ${e.status}`);return this.directory=await e.json(),this.directory}async getNonce(){if(this.nonce){let n=this.nonce;return this.nonce=null,n}let e=await this.getDirectory(),r=(await fetch(e.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!r)throw Error("Failed to get nonce from ACME server");return r}getJwk(){let e=this.accountKey.split(`
596
+ `).filter((l)=>!l.startsWith("-----")).join(""),t=Buffer.from(e,"base64"),r=t.length-65,n=t.subarray(r+1,r+33),i=t.subarray(r+33,r+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(n),y:this.base64UrlEncode(i)}}getJwkThumbprint(){let e=this.getJwk(),t=JSON.stringify({crv:e.crv,kty:e.kty,x:e.x,y:e.y}),r=we("sha256").update(t).digest();return this.base64UrlEncode(r)}base64UrlEncode(e){return(typeof e==="string"?Buffer.from(e):e).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(e,t){let r=await this.getNonce(),n=this.getJwk(),i={alg:"ES256",nonce:r,url:e};if(this.accountUrl)i.kid=this.accountUrl;else i.jwk=n;let l=this.base64UrlEncode(JSON.stringify(i)),c=t===""?"":this.base64UrlEncode(JSON.stringify(t)),s=`${l}.${c}`,d=rt("SHA256");d.update(s);let h=d.sign(this.accountKey),u=h.subarray(4,4+h[3]),b=4+h[3]+2,A=h.subarray(b,b+h[b-1]),R=Buffer.alloc(32),y=Buffer.alloc(32);u.copy(R,32-u.length),A.copy(y,32-A.length);let m=Buffer.concat([R,y]);return JSON.stringify({protected:l,payload:c,signature:this.base64UrlEncode(m)})}async acmeRequest(e,t){let r=await this.signPayload(e,t),n=await fetch(e,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:r}),i=n.headers.get("replay-nonce");if(i)this.nonce=i;let l,c=n.headers.get("content-type");if(c?.includes("application/json")||c?.includes("application/problem+json"))l=await n.json();else l=await n.text();if(!n.ok)throw Error(`ACME request failed: ${JSON.stringify(l)}`);return{body:l,headers:n.headers}}async registerAccount(){let e=await this.getDirectory(),{body:t,headers:r}=await this.acmeRequest(e.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),n=r.get("location");if(!n)throw Error("No account URL returned");return this.accountUrl=n,n}async createOrder(e){if(!this.accountUrl)await this.registerAccount();let t=await this.getDirectory(),{body:r,headers:n}=await this.acmeRequest(t.newOrder,{identifiers:e.map((l)=>({type:"dns",value:l}))}),i=n.get("location");if(!i)throw Error("No order URL returned");return{orderUrl:i,authorizations:r.authorizations,finalize:r.finalize}}async getAuthorization(e){let{body:t}=await this.acmeRequest(e,""),r=t.identifier.value,n=this.getJwkThumbprint(),i=t.challenges.filter((l)=>l.type==="http-01"||l.type==="dns-01").map((l)=>{let c=`${l.token}.${n}`;if(l.type==="http-01")return{type:"http-01",token:l.token,keyAuthorization:c,identifier:`/.well-known/acme-challenge/${l.token}`};else{let s=this.base64UrlEncode(we("sha256").update(c).digest());return{type:"dns-01",token:l.token,keyAuthorization:c,identifier:`_acme-challenge.${r}`,dnsValue:s}}});return{domain:r,challenges:i}}async respondToChallenge(e){await this.acmeRequest(e,{})}async waitForAuthorization(e,t=30){for(let r=0;r<t;r++){let{body:n}=await this.acmeRequest(e,"");if(n.status==="valid")return;if(n.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(n)}`);await new Promise((i)=>setTimeout(i,2000))}throw Error("Authorization timed out")}generateCsr(e){let{privateKey:t}=Oe("rsa",{modulusLength:2048}),r=t.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(e,t),privateKey:r}}createSimpleCsr(e,t){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(e,t){let{csr:r,privateKey:n}=this.generateCsr(t),{body:i}=await this.acmeRequest(e,{csr:this.base64UrlEncode(Buffer.from(r,"base64"))}),l=i.certificate;if(!l)throw Error("Certificate not immediately available - polling not implemented");let s=await(await fetch(l)).text(),d=s.split(/(?=-----BEGIN CERTIFICATE-----)/g),h=d[0],u=d.slice(1).join("");return{certificate:h,privateKey:n,chain:u,fullchain:s,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var Ne=["js","mjs","cjs","css","map","woff","woff2","ttf","otf","eot","png","jpg","jpeg","gif","webp","avif","svg","ico","mp4","webm","ogg","mp3","wav","pdf","wasm"];function oe(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`}function ke(e){return`{${e.map(oe).join(" ")}}`}function ae(e){if(e.length===1)return`http.host eq ${oe(e[0])}`;return`http.host in ${ke(e)}`}function se(e,t={}){if(t.enabled===!1||e.length===0)return[];let r=ae(e),n=[],i=t.bypassPaths??[],l=i.length>0?`(${i.map((h)=>`starts_with(http.request.uri.path, ${oe(h)})`).join(" or ")})`:void 0;if(l)n.push({action:"set_cache_settings",description:"bypass cache",expression:`(${r} and ${l})`,enabled:!0,action_parameters:{cache:!1}});let c=l?`${r} and not ${l}`:r,s=t.assetExtensions??Ne,d=s.length>0?`lower(http.request.uri.path.extension) in ${ke([...s])}`:void 0;if(d)n.push({action:"set_cache_settings",description:"cache fingerprinted assets",expression:`(${c} and ${d})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:t.assetEdgeTtl??2592000},browser_ttl:{mode:"override_origin",default:t.assetBrowserTtl??31536000}}});return n.push({action:"set_cache_settings",description:"cache documents",expression:d?`(${c} and not ${d})`:`(${c})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:t.documentEdgeTtl??3600},browser_ttl:{mode:"override_origin",default:t.documentBrowserTtl??0}}}),n}function ce(e,t,r){if(e.length===0||!t||!r)return[];return[{action:"rewrite",description:"origin guard header",expression:`(${ae(e)})`,enabled:!0,action_parameters:{headers:{[t]:{operation:"set",value:r}}}}]}var k=(e)=>e===void 0?void 0:e?"on":"off";function le(e){let t={ssl:e.ssl,always_use_https:k(e.alwaysUseHttps),automatic_https_rewrites:k(e.automaticHttpsRewrites),min_tls_version:e.minTlsVersion,tls_1_3:k(e.tls13),brotli:k(e.brotli),http3:k(e.http3),"0rtt":k(e.zeroRtt),early_hints:k(e.earlyHints),browser_cache_ttl:e.browserCacheTtl,always_online:k(e.alwaysOnline),websockets:k(e.websockets)};if(e.hsts)t.security_header={strict_transport_security:{enabled:e.hsts.enabled,max_age:e.hsts.maxAge??31536000,include_subdomains:e.hsts.includeSubdomains??!1,preload:e.hsts.preload??!1,nosniff:e.hsts.noSniff??!0}};for(let r of Object.keys(t))if(t[r]===void 0)delete t[r];return{...t,...e.raw??{}}}var W={ssl:"strict",alwaysUseHttps:!0,automaticHttpsRewrites:!0,minTlsVersion:"1.2",tls13:!0,brotli:!0,http3:!0,earlyHints:!0,alwaysOnline:!0,browserCacheTtl:0};import{connect as it}from"node:tls";async function de(e){let{address:t,serverName:r,port:n=443,timeoutMs:i=5000}=e;return new Promise((l)=>{let c=!1,s=(h)=>{if(c)return;c=!0;try{d.destroy()}catch{}l(h)},d=it({host:t,port:n,servername:r,rejectUnauthorized:!1,timeout:i});d.once("secureConnect",()=>{if(d.authorized){s({reachable:!0,trusted:!0});return}s({reachable:!0,trusted:!1,reason:d.authorizationError?String(d.authorizationError):"origin certificate is not trusted for this hostname"})}),d.once("timeout",()=>{s({reachable:!1,trusted:!1,reason:`no TLS handshake within ${i}ms`})}),d.once("error",(h)=>{s({reachable:!1,trusted:!1,reason:h.message})})})}async function ot(e){let{provider:t,zone:r,hosts:n,ipv4:i,ipv6:l,proxied:c=!0,settings:s=W,cache:d,originGuard:h,purge:u=!0,ttl:b=300,skipOriginProbe:A=!1}=e,R={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(n.length===0)return R;let y=[];for(let o of n){let g=c;if(c&&!A){let f=await de({address:i,serverName:o});if(!f.trusted){g=!1;let p=f.reason||"origin is not serving a trusted certificate";R.deferredProxy.push({host:o,reason:p}),R.warnings.push(`${o}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${p}). 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(g)y.push(o);let a=[{type:"A",content:i}];if(l&&ue(o))a.push({type:"AAAA",content:l});for(let{type:f,content:p}of a){let C=await t.upsertRecord(r,{name:o,type:f,content:p,ttl:b,proxied:g});if(C.success)R.records.push({host:o,type:f,content:p,proxied:g});else R.warnings.push(`${o} ${f} → ${p} failed: ${C.message||"unknown provider error"}`)}}if(y.length===0){if(c)R.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return R}try{let o=le(s),g=await t.applyZoneSettings(r,o);R.settingsChanged=g.changed;for(let a of g.failed)R.warnings.push(`zone setting '${a.id}' could not be applied: ${a.error}`)}catch(o){R.warnings.push(`zone settings could not be read: ${o instanceof Error?o.message:String(o)}`)}let m=se(y,d);if(m.length>0){let o=await t.putManagedPhaseRules(r,"http_request_cache_settings",m);if(o.success)R.cacheRules=m.length;else R.warnings.push(`cache rules could not be written: ${o.message}`)}if(h){let o=ce(y,h.header,h.value);if(o.length>0){let g=await t.putManagedPhaseRules(r,"http_request_late_transform",o);if(g.success)R.originGuard=!0;else R.warnings.push(`origin guard header could not be written: ${g.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(u){if(R.purged=await t.purgeCache(r,{hosts:y}),!R.purged)R.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return R}var at=(e)=>process.env[e];function xe(e,t){let r=e.replace(/\.$/,"").toLowerCase();if(t){let n=t.replace(/\.$/,"").toLowerCase();if(r===n||r.endsWith(`.${n}`))return n}return r.split(".").slice(-2).join(".")}function st(e,t={}){let r=t.env??at,n=e.infrastructure?.compute?.proxy?.cdn,i=[];if(!n||n.provider!=="cloudflare")return{plan:null,errors:i};if(n.originDomain)i.push(`compute.proxy.cdn.originDomain (${n.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 l=r("CLOUDFLARE_API_TOKEN");if(!l)return i.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:i};let c=e.sites??{},s=n.frontedHosts?.length?[...new Set(n.frontedHosts.map((A)=>A.toLowerCase()))]:pe(c,{autoWww:e.infrastructure?.compute?.proxy?.autoWww!==!1});if(s.length===0)return i.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:i};let d=e.infrastructure?.dns?.domain,h=new Set(s.map((A)=>xe(A,d)));if(h.size>1)return i.push(`Fronted hosts span more than one zone (${[...h].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:i};let u=n.cloudflare??{},b=n.secret?{header:n.secretHeader??"X-Origin-Verify",value:n.secret}:void 0;return{plan:{zone:[...h][0],hosts:s,apiToken:l,zoneId:u.zoneId??r("CLOUDFLARE_ZONE_ID"),accountId:u.accountId??r("CLOUDFLARE_ACCOUNT_ID"),proxied:u.proxied!==!1,settings:u.settings??W,cache:u.cache,originGuard:b,purge:u.purgeOnDeploy!==!1,skipOriginProbe:u.skipOriginProbe===!0},errors:i}}export{Au as ABTestManager,mr as ACMClient,fr as ACMDnsValidator,ve as ACME_DIRECTORIES,M as AI,Df as API_IDEMPOTENCY_TTL_MS,Pf as API_TOKEN_DEFAULT_TTL_MS,If as API_TOKEN_MAX_TTL_MS,vy as API_VERSION,uf as AUTHORIZATION_CAPABILITIES,Ym as AUTH_ACTION_TOKEN_TTL_MS,Qm as AUTH_MFA_CHALLENGE_TTL_MS,Xm as AUTH_OIDC_TRANSACTION_TTL_MS,Jm as AUTH_SESSION_ABSOLUTE_TTL_MS,jm as AUTH_SESSION_IDLE_TTL_MS,Oc as AWSAPIError,Ct as AWSClient,Le as AWSCloudFormationClient,Me as AWSCloudFrontClient,cu as AWSConfigManager,$s as AWS_PSEUDO_PARAMETERS,Sd as AWS_REGIONS,nt as AcmeClient,$t as AlertEvaluator,Tt as AlertStore,Fh as AnomalyConfigStore,Pe as ApiGateway,Iy as ApiServiceError,Wr as ApplicationAutoScalingClient,Ts as Arn,Cs as AssetHasher,hs as Auth,ef as AuthenticationStore,Ey as AutomationApiService,Ef as AutomationIdentityStore,qC as AwsAuroraDataAdapter,XC as AwsAuroraTransport,KS as AwsDatabaseBackupSource,mn as AwsDriver,jC as AwsElastiCacheDataAdapter,eS as AwsElastiCacheTransport,zy as AwsIamCapabilityScanner,eA as AwsInfrastructureBackupSource,ZC as AwsRdsDataAdapter,QC as AwsRdsTransport,RS as AwsRegionalDriver,oA as AwsSecretsManagerConfigurationBackend,Ty as AwsSpendTransport,aA as AwsSsmConfigurationBackend,HS as BackupCoordinator,iu as BackupManager,VS as BackupStore,Mp as BatchProcessingManager,Or as BedrockClient,wr as BedrockRuntimeClient,Dg as BitbucketSourceAdapter,hu as BlueGreenManager,Ap as BounceComplaintHandler,Ju as BuildOptimizationManager,tS as BunDockerRuntime,YS as BunDockerVolumeRuntime,qS as BunFilesystemArchiveRuntime,as as CDN,lt as CHAIN_HEADER,jt as CLOUDFLARE_MANAGED_RULE_PREFIX,Vd as COMMON_CROSS_ACCOUNT_ROLES,lf as CONTROL_PLANE_SCHEMA_VERSION,re as Cache,Cu as CanaryManager,Gu as CertificateManager,lg as CloudBlockVolumeDriver,An as CloudDriverFactory,Pc as CloudError,Ps as CloudFormationBuilder,Le as CloudFormationClient,Me as CloudFrontClient,du as CloudTrailManager,Rr as CloudWatchLogsClient,Jt as CloudflareProvider,ad as CommandHistory,bs as Communication,mg as ComposeApplicationService,pg as ComposeApplicationStore,vr as ComprehendClient,w as Compute,$y as ComputeSpendTransport,Ic as ConfigurationError,cA as ConfigurationService,tA as ConfigurationStore,Tr as ConnectClient,YC as ContainerDataAdapter,Qu as ContainerRegistryManager,XS as ControlPlaneBackupSource,LS as ControlPlaneCleanupDriver,Tf as ControlPlaneStore,lh as CounterTracker,Dc as CredentialError,ud as CrossRegionReferenceManager,Ks as DASHBOARD_ENTRY,Us as DASHBOARD_PORT_BASE,Zs as DASHBOARD_PORT_SPAN,Gs as DASHBOARD_STATE_DIR,ei as DEFAULT_ATTACK_MODE_HOURS,wt as DEFAULT_DDOS_THRESHOLDS,ah as DEFAULT_METER_MAPPINGS,Yg as DEFAULT_PRICE_BOOK,pt as DEFAULT_RECURSION_LIMITS,Wc as DEFAULT_SERVICE_LIMITS,Ea as DEFAULT_STATE_DIR,Ne as DEFAULT_STATIC_ASSET_EXTENSIONS,ty as DEFAULT_TELEMETRY_POLICY,mh as DEFAULT_THRESHOLDS,Yf as DEPLOYMENT_QUEUE_KINDS,ct as DEPTH_HEADER,Vh as DETECTABLE_SIGNALS,$C as DIAGNOSTIC_PRESETS,xp as DLQMonitoringManager,ss as DNS,hp as DNSSECManager,KC as DataServiceLifecycle,HC as DataServiceStore,U as Database,Vu as DatabaseUserManager,xc as DebugLogger,rs as DependencyGraph,ys as Deployment,Ec as DeploymentError,au as DisasterRecoveryManager,ur as DnsProviderFactory,rS as DockerDataTransport,gC as DockerDiscoveryAdapter,sg as DockerNamedVolumeDriver,QS as DockerVolumeBackupSource,Zf as DurableOperationQueue,qf as DurableQueueWorker,Ir as DynamoDBClient,Gt as EC2Client,gr as ECRClient,hr as ECSClient,Kr as EFSClient,$r as ELBv2Client,zg as ENFORCEMENT_ACTIONS,Rh as ENFORCEMENT_DESCRIPTIONS,Hg as ENFORCEMENT_SEVERITY,SC as EcsRuntimeAdapter,Jn as EdgeRateLimiter,_r as ElastiCacheClient,L as Email,Ep as EmailAdvanced,Rp as EmailAnalyticsManager,Rt as EmailClient,wp as EmailHandlers,Ip as EmailTemplateManager,nS as EncryptedDataSecretStore,vc as ErrorCodes,Vr as EventBridgeClient,FC as EventBridgeJobAdapter,sA as ExternalConfigurationBackend,Np as FIFOQueueManager,Hh as FOCUS_VERSION,Kc as FileCache,K as FileSystem,jS as FilesystemBackupSource,cS as FleetService,sS as FleetStore,Rs as Fn,Eg as GiteaSourceAdapter,Pg as GithubSourceAdapter,Ig as GitlabSourceAdapter,pd as GlobalResourceManager,qt as GoDaddyProvider,pu as GuardDutyManager,tl as HashCache,Nm as HealthCheckManager,Dt as HealthCheckRunner,fn as HetznerClient,Cn as HetznerDriver,St as IAMClient,jr as IPV6_EXCLUDED_HOST_LABELS,qu as ImageScanningManager,ze as InfrastructureGenerator,yf as InvalidOperationTransitionError,ds as JobLoader,VC as JobProviderReconciler,BC as JobService,xC as JobStore,Fr as KendraClient,Rm as LARAVEL_SERVERLESS_BUILD_STEPS,br as LambdaClient,ap as LambdaConcurrencyManager,pp as LambdaDLQManager,cp as LambdaDestinationsManager,rp as LambdaLayersManager,AC as LambdaRuntimeAdapter,dp as LambdaVPCManager,ip as LambdaVersionsManager,iA as LocalEncryptedConfigurationBackend,JS as LogicalDatabaseBackupSource,Eu as LogsManager,Up as MANAGED_NODE_VERSIONS,Mn as MANAGEMENT_DASHBOARD_SITE,Qs as MANAGEMENT_DASHBOARD_SITE_PREFIX,Xn as MAX_CONTROL_HOURS,bf as MAX_CONTROL_PLANE_ERROR_BYTES,Af as MAX_CONTROL_PLANE_JSON_BYTES,Wg as METERS,Bg as METER_KEYS,Gg as MICRO_CENTS,Ch as MIN_PROJECTION_CONFIDENCE,NS as MaintenanceService,OS as MaintenanceStore,fs as Messaging,Iu as MetricsManager,Nu as MigrationManager,Pl as MockCloudFormation,Dl as MockDynamoDB,Il as MockS3,Ie as Monitoring,Nd as MultiAccountManager,ld as MultiRegionManager,Gl as MultiStepProgress,Re as Network,xm as NetworkSecurityManager,It as NotificationRouter,Dr as OpenSearchClient,hf as OptimisticConcurrencyError,kd as OrganizationManager,$m as PHP_DEFAULT_EXCLUDES,Yp as PHP_LAYER_EXTENSIONS,Ut as PROXIABLE_RECORD_TYPES,As as ParameterStore,Mu as PerformanceManager,$e as Permissions,Mr as PersonalizeClient,ls as Phone,Op as PhoneAdvanced,cs as PhoneHandlers,pS as PlacementService,uS as PlacementStore,xr as PollyClient,Zt as PorkbunProvider,My as PreDeployScanner,wl as PreviewEnvironmentManager,Jf as PreviewEnvironmentService,jf as PreviewEnvironmentStore,xl as PreviewNotificationService,Hl as ProgressBar,Ru as ProgressiveDeploymentManager,ti as ProtectionControlStore,Ga as Pseudo,te as Queue,Gf as QueueCancellationError,Vp as QueueManagementManager,Ia as QueuePresets,Kf as QueueTimeoutError,Un as RATE_LIMIT_KEY_SEPARATOR,Pr as RDSClient,Md as RECOMMENDED_ACCOUNT_STRUCTURES,Fd as RECOMMENDED_SCPS,bg as RELEASE_QUEUE_KINDS,nd as REPL,od as REPLCommandBuilder,id as REPLContext,cl as RateLimiter,Da as RealtimePresets,ey as RecordingSpendTransport,gt as RecursionGuard,Z as Redirects,md as RegionPairManager,AS as RegionService,SS as RegionStore,os as Registry,Nr as RekognitionClient,yg as ReleaseService,hg as ReleaseStore,mS as RemoteBuildService,xu as ReplicaManager,Mm as ResourceManagementManager,Uf as RetryableOperationError,q as Route53Client,Kt as Route53DomainsClient,tr as Route53Provider,Cp as Route53ResolverManager,fp as Route53RoutingManager,PC as RuntimeOperationService,IC as RuntimeStreamRegistry,zS as S3BackupDestinationAdapter,At as S3Client,Tc as S3Error,Ly as SECRET_PATTERNS,Lh as SENSITIVITY_THRESHOLDS,bt as SESClient,ms as SMS,Sr as SNSClient,by as SPEND_CYCLE_SECONDS,jh as SPEND_GATE_SETTING,Cy as SPEND_LEASE_SETTING,Ar as SQSClient,yr as SSMClient,wa as STATE_DIR_ENV_VAR,W as STATIC_SITE_ZONE_SETTINGS,Ft as STSClient,Br as SchedulerClient,De as Search,By as SecretFindingScanner,Ss as Secrets,zu as SecretsManager,Cr as SecretsManagerClient,Bu as SecretsRotationManager,ee as Security,fu as SecurityHubManager,xy as SecurityPostureStore,_y as SecurityScannerRunner,Uu as SecurityScanningManager,$p as SenderReputationManager,MC as ServerCronJobAdapter,JC as ServerDataAdapter,cg as ServerPathVolumeDriver,ep as ServiceMeshManager,Te as Sftp,Bh as SignalSource,vp as SmsAdvanced,zr as SmsClient,ps as SmsHandlers,Tg as SourceConnectionStore,$g as SourceProviderError,Yh as SpendCapError,Jh as SpendGate,Sy as SpendLoopLease,yy as SpendNotificationRouter,Ay as SpendRunner,Zh as SpendService,fh as SpendStore,Kl as Spinner,oS as SshFleetDriver,fd as StackDependencyManager,us as StacksIntegration,Em as StaticSiteManager,X as Storage,Om as StorageAdvancedManager,Gr as SupportClient,Ou as SyntheticsManager,iS as SystemFleetSshTransport,CC as SystemdDiscoveryAdapter,dt as TRACE_HEADER,Ul as TaskList,my as TelemetryStore,Se as TemplateBuilder,Uc as TemplateCache,kr as TextractClient,Er as TranscribeClient,Lr as TranslateClient,MS as TransportDisasterRecoveryDriver,xS as TransportPlatformMaintenanceDriver,gS as TransportRemoteBuildDriver,Wy as TrivyImageScanner,wf as TsCloudApiError,Of as TsCloudClient,fy as URGENT_SPEND_EVENTS,Th as USER_VISIBLE_ACTIONS,TS as UnavailableRegionalDriver,ar as UnifiedDnsValidator,Cf as UnsupportedSchemaVersionError,wc as ValidationError,Hr as VoiceClient,og as VolumeService,eg as VolumeStore,gs as Workflow,$u as XRayManager,bu as abTestManager,Sg as activateImmutableRelease,cC as ageSeconds,uh as aggregateDeltas,ns as analyzeStackDiff,xh as anomalyOptionsForSignal,ii as applyControlsToDdos,ni as applyControlsToRateLimits,Mt as applyMitigationFactor,ir as applyZoneMigration,Gp as artifactKey,gg as assertReleaseStrategy,Qh as assertSpendAllows,qy as attachProvenanceToRelease,Ky as attachSbomToRelease,Uy as attachVulnerabilitySummary,rf as authEncryptionKeyFile,ff as authorizeOrganization,TC as authorizeRuntimePath,Ql as autocomplete,lu as awsConfigManager,WS as backupCredentialStatus,ou as backupManager,nl as batch,Fp as batchProcessingManager,sf as beginOidcAuthorization,yu as blueGreenManager,bp as bounceComplaintHandler,rh as budgetWindow,gi as buildAndPushServerlessImage,im as buildBunRuntimeLayerZip,Is as buildCloudFormationTemplate,zf as buildComposeLogsCommand,Bf as buildComposeRuntimeCommand,Wf as buildComposeScaleCommand,Hf as buildComposeShellCommand,yi as buildFunctionEnv,Ln as buildHostCleanupScript,za as buildMailEnv,Wn as buildManagementDashboardArtifact,ki as buildMediaCdnPlan,nm as buildNodeRuntimeLayerZip,Yu as buildOptimizationManager,ce as buildOriginGuardRule,Tm as buildPhpRuntimeLayerZip,kn as buildSiteDeployScript,Rn as buildSshArgs,se as buildStaticSiteCacheRules,xn as buildStaticSiteDeployScript,lC as bytes,Su as canaryManager,$S as canonicalJson,oC as capabilities,dS as capacity,fl as categorizeChanges,Ku as certificateManager,Vc as checkIAMPermissions,dm as checkInvocation,zc as checkServiceQuotas,ll as chunk,Ji as cleanupDns01Challenge,Ra as clearSigningKeyCache,xg as cloneSourceBinding,yl as cloudConfigSchema,bn as cloudDrivers,uu as cloudTrailManager,Im as collectPhpAppEntries,Ur as collectServerDnsDomains,ug as completeComposeVolumeDeletion,cf as completeOidcAuthorization,ic as composePresets,_f as composeProjectName,Jp as composeServerlessAppTemplate,Py as compositeSpendTransport,US as compressBackup,Wm as config,GC as connectionGuidance,Xu as containerRegistryManager,Sf as controlPlaneDatabaseFile,df as controlPlaneMigrations,ks as createApiBackendPreset,ky as createApiV1Handler,CS as createAsgBuildDriver,GS as createBackupQueueHandlers,ym as createCliHandler,Sn as createCloudDriver,Ce as createCloudFrontPolicy,Sc as createCredentialProvider,Hs as createDashboardSite,Vs as createDataPipelinePreset,UC as createDataServiceQueueHandlers,Xf as createDeploymentQueueHandlers,j as createDnsProvider,yS as createEcsBuildDriver,Xh as createEnforcementHandlers,kc as createError,vs as createExistingStaticFullStackPreset,aS as createFleetQueueHandlers,Ns as createFullStackAppPreset,cr as createGoDaddyValidator,Cm as createHandlers,gm as createHttpHandler,Ls as createJamstackPreset,WC as createJobQueueHandlers,Ws as createLaravelPreset,_s as createMLApiPreset,kS as createMaintenanceQueueHandlers,Oi as createMediaAccessToken,Ms as createMicroservicesPreset,El as createMockAWS,Es as createNodeJsServerPreset,ws as createNodeJsServerlessPreset,Ht as createObjectStorageClient,sr as createPorkbunValidator,oc as createPreset,ga as createPresignedUrl,ha as createPresignedUrlAsync,hm as createQueueHandler,Fs as createRealtimeAppPreset,bS as createRegionQueueHandlers,Zy as createReleaseProvenance,Rg as createReleaseQueueHandlers,fS as createRemoteBuildQueueHandlers,lr as createRoute53Validator,bC as createRuntimeAdapters,$c as createS3Client,hS as createServerBuildDriver,zs as createServerlessLaravelPreset,Os as createServerlessNodePreset,wg as createSourceAdapter,Ds as createStaticSitePreset,Bs as createTraditionalWebAppPreset,ag as createVolumeQueueHandlers,xs as createWordPressPreset,Bp as createZip,gd as crossRegionReferenceManager,$i as dashboardActions,Fn as dashboardCredentialsFile,zC as dataServiceCapabilities,_u as databaseUserManager,Hm as decodeBase32,ZS as decompressBackup,BS as decryptBackup,Vm as defaultConfig,Sl as defaultLocalConfig,Qn as defaultRateLimitRules,pi as deleteStaticSite,Hn as deployAllComputeSites,Ci as deployServerlessApp,fi as deploySite,zn as deploySiteRelease,li as deployStaticSite,mi as deployStaticSiteFull,ai as deployStaticSiteWithExternalDns,si as deployStaticSiteWithExternalDnsFull,Fa as deploymentCoexistenceError,qs as deriveManagementDashboardPort,ri as describePosture,LC as desiredJobProviderState,Nh as detectAnomalies,La as detectDeploymentTargets,dr as detectDnsProvider,kh as detectLatestAnomaly,Mc as detectMisconfigurations,pa as detectServiceRegion,kf as diffCompose,ul as diffTemplates,kg as discoverGitRefs,af as discoverOidcProvider,dC as discoverRuntimeInventory,Lp as dlqMonitoringManager,pr as dnsProviders,yp as dnssecManager,fC as dockerWorkloads,IS as documentDigest,su as drManager,uC as ecsWorkloads,gf as effectiveCapabilities,Tp as emailAnalyticsManager,Dp as emailTemplateManager,zm as encodeBase32,_S as encryptBackup,Yy as ensureDefaultSecurityPolicies,wn as ensureFirewall,Bn as ensureManagementDashboard,On as ensureServer,En as ensureSshKey,an as escapeSecLang,Ah as evaluateBudget,Et as evaluateTelemetryAlertRules,NC as eventBridgeScheduleInput,mm as eventToRequest,vh as ewma,Nf as exportCompose,rr as exportRoute53Zone,nc as extendPreset,kp as fifoQueueManager,el as findChangedFiles,sh as findMapping,Ug as findPriceEntry,zd as formatAccountStructure,_l as formatBytes,gy as formatCents,is as formatDiff,Bl as formatDuration,ed as formatFlagSuggestions,sd as formatHistory,cd as formatHistoryStats,zl as formatKeyValue,Wl as formatList,Vl as formatProgressBar,wd as formatRegion,Od as formatRegionList,Vy as formatScanResults,ql as formatSuggestion,Ml as formatTable,yh as formatTimeToExhaustion,Fl as formatTree,gc as fromEC2Metadata,hc as fromECSMetadata,mc as fromEnvironment,fc as fromSharedCredentials,yc as fromWebIdentity,ut as functionFingerprint,pe as gatewayHostnames,tm as generateAppImageDockerfile,ru as generateApprovalConfig,Wp as generateBootstrap,Nl as generateCleanupWorkflow,kl as generateCostReportWorkflow,Bd as generateCrossAccountRoleCF,Hy as generateCycloneDxSbom,Xd as generateDeploymentConfig,qd as generateDeploymentPipeline,Hd as generateDeploymentWorkflow,oi as generateExternalDnsStaticSiteTemplate,qi as generateHttpsServerCode,Gy as generateImageSbom,Zi as generateLetsEncryptUserData,be as generateLogicalId,Qd as generateManualPipeline,Zd as generateMatrixWorkflow,eu as generateMultiEnvConfig,jd as generateMultiEnvPipeline,Gd as generateMultiEnvWorkflow,Kd as generatePRPreviewWorkflow,nu as generateParallelConfig,Sm as generatePhpFpmConfig,em as generatePhpLayerDockerfile,Jd as generatePreviewPipeline,vl as generatePreviewWorkflow,Ae as generateResourceName,tu as generateScheduledConfig,Yd as generateScheduledPipeline,Ud as generateScheduledWorkflow,ci as generateStaticSiteTemplate,pn as generateUbuntuAppCloudInit,Rc as getAccountId,bd as getAllRegions,Id as getClosestRegion,td as getCommandUsage,Lf as getComposeTemplate,_m as getConfig,Jl as getContextualHelp,Cc as getCredentials,gl as getDeploymentStrategy,hl as getDiffStats,pl as getDiffSummary,Nc as getErrorDetails,Al as getLocalConfig,Tl as getLocalCredentials,Rl as getLocalEndpoint,$l as getLocalEnvVars,Hc as getQuotaUsageSummary,_d as getRecommendedStructure,Ad as getRegion,vd as getRegionStats,Td as getRegionsByCompliance,Rd as getRegionsByLocation,$d as getRegionsByPricingTier,_c as getRequiredPermissions,Ta as getSigningKeyCacheSize,Ka as getTimestamp,Zn as globMatches,cn as globToRegex,hd as globalResourceManager,Sh as governingLimitCents,mu as guardDutyManager,wy as handleSpendRequest,on as hasAutoWwwVariant,Ys as hasManagementDashboardSite,Xr as hasProxyUpstream,Jc as hashBuffer,Yc as hashDirectory,qc as hashFile,Qc as hashManifest,jc as hashString,km as healthCheckManager,ue as hostAcceptsIpv6,ae as hostCondition,Gm as hotp,ih as hourBucket,oh as hourBucketsBetween,ju as imageScanningManager,hi as infraEnvFromOutputs,ft as inspectInvocation,sm as installRecursionFetch,ui as invalidateCache,om as invocationContext,jl as isLikelyTypo,bl as isLocalDevelopment,ec as isManagementDashboardSiteName,$a as isNodeCryptoAvailable,Dh as isOperationAllowed,Pt as isQuietHours,sn as isSafePattern,xa as isStatePath,Ot as isValidCidr,Pd as isValidRegion,Qg as isValidTimeZone,Pa as isWebCryptoAvailable,OC as jobProviderCapability,_t as keyMatchesFilters,sp as lambdaConcurrencyManager,mp as lambdaDLQManager,lp as lambdaDestinationsManager,np as lambdaLayersManager,up as lambdaVPCManager,op as lambdaVersionsManager,pC as lambdaWorkloads,bm as laravelServerlessEnvDefaults,xf as listComposeTemplates,Fg as listSourceReferences,Bm as loadCloudConfig,iy as loadTelemetryPolicy,wu as logsManager,zh as lookbackHoursForSignal,_a as mailEnabled,Wa as mailFirewallPorts,vS as maintenanceWindowOpen,ya as makeAWSRequest,Sa as makeAWSRequestAsync,Ca as makeAWSRequestOnce,Xs as managementDashboardSiteName,PS as manifestDigest,Zm as matchTotpCounter,Ni as mediaObjectHeaders,Eh as median,wh as medianAbsoluteDeviation,bh as mergeDecisions,ac as mergeInfrastructure,Jg as mergePriceBooks,dh as meterTelemetry,Du as metricsManager,Bt as migrateObjectStorage,ku as migrationManager,xd as multiAccountManager,dd as multiRegionManager,Yi as needsRenewal,Lm as networkSecurityManager,EC as nextScheduleRuns,qr as normalizePublicIpv6,aC as normalizeRuntimeStatus,DC as normalizeScheduleExpression,Og as normalizeSourceEvent,hn as normalizeSshPublicKey,ry as normalizeTelemetryPolicy,Ny as openApiDocument,Wh as optionsForSignal,Ld as organizationManager,Dm as packagePhpApp,Kp as packageServerlessApp,rl as parallel,il as parallelMap,ol as parallelWithRetry,mt as parseChain,vf as parseCompose,Ff as parseComposeCatalog,mC as parseDockerInspect,rA as parseDotenv,ba as parseJSONResponse,hC as parseSystemdRecords,Aa as parseXMLResponse,ly as pathTemplate,hh as percentOfLimit,Fu as performanceManager,Xp as phpLayerBuildStage,Qp as phpLayerPackages,Am as phpRuntimeLayerAssets,Vf as planComposeTemplateUpgrade,$h as planEnforcement,Lt as planMitigation,nr as planZoneMigration,Yt as policyTag,Ol as previewManager,Ll as previewNotifications,wC as previewSchedule,nh as previousBudgetWindow,Zg as priceUsage,qg as priceUsageLines,de as probeOriginTls,dl as processInChunks,vg as processSourceWebhook,tC as productionChangeReview,Tu as progressiveDeploymentManager,gh as projectSpend,ht as propagationHeaders,Wt as providerEndpoint,DS as publicKeyFingerprint,Qt as qualifyName,_p as queueManagementManager,Xc as quickHash,Yn as rateLimitHeaders,jn as rateLimitKey,Jr as reconcileAddressRecords,ot as reconcileCloudflareCdn,er as reconcileDeclaredRecords,kC as reconcileJobObservation,Vg as reconcileSourceWebhook,eC as recordDashboardHostPosture,Qy as recordPreDeploySecretScan,Xy as recordSkippedSecretScan,yt as recursionBlockedResponse,sC as redactRuntimeConfig,sy as redactTelemetryText,cy as redactTelemetryValue,Si as redeployServerlessApp,yd as regionPairManager,fg as releaseStrategyCapabilities,Cg as releaseTrafficPlan,Gn as reloadRpxGateway,Vt as remapKey,_g as removeSourceWebhook,Zr as removeStaleServerAddressRecords,Mf as renderComposeTemplate,xt as renderDdosInstallScript,kt as renderNftablesRuleset,vC as renderServerCron,Nt as renderSysctlFile,ln as renderWafConfig,dn as renderWafInstallScript,Kn as renewRpxCertificates,Lu as replicaManager,Dy as requestHash,ml as requiresReplacement,lm as resetRecursionRuntime,pm as resolveApp,Va as resolveAppDatabase,nf as resolveAuthEncryptionKey,Ha as resolveCloudProvider,st as resolveCloudflareCdnPlan,Ac as resolveCredentials,Pi as resolveDashboardAction,Vn as resolveDashboardAuth,js as resolveDashboardDomain,Js as resolveDashboardDomains,Xt as resolveDeclaredRecords,Qa as resolveDeployBucketName,Ma as resolveDeploymentMode,Nn as resolveExecStart,gn as resolveHetznerApiToken,Ba as resolveMailService,rc as resolveManagementDashboardSite,tc as resolveManagementDashboardSites,zt as resolveObjectStorage,Za as resolveProjectStackName,Qr as resolveProxyUpstreams,jp as resolveQueueNames,Qf as resolveQueuedDeploymentCommand,qp as resolveQueues,am as resolveRecursionConfig,bc as resolveRegion,RC as resolveRuntimeInventory,Xa as resolveServerlessAppStackName,es as resolveServerlessArtifactBucketName,ts as resolveServerlessAssetBucketName,Zp as resolveServerlessRuntime,Ja as resolveSiteBucketName,en as resolveSiteDeployTarget,tn as resolveSiteKind,ja as resolveSiteResourceName,qa as resolveSiteStackName,ka as resolveStatePath,Ya as resolveStorageBucketName,_n as resolveUiSource,xe as resolveZoneApex,Fm as resourceManagementManager,fm as responseToResult,Oh as robustZScore,pf as roleCapabilities,Ag as rollbackImmutableRelease,Ai as rollbackServerlessApp,jg as roundCents,Sp as route53ResolverManager,gp as route53RoutingManager,Mh as routeMatches,qn as ruleMatches,zp as runBuildHooks,Ph as runEnforcement,Pm as runPhpBuildHooks,Ri as runRemoteCommand,nC as runtimeId,Ti as sanitizeCloudConfig,Rf as sanitizeControlPlaneValue,Ua as sanitizeName,of as sanitizeOidcReturnPath,oy as saveTelemetryPolicy,Fy as scanForSecrets,mf as scopeContains,ph as scopeKey,Pn as scpUpload,Yl as searchCommands,$f as searchControlPlane,Hu as secretsManager,Wu as secretsRotationManager,rC as secureContainerRelease,gu as securityHubManager,Zu as securityScanningManager,Jy as securityScope,tf as sendAuthenticationEmail,Pp as senderReputationManager,al as sequence,nA as serializeDotenv,vn as serverPublicIpv4,tp as serviceMeshManager,bi as setMaintenance,Oa as setStateDir,ji as setupDns01Challenge,Hp as sha256,cm as sharedRecursionGuard,rm as sharedRuntimeLoop,nn as shipsARelease,wi as signCloudFrontCookies,Ei as signCloudFrontUrl,ma as signRequest,fa as signRequestAsync,_h as signalDefinition,hy as spendNotificationText,Oy as spendOpenApiPaths,Tn as sshExec,$n as sshExecOrThrow,Cd as stackDependencyManager,Ii as startLocalDashboardServer,Ry as startSpendLoop,va as stateDir,Na as statePath,wm as staticSiteManager,vm as storageAdvancedManager,Uh as streamFocusJsonl,Ih as strongestActiveAction,Zl as suggestCommand,Xl as suggestFlags,Bc as suggestIAMPolicy,Gc as suggestQuotaIncrease,Ed as suggestRegionPairs,Dd as suggestRegions,Mg as syncSourceRepositories,dg as synchronizeComposeVolumes,lA as synchronizeConfiguredConfiguration,_C as synchronizeConfiguredJobs,vu as syntheticsManager,vt as sysctlHardening,yC as systemdWorkloads,py as telemetryBucketLabel,dy as telemetryCursor,ay as telemetryEstimatedMonthlyCost,uy as telemetryPercentile,ny as telemetryPolicyKey,Zc as templateCache,Lg as testSourceConnection,Kg as tieredMicroCents,le as toCloudflareZoneSettings,Kh as toFocusJsonl,Gh as toFocusRecords,Km as totp,qm as totpUri,iC as unsupportedCapabilities,tg as unsupportedVolumeCapabilities,wS as updateCompatibility,di as uploadStaticFiles,ch as usageDeltaKey,th as utcInstantOfLocal,Wd as validateAccountStructure,Cl as validateAgainstSchema,ig as validateAttachment,FS as validateBackupDestination,rd as validateCommand,Lc as validateConfiguration,Fc as validateCredentials,rn as validateDeploymentConfig,ng as validateMountPath,je as validateResourceLimits,He as validateTemplate,qe as validateTemplateSize,Yr as verifyAddressRecord,jy as verifyArtifactSignature,vi as verifyMediaAccessToken,Um as verifyTotp,ES as verifyUpdateSignature,or as verifyZoneParity,rg as volumeCapabilities,un as wafEventTelemetry,Dn as waitForCloudInit,In as waitForSsh,Ng as webhookEndpoint,uc as withCDN,dc as withCache,lc as withDatabase,um as withInvocation,sc as withMonitoring,pc as withQueue,cc as withSecurity,sl as withTimeout,yn as wrapCloudInitUserData,Pu as xrayManager,lS as zeroCapacity,qh as zeroFill,eh as zoneOffsetMs,Xg as zonedParts};