@stacksjs/ts-cloud 0.16.52 → 0.16.54

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 (199) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/{chunk-z06jkvvr.js → chunk-0xfy78nc.js} +4 -4
  3. package/dist/bin/chunk-1cccv502.js +1 -0
  4. package/dist/bin/{chunk-n5kdne4p.js → chunk-1q6wqzh1.js} +3 -3
  5. package/dist/bin/{chunk-ddyd6f14.js → chunk-28124w0n.js} +2 -2
  6. package/dist/bin/{chunk-ppd463ev.js → chunk-3mhzd931.js} +1 -1
  7. package/dist/bin/{chunk-q2rqmc2x.js → chunk-4crz28b9.js} +1 -1
  8. package/dist/bin/chunk-5s91mpty.js +1 -0
  9. package/dist/bin/chunk-6sfn8fjv.js +1 -0
  10. package/dist/bin/chunk-6tdt3ea9.js +1 -0
  11. package/dist/bin/{chunk-dv2he3vc.js → chunk-7cactd6c.js} +2 -2
  12. package/dist/bin/{chunk-2wh45zhk.js → chunk-7p70c4br.js} +2 -2
  13. package/dist/bin/{chunk-93yw46n7.js → chunk-8fh0gv4q.js} +1 -1
  14. package/dist/bin/chunk-8nfrknq3.js +1 -0
  15. package/dist/bin/{chunk-0wtshht7.js → chunk-95djv2ja.js} +1 -1
  16. package/dist/bin/chunk-9de905c6.js +1 -0
  17. package/dist/bin/{chunk-te52z1wk.js → chunk-9t78j764.js} +1 -1
  18. package/dist/bin/chunk-a4z8b18n.js +1 -0
  19. package/dist/bin/chunk-apqyj6gr.js +1 -0
  20. package/dist/bin/chunk-bn2sn094.js +1 -0
  21. package/dist/bin/chunk-bzbah8jm.js +1 -0
  22. package/dist/bin/chunk-bzpeqh5z.js +1 -0
  23. package/dist/bin/{chunk-mcg4wg4j.js → chunk-bzzwbkrx.js} +4 -4
  24. package/dist/bin/{chunk-f78wmcvb.js → chunk-cdseg15k.js} +2 -2
  25. package/dist/bin/{chunk-wv8060cw.js → chunk-dg8ceycc.js} +5 -5
  26. package/dist/bin/chunk-e0d34gcp.js +1 -0
  27. package/dist/bin/chunk-e3zsrpbj.js +1 -0
  28. package/dist/bin/{chunk-t970yjvz.js → chunk-ek27709c.js} +5 -5
  29. package/dist/bin/chunk-erdz4875.js +1 -0
  30. package/dist/bin/chunk-et6hzqpx.js +1 -0
  31. package/dist/bin/{chunk-0e9yddgc.js → chunk-gqyfa360.js} +60 -60
  32. package/dist/bin/{chunk-ngmewar1.js → chunk-hkx5j0bn.js} +3 -3
  33. package/dist/bin/chunk-hrg9ygbz.js +1 -0
  34. package/dist/bin/{chunk-fjbhvhqb.js → chunk-hzc049ns.js} +1 -1
  35. package/dist/bin/{chunk-rwbdtxte.js → chunk-jvbe549p.js} +1 -1
  36. package/dist/bin/{chunk-5c4xh61a.js → chunk-jxm62h8r.js} +16 -16
  37. package/dist/bin/{chunk-a7hhzbvm.js → chunk-jyvr7eh5.js} +3 -3
  38. package/dist/bin/{chunk-cjagqdk3.js → chunk-k1kk78qg.js} +5 -5
  39. package/dist/bin/chunk-kj1e4xvg.js +1 -0
  40. package/dist/bin/{chunk-811k54jq.js → chunk-kqd186ky.js} +2 -2
  41. package/dist/bin/{chunk-we2raqk3.js → chunk-mdcv2vw1.js} +2 -2
  42. package/dist/bin/{chunk-da6dmacg.js → chunk-n2jh5p5x.js} +2 -2
  43. package/dist/bin/chunk-n6hngvvb.js +1 -0
  44. package/dist/bin/chunk-n9aeark7.js +1 -0
  45. package/dist/bin/{chunk-7czb1kgg.js → chunk-nva480hg.js} +2 -2
  46. package/dist/bin/{chunk-yfa84s0c.js → chunk-p23wfy3r.js} +1 -1
  47. package/dist/bin/{chunk-ytzcsskk.js → chunk-p6qa21fr.js} +2 -2
  48. package/dist/bin/chunk-pexjxc5g.js +1 -0
  49. package/dist/bin/{chunk-sa9c8vb5.js → chunk-pr5c0q0k.js} +5 -5
  50. package/dist/bin/{chunk-m3xap663.js → chunk-q0takzyx.js} +4 -4
  51. package/dist/bin/{chunk-hhmqsrfc.js → chunk-rbyrd9we.js} +1 -1
  52. package/dist/bin/{chunk-45thdtvf.js → chunk-rqvrjp8g.js} +36 -36
  53. package/dist/bin/chunk-s98wngxx.js +1 -0
  54. package/dist/bin/{chunk-83brtkvn.js → chunk-sbate1ky.js} +1 -1
  55. package/dist/bin/{chunk-5ny7rggt.js → chunk-sy4zws71.js} +1 -1
  56. package/dist/bin/chunk-t2ec6d8h.js +1 -0
  57. package/dist/bin/{chunk-fhe0mdjg.js → chunk-tbp1gf1p.js} +1 -1
  58. package/dist/bin/{chunk-734n0gkw.js → chunk-v0g82agx.js} +1 -1
  59. package/dist/bin/{chunk-f0vedy45.js → chunk-v9js2b1d.js} +1 -1
  60. package/dist/bin/chunk-z3f0k8jt.js +740 -0
  61. package/dist/bin/{chunk-33ntxz01.js → chunk-z6xnegpe.js} +3 -3
  62. package/dist/bin/cli.js +239 -239
  63. package/dist/bin/dashboard-server.js +1 -1
  64. package/dist/{chunk-rjaa4epz.js → chunk-07z9bps2.js} +90 -90
  65. package/dist/{chunk-qcv4twc6.js → chunk-184bvh5s.js} +19 -19
  66. package/dist/chunk-27ny16g8.js +1 -0
  67. package/dist/{chunk-pz33w7gv.js → chunk-2hma3g5q.js} +2 -2
  68. package/dist/chunk-2n3c5axm.js +1 -0
  69. package/dist/{chunk-6gnmrtp9.js → chunk-430acqjk.js} +19 -19
  70. package/dist/chunk-5yrabpmr.js +1 -0
  71. package/dist/{chunk-9ggg2ktx.js → chunk-7ag4wc74.js} +2 -2
  72. package/dist/{chunk-thdfk76k.js → chunk-80bgb48v.js} +2 -2
  73. package/dist/{chunk-8b2mxhcm.js → chunk-94z7s8ky.js} +5 -5
  74. package/dist/{chunk-6m8p1n88.js → chunk-a99wz633.js} +12 -12
  75. package/dist/{chunk-x4qye2rc.js → chunk-apj1eqcy.js} +4 -4
  76. package/dist/chunk-b11w48de.js +464 -0
  77. package/dist/chunk-bg89ad2e.js +1 -0
  78. package/dist/{chunk-erfh93dq.js → chunk-c482jhc6.js} +2 -2
  79. package/dist/{chunk-zf5wdx6v.js → chunk-d245va6b.js} +1 -1
  80. package/dist/{chunk-ca191b00.js → chunk-e42gpavb.js} +5 -5
  81. package/dist/chunk-e5xg3p1x.js +1 -0
  82. package/dist/{chunk-ffyx50xx.js → chunk-gmtds745.js} +1 -1
  83. package/dist/{chunk-p101nhg2.js → chunk-hybz2q8w.js} +4 -4
  84. package/dist/{chunk-j99nkav5.js → chunk-jyvnfny6.js} +3 -3
  85. package/dist/{chunk-4abbccq7.js → chunk-mp2y4t6w.js} +1 -1
  86. package/dist/{chunk-jytama4e.js → chunk-nhsefr22.js} +5 -5
  87. package/dist/{chunk-3ncnrrvm.js → chunk-qjp3f5y8.js} +7 -7
  88. package/dist/{chunk-0qgfe5ff.js → chunk-qyr5hn6v.js} +3 -3
  89. package/dist/{chunk-m9r0a1v9.js → chunk-smt4t6rc.js} +2 -2
  90. package/dist/{chunk-0cz2s19h.js → chunk-stc3ykm3.js} +2 -2
  91. package/dist/{chunk-4yqd62rd.js → chunk-v4vz0e85.js} +1 -1
  92. package/dist/{chunk-qcj3hkba.js → chunk-vgtqd3sb.js} +1 -1
  93. package/dist/{chunk-r5mk071y.js → chunk-wbbbpt4v.js} +5 -5
  94. package/dist/chunk-xfced13z.js +1 -0
  95. package/dist/{chunk-jtvw9d4x.js → chunk-y7k5872m.js} +1 -1
  96. package/dist/{chunk-xgc6hskd.js → chunk-yt8qgn5d.js} +6 -6
  97. package/dist/{chunk-prtvb2fh.js → chunk-zvcd6x45.js} +83 -83
  98. package/dist/deploy/index.js +1 -1
  99. package/dist/dns/index.js +1 -1
  100. package/dist/drivers/hetzner/client.d.ts +30 -0
  101. package/dist/drivers/hetzner/driver.d.ts +3 -2
  102. package/dist/drivers/hetzner/volumes.d.ts +9 -0
  103. package/dist/drivers/index.d.ts +4 -0
  104. package/dist/drivers/index.js +1 -1
  105. package/dist/drivers/shared/compute-storage-agent.d.ts +3 -0
  106. package/dist/drivers/shared/compute-storage.d.ts +21 -0
  107. package/dist/drivers/shared/notifications.d.ts +3 -1
  108. package/dist/index.d.ts +1 -1
  109. package/dist/index.js +19 -19
  110. package/dist/mail/index.js +2 -2
  111. package/dist/operations/index.js +1 -1
  112. package/dist/protection/index.js +1 -1
  113. package/dist/spend/index.js +1 -1
  114. package/dist/ui/404.html +1 -1
  115. package/dist/ui/accept-invitation.html +1 -1
  116. package/dist/ui/access-denied.html +1 -1
  117. package/dist/ui/account/automation.html +5 -5
  118. package/dist/ui/account/security.html +2 -2
  119. package/dist/ui/applications/compose.html +6 -6
  120. package/dist/ui/applications/new.html +2 -2
  121. package/dist/ui/data/backups.html +6 -6
  122. package/dist/ui/data/services.html +6 -6
  123. package/dist/ui/data/volumes.html +5 -5
  124. package/dist/ui/index.html +6 -6
  125. package/dist/ui/infrastructure/topology.html +5 -5
  126. package/dist/ui/integrations.html +1 -1
  127. package/dist/ui/operations/alerts.html +6 -6
  128. package/dist/ui/operations/configuration.html +6 -6
  129. package/dist/ui/operations/jobs.html +6 -6
  130. package/dist/ui/operations/maintenance.html +6 -6
  131. package/dist/ui/operations/observability.html +5 -5
  132. package/dist/ui/operations/previews.html +6 -6
  133. package/dist/ui/operations/queue.html +6 -6
  134. package/dist/ui/operations/regions.html +6 -6
  135. package/dist/ui/operations/releases.html +6 -6
  136. package/dist/ui/operations/spend.html +6 -6
  137. package/dist/ui/operations/workloads.html +6 -6
  138. package/dist/ui/security.html +2 -2
  139. package/dist/ui/server/actions.html +6 -6
  140. package/dist/ui/server/activity.html +1 -1
  141. package/dist/ui/server/capacity.html +6 -6
  142. package/dist/ui/server/database.html +5 -5
  143. package/dist/ui/server/deployments.html +6 -6
  144. package/dist/ui/server/diagnostics.html +2 -2
  145. package/dist/ui/server/firewall.html +6 -6
  146. package/dist/ui/server/fleet.html +6 -6
  147. package/dist/ui/server/logs.html +6 -6
  148. package/dist/ui/server/metrics.html +7 -7
  149. package/dist/ui/server/security.html +1 -1
  150. package/dist/ui/server/services.html +1 -1
  151. package/dist/ui/server/sites.html +6 -6
  152. package/dist/ui/server/ssh-keys.html +6 -6
  153. package/dist/ui/server/team.html +6 -6
  154. package/dist/ui/server/terminal.html +2 -2
  155. package/dist/ui/serverless/alarms.html +6 -6
  156. package/dist/ui/serverless/assets.html +2 -2
  157. package/dist/ui/serverless/cost.html +2 -2
  158. package/dist/ui/serverless/data.html +6 -6
  159. package/dist/ui/serverless/deployments.html +2 -2
  160. package/dist/ui/serverless/firewall.html +1 -1
  161. package/dist/ui/serverless/functions.html +5 -5
  162. package/dist/ui/serverless/logs.html +6 -6
  163. package/dist/ui/serverless/metrics.html +2 -2
  164. package/dist/ui/serverless/queues.html +5 -5
  165. package/dist/ui/serverless/secrets.html +5 -5
  166. package/dist/ui/serverless/traces.html +6 -6
  167. package/dist/ui/serverless.html +6 -6
  168. package/dist/ui-src/pages/server/metrics.stx +9 -0
  169. package/package.json +3 -3
  170. package/dist/bin/chunk-20dp8658.js +0 -1
  171. package/dist/bin/chunk-334jngt2.js +0 -1
  172. package/dist/bin/chunk-3k7y1h18.js +0 -1
  173. package/dist/bin/chunk-626npmtj.js +0 -1
  174. package/dist/bin/chunk-67vf8myy.js +0 -1
  175. package/dist/bin/chunk-74wppexz.js +0 -1
  176. package/dist/bin/chunk-87g6jcfm.js +0 -1
  177. package/dist/bin/chunk-8ya34jz7.js +0 -1
  178. package/dist/bin/chunk-964xmgb6.js +0 -1
  179. package/dist/bin/chunk-9qdrv6zp.js +0 -1
  180. package/dist/bin/chunk-azarn24c.js +0 -1
  181. package/dist/bin/chunk-dpk5r544.js +0 -1
  182. package/dist/bin/chunk-f578z20t.js +0 -1
  183. package/dist/bin/chunk-f9469h6q.js +0 -1
  184. package/dist/bin/chunk-g6ph425d.js +0 -1
  185. package/dist/bin/chunk-k6g1c681.js +0 -1
  186. package/dist/bin/chunk-m7pbssep.js +0 -1
  187. package/dist/bin/chunk-n7xadeqe.js +0 -1
  188. package/dist/bin/chunk-nxvtya6v.js +0 -724
  189. package/dist/bin/chunk-p6wxv8yq.js +0 -1
  190. package/dist/bin/chunk-vpt43nwa.js +0 -1
  191. package/dist/bin/chunk-wgh66c5r.js +0 -1
  192. package/dist/bin/chunk-zywk12mp.js +0 -1
  193. package/dist/chunk-09d6pdgx.js +0 -1
  194. package/dist/chunk-21mmcmm7.js +0 -1
  195. package/dist/chunk-2gqm2h84.js +0 -1
  196. package/dist/chunk-ggtsfsxx.js +0 -448
  197. package/dist/chunk-jgsey18z.js +0 -1
  198. package/dist/chunk-qbsrs1gp.js +0 -1
  199. package/dist/chunk-tnqj2en4.js +0 -1
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{EI,vI,qd,nm,jd,zd,sn,Q,l,Kd,im,K,Wd,g,HA,b,Xe,Hi,on,w,be,Jd,GA,r,t,TI,wI,p,RI,DI,PI,NI,kI,sr,Xd,Gi,VA,BI,xI,xe,Ye,Yd,sm,om,OI,am,cm,dm,Bo,Zd,ce,an,Tt,xo,wt,Ce,qA,el,Oo,lm,um,gm,pm,tl,_I,W,C,jA,zA,mm,a,y,Ze,m,fm,et,J,Rt,LI,hm,X,rl,Oe,or,_o,de,nl,le,KA,Lo,Y,Z,_,Vi,D,ar,Dt,ee,e,cn,$I,Am,il,MI,FI,UI,QI,sl,HI,GI,VI,qI,jI,zI,KI,WI,JI,XI,YI,ZI,WA,JA,XA,YA,ZA,ey,ty,cr,ym,Sm,dr,qi,eb,Im,tb,rb,dn,nb,ib,sb,ob,ab,cb,ry,ny,iy,sy,oy,ji,db,$o,ay,bm,V,cy,tt,Mo,Pt,dy,Cm,ly,uy,gy,Em,q,lb,ub,gb,pb,py,mb,te,fb,hb,Ab,ol,al,my,vm,Tm,yb,Sb,Ib,bb,Cb,fy,cl,Eb,vb,Tb,wb,Rb,hy,Ay,Db,Pb,Nb,kb,Bb,xb,Ob,yy,_b,wm,dl,Lb,$b,Mb,Fb,Rm,Dm,Pm,Ub,ll,Sy,Iy,by,Cy,ul,Ey,Qb,Hb,Gb,Vb,qb,jb,zb,vy,Ty,wy,Ry,Nm,Kb,Wb,Jb,Xb,Yb,Zb,eC,tC,rC,Dy,Py,Ny,ky,nC,iC,km,sC,Bm,xm,Om,_m,oC,aC,cC,dC,_e,zi,lC,uC,gC,pC,mC,fC,hC,AC,By,yC,SC,Lm,$m,IC,bC,xy,CC,EC,vC,TC,wC,RC,DC,PC,NC,kC,BC,xC,OC,_C,LC,$C,MC,FC,UC,QC,HC,gl,Oy,pl,_y,ml,Ly,fl,$y,hl,My,lr,Fy,Al,Uy,Ki,Qy,yl,Hy,Sl,Gy,Mm,GC,Fm,VC,Il,Vy,ur,qy,Um,qC,bl,jy,Qm,jC,Hm,zC,Gm,KC,Cl,zy,Vm,WC,qm,JC,jm,XC,zm,YC,El,Ky,vl,Wy,Km,ZC,Wm,eE,Jm,tE,Xm,rE,Ym,nE,Zm,iE,Tl,Jy,ef,sE,tf,oE,rf,aE,nf,cE,sf,dE,of,lE,af,cf,df,lf,uf,uE,gf,gE,pf,pE,mf,mE,rt,ff,Xy,Fo,wl,ln,Yy,Wi,gr,Rl,Dl,Zy,eS,Pl,hf,Nl,Af,fE,hE,Uo,Qo,Ho,kl,un,Bl,xl,Ji,Go,Vo,yf,tS,rS,nS,AE,Sf,If,yE,iS,bf,sS,oS,aS,SE,Cf,gn,Ol,Ef,IE,cS,qo,jo,_l,vf,bE,Ll,dS,Tf,CE,wf,EE,Rf,vE}from"./chunk-prtvb2fh.js";import{$l,N,Ml,zo,lS,Df,uS,gS,pS,mS,fS,hS,AS,yS}from"./chunk-6m8p1n88.js";import{Zo,Pf,ql,CS,es,jl,ea,Nf,kf,mn,ta,zl,it,Kl,Wl,Jl,ts,fn,Bf,st,Xl,ra,na,ia,Yl,Zl,eu,rs,sa,tu,hn,ns,oa,Nt,xf,ru,nu,Of,iu,aa,pr,su,ou,au,cu,ot,_f,du,mr,ca,da,la,is,ss,An,lu,os,ua,ga,yn,uu,Sn,Lf,$f,kt,In,pa,Mf,gu,pu,ma,mu,fu,hu,ES,ue,Au,vS,TS,as,cs,wS,Ee,Ff,Bt,Le,$e,xt,yu,Su,Iu,bu,Uf,Qf,fa,Hf,Gf,ha,Cu,Eu,Vf,ge,qf,vu,ve,Aa,at,Ot,_t,bn,ds,Tu,RS,jf,zf,Kf,Wf,ya,Sa,wu,Ia,Cn,ba,Ru,ls,Du,Ca,Ea,va,Ta,wa,Ra,Da,Pa,Pu,fr,Na,Nu,En,ku,ka,Ba,Bu,hr,xa,Oa,Jf,DS,us,PS,NS,kS,_a,La,xu,Xf,$a,vn,Ou,gs,_u,Lu,$u,Ma,Yf,Fa,Mu,Zf,Ua,eh,Tn,wn,Fu,ps,qu,Wu,Ju,Xu,Yu,Zu,fs,Ar,Ha,Rn,Dn,yr,ct,ch,Va,dh,lh,rg,qa,As,ng,ja,$t,Fe,ig,za,Ka,sg,Wa,Ja,Xa,Ya,og,ag,Nn,Za,ec,tc,rc,cg,ys,kn,Ss,nc}from"./chunk-rjaa4epz.js";import{U,Vr,od,oo,d,kp,Bp}from"./chunk-pz33w7gv.js";import{It,sd,Ti,wi,Ri,Np}from"./chunk-x4qye2rc.js";import{Hh,Gh,Vh,up,gp,pp,qh,mp,fp,jh,zh,hp,Kh,Wh,nd,Ap,Jh,Xh,yp,Yh,Zh,eA,tA,rA,nA,iA,vi,id,Sp,Ip,bp,Cp,Ep,vp,Tp,wp,Rp,Dp,Pp,sA,oA,aA,cA,dA,lA,uA}from"./chunk-qcv4twc6.js";import{Ke,ad,Ie,Yt,cd,x,Zt,bt,dd,ao,mA,xp,ld,s,Di,co,qr,ud,gd,jr,fA,pd,SI,II,lo,bI,CI,md,fd,Pi,uo,ae,c,go,We,zr,hA,AA,hd,yA,po,SA,IA,mo,Ad,Kr,fo,bA,er,yd,Op,tr,Wr,CA,ho,EA,O,vA,Sd,_p,Ao,TA,wA,RA,Id,Ni,yo,bd,rr,Ct,DA,Jr,PA,Cd,Lp,$p,So,Ed,vd,Et,Mp,ki,Td,Io,Xr,Fp,Bi,wd,Rd,xi,Up,Dd,Pd,Nd,kd,bo,Qp,Hp,NA,Gp,Bd,Oi,Vp,qp,Co,Yr,Eo,vo,To,xd,jp,Od,wo,kA,nr,BA,_d,Zr,Ld,xA,$d,zp,_i,en,Ro,Li,Je,OA,Kp,Wp,ir,Md,Fd,Ud,$i,Mi,Fi,_A,LA,vt,Do,$A,tn,Jp,Po,MA,Xp,Yp,Zp,FA,em,tm,UA,i,QA,Ui,No,ko}from"./chunk-6gnmrtp9.js";import{n}from"./chunk-ca191b00.js";import{Re,gt,Gn}from"./chunk-0qgfe5ff.js";import{o}from"./chunk-j99nkav5.js";import{Te,ws,Rs,ug,cc,dc,Ds,lc,dt,re,lt,pe,v,we,_n,uc,Ue,gc,Ln,$n,Mn,Mt,Ft,Ut,Un,Ir,pc,br,Cr,ut,Qn,fc,Qt,Er,Hn,Ac,hg,Ag,yc,vr}from"./chunk-jytama4e.js";import{pt,he,Ge,yg,Ht,Ic,bc,Gt,H,Vn,Vt,qt,qn,Bs,xs,Tr,wr,jn,Rr,Os,_s,Ls,$s,ie,Ms,Fs,Us,Qs,Ae,Hs,Gs,Vs,k,Cc,zn,Ec,ye,Dr}from"./chunk-m9r0a1v9.js";import{ne}from"./chunk-4abbccq7.js";import{Sg,vc,Ig,De,Tc,Kn,bg,wc,Cg,Eg,Eh,Jn,js,M,Br,Xn,xr,Se,Rc,Yn,Dc,_r,ei,zs,ti,ri,ni,ii,Lr,xc,Ve,se,qe,je,ft,Pe,$r,Ne,ai,ci,di,li,ui,gi,pi,Mr,F,Js,Kg,Uc,fi,hi,Ai,yi,zc,Xs,Kc,Jt,Si,Ys,Zs,Wc,Ii,Jc}from"./chunk-ggtsfsxx.js";import{to,no,io,B,ke}from"./chunk-xgc6hskd.js";import{Fl,Ko,Xi,Yi,Wo,Ul,Ql,Zi,Jo,Xo,Gl,Vl,Yo}from"./chunk-ffyx50xx.js";import{ic,Bn,xn,Is,bs,Cs,Es,sc,oc}from"./chunk-8b2mxhcm.js";import{ac}from"./chunk-p101nhg2.js";import{Sc,Qe,S}from"./chunk-0cz2s19h.js";import{He}from"./chunk-qcj3hkba.js";import{I}from"./chunk-jtvw9d4x.js";import{oe,bi,eo,Xc,Ci,sp}from"./chunk-r5mk071y.js";import{Ur,Be}from"./chunk-thdfk76k.js";import{h}from"./chunk-zf5wdx6v.js";import{Qd,rn,Hd,Gd,Vd,Qi,rm,nn}from"./chunk-3ncnrrvm.js";import{SS,nt}from"./chunk-erfh93dq.js";var Uh="https://api.machines.dev/v1";class Ws extends Error{status;path;constructor(u,f,R){super(u);this.status=f;this.path=R;this.name="FlyApiError"}}function Qc(u){let f=u.ip.includes(":");if(f&&u.ip.startsWith("fdaa:"))return"private_v6";if(u.shared)return"shared_v4";return f?"v6":"v4"}class mg{token;fetch;constructor(u){if(!u.token)throw Error("Fly.io needs an API token: set FLY_API_TOKEN (`fly tokens create deploy` makes one scoped to an app).");this.token=u.token,this.fetch=u.fetch??fetch}async rest(u,f,R={}){let A=new URL(`https://api.machines.dev/v1${f}`);for(let[L,z]of Object.entries(R.query??{}))A.searchParams.set(L,z);let T=await this.fetch(A,{method:u,headers:{Authorization:`Bearer ${this.token}`,...R.body!==void 0?{"Content-Type":"application/json"}:{},...R.headers},body:R.body===void 0?void 0:JSON.stringify(R.body)});if(T.status===404&&R.notFound==="null")return null;let E=await T.text(),P=E?gg(E):void 0;if(!T.ok){let L=typeof P==="object"&&P&&"error"in P?String(P.error):E||T.statusText;throw new Ws(`Fly.io ${u} ${f} failed (${T.status}): ${L}`,T.status,f)}return P}getApp(u){return this.rest("GET",`/apps/${encodeURIComponent(u)}`,{notFound:"null"})}createApp(u,f){return this.rest("POST","/apps",{body:{app_name:u,org_slug:f}})}async listMachines(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines`)??[]}createMachine(u,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines`,{body:f})}updateMachine(u,f,R,A){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}`,{body:R,headers:{"fly-machine-lease-nonce":A}})}async acquireLease(u,f,R=120){let T=(await this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/lease`,{body:{ttl:R}})).data?.nonce;if(!T)throw new Ws(`Fly.io gave no lease nonce for Machine ${f}`,200,`/machines/${f}/lease`);return T}async releaseLease(u,f,R){await this.rest("DELETE",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/lease`,{headers:{"fly-machine-lease-nonce":R}})}async waitForState(u,f,R,A={}){await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/wait`,{query:{state:R,timeout:String(A.timeoutSeconds??60),...A.instanceId?{instance_id:A.instanceId}:{}}})}async listVolumes(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/volumes`)??[]}createVolume(u,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/volumes`,{body:{...f,encrypted:!0}})}async setSecrets(u,f){return(await this.rest("POST",`/apps/${encodeURIComponent(u)}/secrets`,{body:{values:f}})).version}async listIpAssignments(u){return(await this.rest("GET",`/apps/${encodeURIComponent(u)}/ip_assignments`)).ips??[]}async assignIp(u,f){let R=await this.rest("POST",`/apps/${encodeURIComponent(u)}/ip_assignments`,{body:{type:f}});if(!R.ip)throw new Ws(`Fly.io assigned no ${f} address to ${u}`,200,`/apps/${u}/ip_assignments`);return{ip:R.ip,shared:R.shared??f==="shared_v4",region:R.region}}async requestCertificate(u,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/certificates/acme`,{body:{hostname:f}})}}function gg(u){try{return JSON.parse(u)}catch{return}}var Lc="ts-cloud-role";function $S(u,f){let R=u.fly??{},A=R.app??`${u.project.slug}-${f.environment}`;if(!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/.test(A))throw Error(`"${A}" is not a valid Fly app name: lowercase letters, digits and dashes, 3 to 63 characters.`);let T=R.internalPort??3000,E=R.count??1;if(!Number.isInteger(E)||E<1)throw Error(`fly.count must be a whole number of at least 1, got ${E}.`);return{app:A,org:R.org??"personal",image:f.image,regions:R.regions?.length?R.regions:["iad"],count:E,internalPort:T,healthPath:R.healthPath??"/",vm:{cpuKind:R.vm?.cpuKind??"shared",cpus:R.vm?.cpus??1,memoryMb:R.vm?.memoryMb??512},...R.volume?{volume:{name:R.volume.name??"data",sizeGb:R.volume.sizeGb,path:R.volume.path}}:{},autoStop:R.autoStop??!1,env:{...f.env,PORT:String(T)},secrets:f.secrets??{},hostnames:R.hostnames??[],release:f.release}}function fg(u){return{image:u.image,env:u.env,guest:{cpu_kind:u.vm.cpuKind,cpus:u.vm.cpus,memory_mb:u.vm.memoryMb},services:[{protocol:"tcp",internal_port:u.internalPort,ports:[{port:80,handlers:["http"],force_https:!0},{port:443,handlers:["tls","http"]}],autostop:u.autoStop?"stop":"off",autostart:!0,...u.autoStop?{min_machines_running:0}:{},checks:[{type:"http",method:"GET",path:u.healthPath,interval:"15s",timeout:"5s",grace_period:"10s"}]}],restart:{policy:"on-failure",max_retries:10},metadata:{[Lc]:"app","ts-cloud-release":u.release}}}async function IS(u,f,R=()=>{}){let A=!1;if(!await u.getApp(f.app))R(`Creating Fly app ${f.app} in ${f.org}`),await u.createApp(f.app,f.org),A=!0;let T;if(Object.keys(f.secrets).length>0)T=await u.setSecrets(f.app,f.secrets),R(`Set ${Object.keys(f.secrets).length} secret(s) (version ${T})`);let E=await u.listIpAssignments(f.app),P=new Set(E.map(Qc));if(!P.has("v6"))E.push(await u.assignIp(f.app,"v6")),R("Assigned a dedicated IPv6");if(!P.has("v4")&&!P.has("shared_v4"))E.push(await u.assignIp(f.app,"shared_v4")),R("Assigned a shared IPv4");let L=fg(f),z=(await u.listMachines(f.app)).filter((Me)=>{let ze=Me.config?.metadata??{};if(ze[Lc])return ze[Lc]==="app";return!ze.fly_process_group||ze.fly_process_group==="app"}),fe=f.volume?await u.listVolumes(f.app):[],me=[],At=[],Lt=new Set;for(let Me of f.regions){let ze=z.filter((j)=>j.region===Me).sort((j,yt)=>j.id.localeCompare(yt.id));for(let j=0;j<f.count;j++){let yt=ze[j];if(yt){Lt.add(yt.id),await Rg(u,f.app,yt,L,T),At.push(yt.id),R(`Updated ${yt.id} (${Me}) to ${f.image}`);continue}let G=f.volume?[{volume:(await Tg(u,f,Me,fe)).id,path:f.volume.path}]:void 0,ht=await u.createMachine(f.app,{region:Me,name:`${f.app}-${Me}-${j+1}`,config:{...L,...G?{mounts:G}:{}},...T!==void 0?{min_secrets_version:T}:{}});await u.waitForState(f.app,ht.id,"started",{instanceId:ht.instance_id}),me.push(ht.id),R(`Created ${ht.id} in ${Me}`)}}let mt=[];for(let Me of f.hostnames)mt.push(await u.requestCertificate(f.app,Me));return{app:f.app,url:`https://${f.app}.fly.dev`,createdApp:A,created:me,updated:At,untouched:z.filter((Me)=>!Lt.has(Me.id)).map((Me)=>Me.id),ips:E,certificates:mt}}async function Rg(u,f,R,A,T){let E=await u.acquireLease(f,R.id);try{let P=await u.updateMachine(f,R.id,{config:{...A,...R.config?.mounts?.length?{mounts:R.config.mounts}:{}},...T!==void 0?{min_secrets_version:T}:{}},E);await u.waitForState(f,R.id,"started",{instanceId:P.instance_id})}finally{await u.releaseLease(f,R.id,E)}}async function Tg(u,f,R,A){let T=A.find((P)=>P.region===R&&P.name===f.volume.name&&!P.attached_machine_id);if(T)return T.attached_machine_id="pending",T;let E=await u.createVolume(f.app,{name:f.volume.name,region:R,size_gb:f.volume.sizeGb});return A.push({...E,attached_machine_id:"pending"}),E}import{createHmac as Hl,createSign as Pg,timingSafeEqual as $g}from"node:crypto";function ro(u){let f=u instanceof Date?u.getTime():u;if(!Number.isFinite(f))throw TypeError("Media access timestamp must be finite");return Math.floor(f/1000)}function Vu(u){return Buffer.from(u).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function wg(u){return Buffer.from(u).toString("base64url")}function zu(u,f=!1){if(!u||/[\r\n]/.test(u))throw TypeError("Media resource is invalid");let R=f?u.replaceAll("*","wildcard"):u,A=new URL(R);if(!["http:","https:"].includes(A.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!f&&u.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function Hu(u,f){let R=Pg("RSA-SHA1");return R.update(u),R.end(),Vu(R.sign(f))}function Uu(u){zu(u.resource,!0);let R={DateLessThan:{"AWS:EpochTime":ro(u.expiresAt)}};if(u.activeAt!==void 0)R.DateGreaterThan={"AWS:EpochTime":ro(u.activeAt)};if(u.ipAddress)R.IpAddress={"AWS:SourceIp":u.ipAddress};return JSON.stringify({Statement:[{Resource:u.resource,Condition:R}]})}function MS(u,f,R){zu(u);let A=ro(f),T=u.includes("?")?"&":"?",E=Uu({resource:u,expiresAt:f}),P=Hu(E,R.privateKey);return`${u}${T}Expires=${A}&Signature=${encodeURIComponent(P)}&Key-Pair-Id=${encodeURIComponent(R.keyPairId)}`}function BS(u,f){let R=Uu(u);return{"CloudFront-Key-Pair-Id":f.keyPairId,"CloudFront-Policy":Vu(Buffer.from(R)),"CloudFront-Signature":Hu(R,f.privateKey)}}function WS(u){if(!u.resource||/[\r\n]/.test(u.resource))throw TypeError("Media resource is invalid");let f=wg(Buffer.from(JSON.stringify({resource:u.resource,expiresAt:ro(u.expiresAt),...u.keyId?{keyId:u.keyId}:{},...u.audience?{audience:u.audience}:{}}))),R=Hl("sha256",u.secret).update(f).digest("base64url");return`${f}.${R}`}function VS(u,f){let[R,A,T]=u.split(".");if(!R||!A||T)return null;let E=Hl("sha256",f.secret).update(R).digest(),P;try{P=Buffer.from(A,"base64url")}catch{return null}if(E.length!==P.length||!$g(E,P))return null;try{let L=JSON.parse(Buffer.from(R,"base64url").toString("utf8")),z=ro(f.now??Date.now());if(!L.resource||!Number.isSafeInteger(L.expiresAt)||L.expiresAt<=z)return null;if(f.resource&&L.resource!==f.resource)return null;if(f.audience&&L.audience!==f.audience)return null;return L}catch{return null}}function zS(u,f=!1){let R=new URL(u,"https://media.invalid").pathname.toLowerCase(),A=/\.(?:m3u8|mpd|vtt|json)$/.test(R),T=/\.(?:key|license)$/.test(R)||R.includes("/keys/")||R.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":f&&(A||T)?"private, no-store":A?"public, max-age=5, s-maxage=30, stale-while-revalidate=30":"public, max-age=31536000, immutable","Cross-Origin-Resource-Policy":"cross-origin","X-Content-Type-Options":"nosniff"}}function HS(u){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(u.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(u.region))throw TypeError("Media bucket region is invalid");let f=u.prefix?`/${u.prefix.replace(/^\/+|\/+$/g,"")}`:"",R=u.protected??!1,A="public, max-age=31536000, immutable",T=R?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${u.bucket}.s3.${u.region}.amazonaws.com`,originPath:f,domain:u.domain,trustedKeyGroupIds:[...new Set(u.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:T,compress:!0,signed:R},{pathPattern:"*.mpd",cacheControl:T,compress:!0,signed:R},{pathPattern:"*.vtt",cacheControl:T,compress:!0,signed:R},{pathPattern:"*",cacheControl:A,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 Dg{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(u){this.config=u.config,this.environment=u.environment,this.builder=new Jd(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let f=this.config.environments[this.environment]?.infrastructure;if(!f)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...f,compute:{...this.config.infrastructure?.compute,...f.compute},storage:{...this.config.infrastructure?.storage,...f.storage},functions:{...this.config.infrastructure?.functions,...f.functions},servers:{...this.config.infrastructure?.servers,...f.servers},databases:{...this.config.infrastructure?.databases,...f.databases},cdn:{...this.config.infrastructure?.cdn,...f.cdn},sftp:f.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...f.queues},redirects:{...this.config.infrastructure?.redirects,...f.redirects},realtime:{...this.config.infrastructure?.realtime,...f.realtime},cache:{...this.config.infrastructure?.cache,...f.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...f.fileSystem},email:{...this.config.infrastructure?.email,...f.email},search:{...this.config.infrastructure?.search,...f.search},ai:{...this.config.infrastructure?.ai,...f.ai}}}}shouldDeploy(u){if(u.environments&&!u.environments.includes(this.environment))return!1;if(u.requiresFeatures){let f=this.config.features||{};if(!u.requiresFeatures.every((A)=>f[A]===!0))return!1}if(u.regions){let f=this.config.environments[this.environment]?.region||this.config.project.region;if(!u.regions.includes(f))return!1}if(u.condition&&typeof u.condition==="function")return u.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let u=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,f=Number(u||3008);return Number.isFinite(f)&&f>0?f:3008}defaultComputeCachePathPatterns(){return["/api/*","/auth/*","/publisher/api/*","/publisher/*","/publish","/publish/*","/analytics/*","/packages/*","/npm/*","/zig/*","/php/*","/commits/*","/health","/dashboard/*","/search","/login","/logout","/signup","/account","/account/*"]}shouldRouteStorageBucketToCompute(u,f){return u==="public"||f.routeCompute===!0}storageBucketName(u,f,R){return this.mergedConfig.infrastructure?.storage?.[R]?.bucket??`${u}-${f}-${R}`}fileSystemLogicalId(u,f,R){return t(r({slug:`${u}-${R}`,environment:f,resourceType:"efs"}))}resolveSftpStorage(u,f,R){let A=u.storage;if(A?.type==="efs"&&A.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[A.fileSystem])throw Error(`sftp: storage.fileSystem "${A.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(f,R,A.fileSystem)},posixProfile:A.posixProfile}}if(A?.type==="s3"&&A.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[A.storageBucket])throw Error(`sftp: storage.storageBucket "${A.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(f,R,A.storageBucket)}}return}resolveComputeCachePathPatterns(u){if(u&&u.length>0)return u;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(u,f){return{PathPattern:u,TargetOriginId:f,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",OriginRequestPolicyId:"b689b0a8-53d0-40ab-baf2-68738e2966ac"}}appendComputeAppOrigin(u,f,R,A,T,E){let P=this.serverEipLogicalIds.get("app"),L=this.serverEipLogicalIds.get("appInstance");if(!P)return;let z=`EC2-${A}-${T}-api`,fe=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",me=fe==="us-east-1"?".compute-1.amazonaws.com":`.${fe}.compute.amazonaws.com`,At={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:P}]}]},me]]},Lt=this.resolveApiOriginPort();if(u.push({Id:z,DomainName:At,CustomOriginConfig:{HTTPPort:Lt,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),R.push(P),L)R.push(L);for(let mt of E)f.push(this.createComputeCacheBehavior(mt,z))}buildCaddyfile(u){let f=u.filter(([,T])=>typeof T.domain==="string"&&T.domain&&typeof T.port==="number");if(f.length===0)return;let R=new Map;for(let[,T]of f){let E=R.get(T.domain)??[];E.push({port:T.port,path:T.path}),R.set(T.domain,E)}let A=[];for(let[T,E]of R){let L=[...E].sort((z,fe)=>{let me=!z.path||z.path==="/",At=!fe.path||fe.path==="/";if(me&&!At)return 1;if(!me&&At)return-1;return(fe.path?.length??0)-(z.path?.length??0)}).map((z)=>{let fe=!z.path||z.path==="/",me=`reverse_proxy localhost:${z.port}`;return fe?` handle {
1
+ import{DI,PI,el,um,tl,rl,on,Q,l,nl,gm,K,il,g,zA,b,Xe,zi,an,w,be,sl,KA,r,t,kI,NI,p,BI,xI,OI,_I,LI,sr,ol,Ki,WA,$I,MI,xe,Ye,al,pm,mm,FI,fm,hm,Am,Mo,cl,ce,cn,Tt,Fo,wt,Ce,JA,dl,Uo,ym,Sm,Im,bm,ll,UI,W,C,XA,YA,Cm,a,y,Ze,m,Em,et,J,Rt,QI,vm,X,ul,Oe,or,Qo,de,gl,le,ZA,Ho,Y,Z,_,Wi,D,ar,Dt,ee,e,dn,HI,Tm,pl,GI,VI,qI,jI,ml,zI,KI,WI,JI,XI,YI,ZI,eb,tb,rb,nb,ib,ey,ty,ry,ny,iy,sy,oy,cr,wm,Rm,dr,Ji,sb,Dm,ob,ab,ln,cb,db,lb,ub,gb,pb,ay,cy,dy,ly,uy,Xi,mb,Go,gy,Pm,V,py,tt,Vo,Pt,my,km,fy,hy,Ay,Nm,q,fb,hb,Ab,yb,yy,Sb,te,Ib,bb,Cb,fl,hl,Sy,Bm,xm,Eb,vb,Tb,wb,Rb,Iy,Al,Db,Pb,kb,Nb,Bb,by,Cy,xb,Ob,_b,Lb,$b,Mb,Fb,Ey,Ub,Om,yl,Qb,Hb,Gb,Vb,_m,Lm,$m,qb,Sl,vy,Ty,wy,Ry,Il,Dy,jb,zb,Kb,Wb,Jb,Xb,Yb,Py,ky,Ny,By,Mm,Zb,eC,tC,rC,nC,iC,sC,oC,aC,xy,Oy,_y,Ly,cC,dC,Fm,lC,Um,Qm,Hm,Gm,uC,gC,pC,mC,_e,Yi,fC,hC,AC,yC,SC,IC,bC,CC,$y,EC,vC,Vm,qm,TC,wC,My,RC,DC,PC,kC,NC,BC,xC,OC,_C,LC,$C,MC,FC,UC,QC,HC,GC,VC,qC,jC,zC,bl,Fy,Cl,Uy,El,Qy,vl,Hy,Tl,Gy,lr,Vy,wl,qy,Zi,jy,Rl,zy,Dl,Ky,jm,KC,zm,WC,Pl,Wy,ur,Jy,Km,JC,kl,Xy,Wm,XC,Jm,YC,Xm,ZC,Nl,Yy,Ym,eE,Zm,tE,ef,rE,tf,nE,Bl,Zy,xl,eS,rf,iE,nf,sE,sf,oE,of,aE,af,cE,cf,dE,Ol,tS,df,lE,lf,uE,uf,gE,gf,pE,pf,mE,mf,fE,ff,hf,Af,yf,Sf,hE,If,AE,bf,yE,Cf,SE,rt,Ef,rS,qo,_l,un,nS,es,gr,Ll,$l,iS,sS,Ml,vf,Fl,Tf,IE,bE,jo,zo,Ko,Ul,gn,Ql,Hl,ts,Wo,Jo,wf,oS,aS,cS,CE,Rf,Df,EE,dS,Pf,lS,uS,gS,vE,kf,pn,Gl,Nf,TE,pS,Xo,Yo,Vl,Bf,wE,ql,mS,xf,RE,Of,DE,_f,PE}from"./chunk-zvcd6x45.js";import{jl,k,zl,Zo,fS,Lf,hS,AS,yS,SS,IS,bS,CS,ES}from"./chunk-a99wz633.js";import{sa,$f,eu,RS,ss,tu,oa,Mf,Ff,fn,aa,ru,it,nu,iu,su,os,hn,Uf,st,ou,ca,da,la,au,cu,du,as,ua,lu,An,cs,ga,kt,Qf,uu,gu,Hf,pu,pa,pr,mu,fu,hu,Au,ot,Gf,yu,mr,ma,fa,ha,ds,ls,yn,Su,us,Aa,ya,Sn,Iu,In,Vf,qf,Nt,bn,Sa,jf,bu,Cu,Ia,Eu,vu,Tu,DS,ue,wu,PS,kS,gs,ps,NS,Ee,zf,Bt,Le,$e,xt,Ru,Du,Pu,ku,Kf,Wf,ba,Jf,Xf,Ca,Nu,Bu,Yf,ge,Zf,xu,ve,Ea,at,Ot,_t,Cn,ms,Ou,BS,eh,th,rh,nh,va,Ta,_u,wa,En,Ra,Lu,fs,$u,Da,Pa,ka,Na,Ba,xa,Oa,_a,Mu,fr,La,Fu,vn,Uu,$a,Ma,Qu,hr,Fa,Ua,ih,xS,hs,OS,_S,LS,Qa,Ha,Hu,sh,Ga,Tn,Gu,As,Vu,qu,ju,Va,oh,qa,zu,ah,ja,ch,wn,Rn,Ku,ys,eg,ig,sg,og,ag,cg,Is,Ar,Ka,Dn,Pn,yr,ct,hh,Ja,Ah,yh,ug,Xa,Cs,gg,Ya,$t,Fe,pg,Za,ec,mg,tc,rc,nc,ic,fg,hg,Nn,sc,oc,ac,cc,Ag,Es,Bn,vs,dc}from"./chunk-07z9bps2.js";import{U,qr,fd,po,d,Fp,Up}from"./chunk-2hma3g5q.js";import{It,md,ki,Ni,Bi,Mp}from"./chunk-apj1eqcy.js";import{zh,Kh,Wh,Sp,Ip,bp,Jh,Cp,Ep,Xh,Yh,vp,Zh,eA,gd,Tp,tA,rA,wp,nA,iA,sA,oA,aA,cA,dA,Pi,pd,Rp,Dp,Pp,kp,Np,Bp,xp,Op,_p,Lp,$p,lA,uA,gA,pA,mA,fA,hA}from"./chunk-184bvh5s.js";import{Ke,hd,Ie,Yt,Ad,x,Zt,bt,yd,mo,SA,Qp,Sd,s,xi,fo,jr,Id,bd,zr,IA,Cd,vI,TI,ho,wI,RI,Ed,vd,Oi,Ao,ae,c,yo,We,Kr,bA,CA,Td,EA,So,vA,TA,Io,wd,Wr,bo,wA,er,Rd,Hp,tr,Jr,RA,Co,DA,O,PA,Dd,Gp,Eo,kA,NA,BA,Pd,_i,vo,kd,rr,Ct,xA,Xr,OA,Nd,Vp,qp,To,Bd,xd,Et,jp,Li,Od,wo,Yr,zp,$i,_d,Ld,Mi,Kp,$d,Md,Fd,Ud,Ro,Wp,Jp,_A,Xp,Qd,Fi,Yp,Zp,Do,Zr,Po,ko,No,Hd,em,Gd,Bo,LA,nr,$A,Vd,en,qd,MA,jd,tm,Ui,tn,xo,Qi,Je,FA,rm,nm,ir,zd,Kd,Wd,Hi,Gi,Vi,UA,QA,vt,Oo,HA,rn,im,_o,GA,sm,om,am,VA,cm,dm,qA,i,jA,qi,Lo,$o}from"./chunk-430acqjk.js";import{n}from"./chunk-e42gpavb.js";import{Re,gt,Vn}from"./chunk-qyr5hn6v.js";import{o}from"./chunk-jyvnfny6.js";import{Te,Ns,Bs,Ig,mc,fc,xs,hc,dt,re,lt,pe,v,we,Ln,Ac,Ue,yc,$n,Mn,Un,Mt,Ft,Ut,Qn,Ir,Sc,br,Cr,ut,Hn,bc,Qt,Er,Gn,Ec,Tg,wg,vc,vr}from"./chunk-nhsefr22.js";import{pt,he,Ge,Rg,Ht,wc,Rc,Gt,H,qn,Vt,qt,jn,$s,Ms,Tr,wr,zn,Rr,Fs,Us,Qs,Hs,ie,Gs,Vs,qs,js,Ae,zs,Ks,Ws,N,Dc,Kn,Pc,ye,Dr}from"./chunk-smt4t6rc.js";import{ne}from"./chunk-mp2y4t6w.js";import{Dg,kc,Pg,De,Nc,Wn,kg,Bc,Ng,Bg,Nh,Xn,Xs,M,Br,Yn,Zn,xr,_r,ei,Ys,ti,ri,ni,ii,oi,Lr,Se,_c,ai,Lc,$r,Fc,Ve,se,qe,je,ft,di,li,Pe,Mr,ke,gi,pi,mi,fi,hi,Ai,yi,Fr,F,ro,ip,Jc,Ii,bi,Ci,Ei,rd,no,nd,Jt,vi,io,so,id,Ti,sd}from"./chunk-b11w48de.js";import{ao,lo,uo,B,Ne}from"./chunk-yt8qgn5d.js";import{Kl,ea,rs,ns,ta,Wl,Jl,is,ra,na,Yl,Zl,ia}from"./chunk-gmtds745.js";import{lc,xn,On,Ts,ws,Rs,Ds,uc,gc}from"./chunk-94z7s8ky.js";import{pc}from"./chunk-hybz2q8w.js";import{Tc,Qe,S}from"./chunk-stc3ykm3.js";import{He}from"./chunk-vgtqd3sb.js";import{I}from"./chunk-y7k5872m.js";import{oe,wi,oo,od,Ri,pp}from"./chunk-wbbbpt4v.js";import{Qr,Be}from"./chunk-80bgb48v.js";import{h}from"./chunk-d245va6b.js";import{Jd,nn,Xd,Yd,Zd,ji,lm,sn}from"./chunk-qjp3f5y8.js";import{vS,nt}from"./chunk-c482jhc6.js";var qh="https://api.machines.dev/v1";class Ls extends Error{status;path;constructor(u,f,R){super(u);this.status=f;this.path=R;this.name="FlyApiError"}}function Qc(u){let f=u.ip.includes(":");if(f&&u.ip.startsWith("fdaa:"))return"private_v6";if(u.shared)return"shared_v4";return f?"v6":"v4"}class hp{token;fetch;constructor(u){if(!u.token)throw Error("Fly.io needs an API token: set FLY_API_TOKEN (`fly tokens create deploy` makes one scoped to an app).");this.token=u.token,this.fetch=u.fetch??fetch}async rest(u,f,R={}){let A=new URL(`https://api.machines.dev/v1${f}`);for(let[L,z]of Object.entries(R.query??{}))A.searchParams.set(L,z);let T=await this.fetch(A,{method:u,headers:{Authorization:`Bearer ${this.token}`,...R.body!==void 0?{"Content-Type":"application/json"}:{},...R.headers},body:R.body===void 0?void 0:JSON.stringify(R.body)});if(T.status===404&&R.notFound==="null")return null;let E=await T.text(),P=E?yp(E):void 0;if(!T.ok){let L=typeof P==="object"&&P&&"error"in P?String(P.error):E||T.statusText;throw new Ls(`Fly.io ${u} ${f} failed (${T.status}): ${L}`,T.status,f)}return P}getApp(u){return this.rest("GET",`/apps/${encodeURIComponent(u)}`,{notFound:"null"})}createApp(u,f){return this.rest("POST","/apps",{body:{app_name:u,org_slug:f}})}async listMachines(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines`)??[]}createMachine(u,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines`,{body:f})}updateMachine(u,f,R,A){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}`,{body:R,headers:{"fly-machine-lease-nonce":A}})}async acquireLease(u,f,R=120){let T=(await this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/lease`,{body:{ttl:R}})).data?.nonce;if(!T)throw new Ls(`Fly.io gave no lease nonce for Machine ${f}`,200,`/machines/${f}/lease`);return T}async releaseLease(u,f,R){await this.rest("DELETE",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/lease`,{headers:{"fly-machine-lease-nonce":R}})}async waitForState(u,f,R,A={}){await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/wait`,{query:{state:R,timeout:String(A.timeoutSeconds??60),...A.instanceId?{instance_id:A.instanceId}:{}}})}async listVolumes(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/volumes`)??[]}createVolume(u,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/volumes`,{body:{...f,encrypted:!0}})}async setSecrets(u,f){return(await this.rest("POST",`/apps/${encodeURIComponent(u)}/secrets`,{body:{values:f}})).version}async listIpAssignments(u){return(await this.rest("GET",`/apps/${encodeURIComponent(u)}/ip_assignments`)).ips??[]}async assignIp(u,f){let R=await this.rest("POST",`/apps/${encodeURIComponent(u)}/ip_assignments`,{body:{type:f}});if(!R.ip)throw new Ls(`Fly.io assigned no ${f} address to ${u}`,200,`/apps/${u}/ip_assignments`);return{ip:R.ip,shared:R.shared??f==="shared_v4",region:R.region}}async requestCertificate(u,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/certificates/acme`,{body:{hostname:f}})}}function yp(u){try{return JSON.parse(u)}catch{return}}var Wc="ts-cloud-role";function $S(u,f){let R=u.fly??{},A=R.app??`${u.project.slug}-${f.environment}`;if(!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/.test(A))throw Error(`"${A}" is not a valid Fly app name: lowercase letters, digits and dashes, 3 to 63 characters.`);let T=R.internalPort??3000,E=R.count??1;if(!Number.isInteger(E)||E<1)throw Error(`fly.count must be a whole number of at least 1, got ${E}.`);return{app:A,org:R.org??"personal",image:f.image,regions:R.regions?.length?R.regions:["iad"],count:E,internalPort:T,healthPath:R.healthPath??"/",vm:{cpuKind:R.vm?.cpuKind??"shared",cpus:R.vm?.cpus??1,memoryMb:R.vm?.memoryMb??512},...R.volume?{volume:{name:R.volume.name??"data",sizeGb:R.volume.sizeGb,path:R.volume.path}}:{},autoStop:R.autoStop??!1,env:{...f.env,PORT:String(T)},secrets:f.secrets??{},hostnames:R.hostnames??[],release:f.release}}function Ap(u){return{image:u.image,env:u.env,guest:{cpu_kind:u.vm.cpuKind,cpus:u.vm.cpus,memory_mb:u.vm.memoryMb},services:[{protocol:"tcp",internal_port:u.internalPort,ports:[{port:80,handlers:["http"],force_https:!0},{port:443,handlers:["tls","http"]}],autostop:u.autoStop?"stop":"off",autostart:!0,...u.autoStop?{min_machines_running:0}:{},checks:[{type:"http",method:"GET",path:u.healthPath,interval:"15s",timeout:"5s",grace_period:"10s"}]}],restart:{policy:"on-failure",max_retries:10},metadata:{[Wc]:"app","ts-cloud-release":u.release}}}async function wS(u,f,R=()=>{}){let A=!1;if(!await u.getApp(f.app))R(`Creating Fly app ${f.app} in ${f.org}`),await u.createApp(f.app,f.org),A=!0;let T;if(Object.keys(f.secrets).length>0)T=await u.setSecrets(f.app,f.secrets),R(`Set ${Object.keys(f.secrets).length} secret(s) (version ${T})`);let E=await u.listIpAssignments(f.app),P=new Set(E.map(Qc));if(!P.has("v6"))E.push(await u.assignIp(f.app,"v6")),R("Assigned a dedicated IPv6");if(!P.has("v4")&&!P.has("shared_v4"))E.push(await u.assignIp(f.app,"shared_v4")),R("Assigned a shared IPv4");let L=Ap(f),z=(await u.listMachines(f.app)).filter((Me)=>{let ze=Me.config?.metadata??{};if(ze[Wc])return ze[Wc]==="app";return!ze.fly_process_group||ze.fly_process_group==="app"}),fe=f.volume?await u.listVolumes(f.app):[],me=[],At=[],Lt=new Set;for(let Me of f.regions){let ze=z.filter((j)=>j.region===Me).sort((j,yt)=>j.id.localeCompare(yt.id));for(let j=0;j<f.count;j++){let yt=ze[j];if(yt){Lt.add(yt.id),await tg(u,f.app,yt,L,T),At.push(yt.id),R(`Updated ${yt.id} (${Me}) to ${f.image}`);continue}let G=f.volume?[{volume:(await rg(u,f,Me,fe)).id,path:f.volume.path}]:void 0,ht=await u.createMachine(f.app,{region:Me,name:`${f.app}-${Me}-${j+1}`,config:{...L,...G?{mounts:G}:{}},...T!==void 0?{min_secrets_version:T}:{}});await u.waitForState(f.app,ht.id,"started",{instanceId:ht.instance_id}),me.push(ht.id),R(`Created ${ht.id} in ${Me}`)}}let mt=[];for(let Me of f.hostnames)mt.push(await u.requestCertificate(f.app,Me));return{app:f.app,url:`https://${f.app}.fly.dev`,createdApp:A,created:me,updated:At,untouched:z.filter((Me)=>!Lt.has(Me.id)).map((Me)=>Me.id),ips:E,certificates:mt}}async function tg(u,f,R,A,T){let E=await u.acquireLease(f,R.id);try{let P=await u.updateMachine(f,R.id,{config:{...A,...R.config?.mounts?.length?{mounts:R.config.mounts}:{}},...T!==void 0?{min_secrets_version:T}:{}},E);await u.waitForState(f,R.id,"started",{instanceId:P.instance_id})}finally{await u.releaseLease(f,R.id,E)}}async function rg(u,f,R,A){let T=A.find((P)=>P.region===R&&P.name===f.volume.name&&!P.attached_machine_id);if(T)return T.attached_machine_id="pending",T;let E=await u.createVolume(f.app,{name:f.volume.name,region:R,size_gb:f.volume.sizeGb});return A.push({...E,attached_machine_id:"pending"}),E}import{createHmac as Xl,createSign as ng,timingSafeEqual as lg}from"node:crypto";function eo(u){let f=u instanceof Date?u.getTime():u;if(!Number.isFinite(f))throw TypeError("Media access timestamp must be finite");return Math.floor(f/1000)}function Wu(u){return Buffer.from(u).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function dg(u){return Buffer.from(u).toString("base64url")}function Zu(u,f=!1){if(!u||/[\r\n]/.test(u))throw TypeError("Media resource is invalid");let R=f?u.replaceAll("*","wildcard"):u,A=new URL(R);if(!["http:","https:"].includes(A.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!f&&u.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function Ju(u,f){let R=ng("RSA-SHA1");return R.update(u),R.end(),Wu(R.sign(f))}function Yu(u){Zu(u.resource,!0);let R={DateLessThan:{"AWS:EpochTime":eo(u.expiresAt)}};if(u.activeAt!==void 0)R.DateGreaterThan={"AWS:EpochTime":eo(u.activeAt)};if(u.ipAddress)R.IpAddress={"AWS:SourceIp":u.ipAddress};return JSON.stringify({Statement:[{Resource:u.resource,Condition:R}]})}function HS(u,f,R){Zu(u);let A=eo(f),T=u.includes("?")?"&":"?",E=Yu({resource:u,expiresAt:f}),P=Ju(E,R.privateKey);return`${u}${T}Expires=${A}&Signature=${encodeURIComponent(P)}&Key-Pair-Id=${encodeURIComponent(R.keyPairId)}`}function US(u,f){let R=Yu(u);return{"CloudFront-Key-Pair-Id":f.keyPairId,"CloudFront-Policy":Wu(Buffer.from(R)),"CloudFront-Signature":Ju(R,f.privateKey)}}function GS(u){if(!u.resource||/[\r\n]/.test(u.resource))throw TypeError("Media resource is invalid");let f=dg(Buffer.from(JSON.stringify({resource:u.resource,expiresAt:eo(u.expiresAt),...u.keyId?{keyId:u.keyId}:{},...u.audience?{audience:u.audience}:{}}))),R=Xl("sha256",u.secret).update(f).digest("base64url");return`${f}.${R}`}function jS(u,f){let[R,A,T]=u.split(".");if(!R||!A||T)return null;let E=Xl("sha256",f.secret).update(R).digest(),P;try{P=Buffer.from(A,"base64url")}catch{return null}if(E.length!==P.length||!lg(E,P))return null;try{let L=JSON.parse(Buffer.from(R,"base64url").toString("utf8")),z=eo(f.now??Date.now());if(!L.resource||!Number.isSafeInteger(L.expiresAt)||L.expiresAt<=z)return null;if(f.resource&&L.resource!==f.resource)return null;if(f.audience&&L.audience!==f.audience)return null;return L}catch{return null}}function KS(u,f=!1){let R=new URL(u,"https://media.invalid").pathname.toLowerCase(),A=/\.(?:m3u8|mpd|vtt|json)$/.test(R),T=/\.(?:key|license)$/.test(R)||R.includes("/keys/")||R.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":f&&(A||T)?"private, no-store":A?"public, max-age=5, s-maxage=30, stale-while-revalidate=30":"public, max-age=31536000, immutable","Cross-Origin-Resource-Policy":"cross-origin","X-Content-Type-Options":"nosniff"}}function qS(u){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(u.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(u.region))throw TypeError("Media bucket region is invalid");let f=u.prefix?`/${u.prefix.replace(/^\/+|\/+$/g,"")}`:"",R=u.protected??!1,A="public, max-age=31536000, immutable",T=R?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${u.bucket}.s3.${u.region}.amazonaws.com`,originPath:f,domain:u.domain,trustedKeyGroupIds:[...new Set(u.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:T,compress:!0,signed:R},{pathPattern:"*.mpd",cacheControl:T,compress:!0,signed:R},{pathPattern:"*.vtt",cacheControl:T,compress:!0,signed:R},{pathPattern:"*",cacheControl:A,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 yg{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(u){this.config=u.config,this.environment=u.environment,this.builder=new sl(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let f=this.config.environments[this.environment]?.infrastructure;if(!f)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...f,compute:{...this.config.infrastructure?.compute,...f.compute},storage:{...this.config.infrastructure?.storage,...f.storage},functions:{...this.config.infrastructure?.functions,...f.functions},servers:{...this.config.infrastructure?.servers,...f.servers},databases:{...this.config.infrastructure?.databases,...f.databases},cdn:{...this.config.infrastructure?.cdn,...f.cdn},sftp:f.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...f.queues},redirects:{...this.config.infrastructure?.redirects,...f.redirects},realtime:{...this.config.infrastructure?.realtime,...f.realtime},cache:{...this.config.infrastructure?.cache,...f.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...f.fileSystem},email:{...this.config.infrastructure?.email,...f.email},search:{...this.config.infrastructure?.search,...f.search},ai:{...this.config.infrastructure?.ai,...f.ai}}}}shouldDeploy(u){if(u.environments&&!u.environments.includes(this.environment))return!1;if(u.requiresFeatures){let f=this.config.features||{};if(!u.requiresFeatures.every((A)=>f[A]===!0))return!1}if(u.regions){let f=this.config.environments[this.environment]?.region||this.config.project.region;if(!u.regions.includes(f))return!1}if(u.condition&&typeof u.condition==="function")return u.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let u=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,f=Number(u||3008);return Number.isFinite(f)&&f>0?f:3008}defaultComputeCachePathPatterns(){return["/api/*","/auth/*","/publisher/api/*","/publisher/*","/publish","/publish/*","/analytics/*","/packages/*","/npm/*","/zig/*","/php/*","/commits/*","/health","/dashboard/*","/search","/login","/logout","/signup","/account","/account/*"]}shouldRouteStorageBucketToCompute(u,f){return u==="public"||f.routeCompute===!0}storageBucketName(u,f,R){return this.mergedConfig.infrastructure?.storage?.[R]?.bucket??`${u}-${f}-${R}`}fileSystemLogicalId(u,f,R){return t(r({slug:`${u}-${R}`,environment:f,resourceType:"efs"}))}resolveSftpStorage(u,f,R){let A=u.storage;if(A?.type==="efs"&&A.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[A.fileSystem])throw Error(`sftp: storage.fileSystem "${A.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(f,R,A.fileSystem)},posixProfile:A.posixProfile}}if(A?.type==="s3"&&A.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[A.storageBucket])throw Error(`sftp: storage.storageBucket "${A.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(f,R,A.storageBucket)}}return}resolveComputeCachePathPatterns(u){if(u&&u.length>0)return u;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(u,f){return{PathPattern:u,TargetOriginId:f,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",OriginRequestPolicyId:"b689b0a8-53d0-40ab-baf2-68738e2966ac"}}appendComputeAppOrigin(u,f,R,A,T,E){let P=this.serverEipLogicalIds.get("app"),L=this.serverEipLogicalIds.get("appInstance");if(!P)return;let z=`EC2-${A}-${T}-api`,fe=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",me=fe==="us-east-1"?".compute-1.amazonaws.com":`.${fe}.compute.amazonaws.com`,At={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:P}]}]},me]]},Lt=this.resolveApiOriginPort();if(u.push({Id:z,DomainName:At,CustomOriginConfig:{HTTPPort:Lt,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),R.push(P),L)R.push(L);for(let mt of E)f.push(this.createComputeCacheBehavior(mt,z))}buildCaddyfile(u){let f=u.filter(([,T])=>typeof T.domain==="string"&&T.domain&&typeof T.port==="number");if(f.length===0)return;let R=new Map;for(let[,T]of f){let E=R.get(T.domain)??[];E.push({port:T.port,path:T.path}),R.set(T.domain,E)}let A=[];for(let[T,E]of R){let L=[...E].sort((z,fe)=>{let me=!z.path||z.path==="/",At=!fe.path||fe.path==="/";if(me&&!At)return 1;if(!me&&At)return-1;return(fe.path?.length??0)-(z.path?.length??0)}).map((z)=>{let fe=!z.path||z.path==="/",me=`reverse_proxy localhost:${z.port}`;return fe?` handle {
2
2
  ${me}
3
3
  }`:` handle ${z.path} {
4
4
  ${me}
@@ -7,11 +7,11 @@ ${L.join(`
7
7
  `)}
8
8
  }`)}return A.join(`
9
9
 
10
- `)}normalizeMountPath(u){let f=u?.mountPath||u?.path;if(!f||f==="/")return;let R=`/${f}`.replace(/\/+/g,"/").replace(/\/$/,"");return R==="/"?void 0:R}storageBucketLogicalId(u,f,R){return`${u}-${f}-s3-${R}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((A)=>A.charAt(0).toUpperCase()+A.slice(1)).join("")}pathMountRewriteFunctionCode(u,f="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(u)}; var rewriteStyle = ${JSON.stringify(f)}; var uri = request.uri; if (uri === prefix) { uri = '/'; } else if (uri.indexOf(prefix + '/') === 0) { uri = uri.substring(prefix.length); } if (uri === '' || uri === '/') { request.uri = '/index.html'; return request; } if (uri.endsWith('/')) { request.uri = uri + 'index.html'; return request; } var lastSegment = uri.substring(uri.lastIndexOf('/') + 1); if (lastSegment.indexOf('.') === -1) { request.uri = rewriteStyle === 'flat' ? uri + '.html' : uri + '/index.html'; return request; } request.uri = uri; return request; }`}generate(){let u=this.mergedConfig.project.slug,f=this.environment,R=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),A=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),T=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(u,f),this.generateContainerInfrastructure(u,f);if(R)this.generateServerless(u,f);if(A)this.generateServer(u,f);if(T)this.generateComputeApp(u,f);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(u,f);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(u,f),this.storageFailoverReplicas.length>0)this.builder.addMetadata(el,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(u){}generateNetworkInfrastructure(u,f){if(this.builder.hasResource("VPC"))return;let A=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:T,logicalId:E}=y.createVpc({slug:u,environment:f,cidr:A,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",T);let P=`${u}${f}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${u}-${f}-igw`},{Key:"Environment",Value:f}]}});let L=`${u}${f}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(L,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:P}}});let z=`${u}${f}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${u}-${f}-public-rt`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${u}${f}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:z},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:P}},DependsOn:L});let fe=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",me=["a","b"];for(let At=0;At<2;At++){let Lt=`PublicSubnet${At+1}`;this.builder.addResource(Lt,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${At}.0/24`,AvailabilityZone:`${fe}${me[At]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${u}-${f}-public-${me[At]}`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${Lt}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:Lt},RouteTableId:{Ref:z}}})}}generateContainerInfrastructure(u,f){let R=this.mergedConfig.infrastructure?.containers;if(!R)return;let A=this.mergedConfig.infrastructure?.loadBalancer,T=this.mergedConfig.infrastructure?.ssl,E=this.mergedConfig.infrastructure?.dns,P;if(T?.enabled&&T.domains?.length)if(T.certificateArn);else{let me=T.domains[0],At=T.domains.slice(1).map((Me)=>{if(Me.includes(".")&&Me.endsWith(me))return Me.replace(`.${me}`,"");return Me}),{certificate:Lt,logicalId:mt}=C.createCertificate({domain:me,subdomains:At,slug:u,environment:f,validationMethod:"DNS",hostedZoneId:E?.hostedZoneId});P=mt,this.builder.addResource(mt,Lt)}let L="ECSCluster";this.builder.addResource(L,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${u}-${f}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${u}-${f}`},{Key:"Environment",Value:f}]}});let z=`${u}${f}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${u}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0",Description:"HTTP"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${f}-alb-sg`},{Key:"Environment",Value:f}]}});let fe=`${u}${f}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[me,At]of Object.entries(R)){let Lt=At.port||3000;this.builder.addResource(fe,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${u}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:Lt,ToPort:Lt,SourceSecurityGroupId:{Ref:z},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${f}-ecs-sg`},{Key:"Environment",Value:f}]}});let mt=`${u}${f}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(mt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-ecs-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"],Policies:[{PolicyName:"ECRPullPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"}]}}]}});let Me=`${u}${f}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-ecs-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"}]}}]}});let ze=`${u}${f}${me}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),j=`/ecs/${u}-${f}-${me}`;this.builder.addResource(ze,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:j,RetentionInDays:30}});let yt=`${u}${f}${me}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),G=String(At.cpu||512),ht=String(At.memory||1024);this.builder.addResource(yt,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${f}-${me}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:G,Memory:ht,ExecutionRoleArn:{"Fn::GetAtt":[mt,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[Me,"Arn"]},ContainerDefinitions:[{Name:me,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${u}:latest`},Essential:!0,PortMappings:[{ContainerPort:Lt,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":j,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":me}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${Lt}${At.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[mt,Me,ze]});let St=`${u}${f}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(A?.enabled!==!1){this.builder.addResource(St,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${u}-${f}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:z}],Tags:[{Key:"Name",Value:`${u}-${f}-alb`},{Key:"Environment",Value:f}]}});let Wt=`${u}${f}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),zt=A?.healthCheck?.path||At.healthCheck||"/health";this.builder.addResource(Wt,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${u}-${f}-tg`,Port:Lt,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:zt,HealthCheckIntervalSeconds:A?.healthCheck?.interval||30,HealthyThresholdCount:A?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:A?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${u}-${f}-tg`},{Key:"Environment",Value:f}]}});let jt=`${u}${f}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(T?.enabled&&T?.redirectHttp)this.builder.addResource(jt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:St},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(jt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:St},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Wt}}]}});if(T?.enabled){let Xt=T.certificateArn||(P?{Ref:P}:void 0);if(Xt){let Pr=`${u}${f}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:St},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Xt}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Wt}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Kt=`${u}${f}${me}Service`.replace(/[^a-zA-Z0-9]/g,""),Sr=At.desiredCount||1;this.builder.addResource(Kt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${f}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:yt},DesiredCount:Sr,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:me,ContainerPort:Lt,TargetGroupArn:{Ref:Wt}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[yt,jt,Wt]});let Or=At.autoScaling;if(Or){let Xt=`${u}${f}${me}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Xt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:Or.max||10,MinCapacity:Or.min||1,ResourceId:{"Fn::Sub":`service/\${${L}}/${u}-${f}-${me}`},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:Kt}),Or.targetCpuUtilization)this.builder.addResource(`${u}${f}${me}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${f}-${me}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Xt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:Or.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(Or.targetMemoryUtilization)this.builder.addResource(`${u}${f}${me}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${f}-${me}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Xt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:Or.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(E?.domain&&E?.hostedZoneId)this.builder.addResource(`${u}${f}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:E.hostedZoneId,Name:`api.${E.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[St,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[St,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[L,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${u}-${f}-${me}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[St,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let Wt=`${u}${f}${me}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Wt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${f}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:yt},DesiredCount:At.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[yt]})}break}}generateServerless(u,f){if(this.mergedConfig.infrastructure?.functions)for(let[R,A]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(A))continue;let{role:T,logicalId:E}=de.createRole({slug:u,environment:f,roleName:`${u}-${f}-${R}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(E,T);let{lambdaFunction:P,logicalId:L}=a.createLambdaFunction({slug:u,environment:f,functionName:`${u}-${f}-${R}`,handler:A.handler||"index.handler",runtime:A.runtime||"nodejs20.x",code:{zipFile:A.code||"export const handler = async () => ({ statusCode: 200 });"},role:E,timeout:A.timeout,memorySize:A.memorySize});this.builder.addResource(L,P)}if(this.mergedConfig.infrastructure?.api){let{restApi:R,logicalId:A}=nl.createRestApi({slug:u,environment:f,apiName:`${u}-${f}-api`});this.builder.addResource(A,R)}}generateServer(u,f){if(!this.mergedConfig.infrastructure?.servers)return;let R=this.mergedConfig.infrastructure.servers,A=this.mergedConfig.infrastructure?.compute,T=this.mergedConfig.infrastructure?.ssl;if(Object.values(R).some((P)=>!P.privateNetwork||P.privateNetwork==="create"))this.generateNetworkInfrastructure(u,f);for(let[P,L]of Object.entries(R)){let z=L.instanceType||L.size||A?.size,me=(z?a.InstanceSize.specs[z]:void 0)?.instanceType||z||"t3.micro",At=L.type||"app",Lt=L.userData||L.startupScript;if(!Lt)Lt=a.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:L.bunVersion||"latest",webServer:"none",domain:L.domain,enableSsl:!!T?.enabled,sslEmail:T?.letsEncrypt?.email,installRedis:At==="cache",installDatabaseClients:!!L.database});let mt=L.privateNetwork&&L.privateNetwork!=="create"?L.privateNetwork:{Ref:"VPC"},Me=L.subnet||{Ref:"PublicSubnet1"},j=!!this.mergedConfig.infrastructure?.email?.server?.enabled,yt=[22,80,443,this.resolveApiOriginPort()];if(j)yt.push(25,465,587,143,993);let G=a.createServerModeStack({slug:`${u}-${P}`,environment:f,vpcId:mt,subnetId:Me,instanceType:me,keyName:L.keyName||`${u}-${f}`,domain:L.domain,userData:Lt,volumeSize:L.diskSize||20,imageId:L.image,allowedPorts:yt});for(let[ht,St]of Object.entries(G.resources))this.builder.addResource(ht,St);this.serverEipLogicalIds.set(P,G.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${P}Instance`,G.outputs.instanceLogicalId),this.builder.addOutput(`${P}InstanceId`,{Value:{Ref:G.outputs.instanceLogicalId},Description:`Instance ID for ${P} server`}),this.builder.addOutput(`${P}PublicIp`,{Value:{Ref:G.outputs.eipLogicalId},Description:`Public IP for ${P} server`})}}generateComputeApp(u,f){let R=this.mergedConfig.infrastructure?.compute;if(!R)return;let A=this.mergedConfig.sites||{},T=Object.entries(A),P=this.mergedConfig.infrastructure?.dns?.domain,L=this.mergedConfig.infrastructure?.database,z=R.size,me=(z?a.InstanceSize.specs[z]:void 0)?.instanceType||z||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(u,f);let At=this.buildCaddyfile(T),Lt=a.UserData.generateBunAppScript({runtime:R.runtime||"bun",runtimeVersion:R.runtimeVersion||"latest",systemPackages:R.systemPackages,database:L,caddyfile:At}),mt=js(R.appUpdates),Me=mt.length>0?`${Lt}
10
+ `)}normalizeMountPath(u){let f=u?.mountPath||u?.path;if(!f||f==="/")return;let R=`/${f}`.replace(/\/+/g,"/").replace(/\/$/,"");return R==="/"?void 0:R}storageBucketLogicalId(u,f,R){return`${u}-${f}-s3-${R}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((A)=>A.charAt(0).toUpperCase()+A.slice(1)).join("")}pathMountRewriteFunctionCode(u,f="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(u)}; var rewriteStyle = ${JSON.stringify(f)}; var uri = request.uri; if (uri === prefix) { uri = '/'; } else if (uri.indexOf(prefix + '/') === 0) { uri = uri.substring(prefix.length); } if (uri === '' || uri === '/') { request.uri = '/index.html'; return request; } if (uri.endsWith('/')) { request.uri = uri + 'index.html'; return request; } var lastSegment = uri.substring(uri.lastIndexOf('/') + 1); if (lastSegment.indexOf('.') === -1) { request.uri = rewriteStyle === 'flat' ? uri + '.html' : uri + '/index.html'; return request; } request.uri = uri; return request; }`}generate(){let u=this.mergedConfig.project.slug,f=this.environment,R=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),A=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),T=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(u,f),this.generateContainerInfrastructure(u,f);if(R)this.generateServerless(u,f);if(A)this.generateServer(u,f);if(T)this.generateComputeApp(u,f);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(u,f);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(u,f),this.storageFailoverReplicas.length>0)this.builder.addMetadata(dl,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(u){}generateNetworkInfrastructure(u,f){if(this.builder.hasResource("VPC"))return;let A=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:T,logicalId:E}=y.createVpc({slug:u,environment:f,cidr:A,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",T);let P=`${u}${f}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${u}-${f}-igw`},{Key:"Environment",Value:f}]}});let L=`${u}${f}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(L,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:P}}});let z=`${u}${f}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${u}-${f}-public-rt`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${u}${f}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:z},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:P}},DependsOn:L});let fe=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",me=["a","b"];for(let At=0;At<2;At++){let Lt=`PublicSubnet${At+1}`;this.builder.addResource(Lt,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${At}.0/24`,AvailabilityZone:`${fe}${me[At]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${u}-${f}-public-${me[At]}`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${Lt}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:Lt},RouteTableId:{Ref:z}}})}}generateContainerInfrastructure(u,f){let R=this.mergedConfig.infrastructure?.containers;if(!R)return;let A=this.mergedConfig.infrastructure?.loadBalancer,T=this.mergedConfig.infrastructure?.ssl,E=this.mergedConfig.infrastructure?.dns,P;if(T?.enabled&&T.domains?.length)if(T.certificateArn);else{let me=T.domains[0],At=T.domains.slice(1).map((Me)=>{if(Me.includes(".")&&Me.endsWith(me))return Me.replace(`.${me}`,"");return Me}),{certificate:Lt,logicalId:mt}=C.createCertificate({domain:me,subdomains:At,slug:u,environment:f,validationMethod:"DNS",hostedZoneId:E?.hostedZoneId});P=mt,this.builder.addResource(mt,Lt)}let L="ECSCluster";this.builder.addResource(L,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${u}-${f}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${u}-${f}`},{Key:"Environment",Value:f}]}});let z=`${u}${f}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${u}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0",Description:"HTTP"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${f}-alb-sg`},{Key:"Environment",Value:f}]}});let fe=`${u}${f}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[me,At]of Object.entries(R)){let Lt=At.port||3000;this.builder.addResource(fe,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${u}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:Lt,ToPort:Lt,SourceSecurityGroupId:{Ref:z},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${f}-ecs-sg`},{Key:"Environment",Value:f}]}});let mt=`${u}${f}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(mt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-ecs-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"],Policies:[{PolicyName:"ECRPullPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"}]}}]}});let Me=`${u}${f}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-ecs-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"}]}}]}});let ze=`${u}${f}${me}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),j=`/ecs/${u}-${f}-${me}`;this.builder.addResource(ze,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:j,RetentionInDays:30}});let yt=`${u}${f}${me}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),G=String(At.cpu||512),ht=String(At.memory||1024);this.builder.addResource(yt,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${f}-${me}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:G,Memory:ht,ExecutionRoleArn:{"Fn::GetAtt":[mt,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[Me,"Arn"]},ContainerDefinitions:[{Name:me,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${u}:latest`},Essential:!0,PortMappings:[{ContainerPort:Lt,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":j,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":me}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${Lt}${At.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[mt,Me,ze]});let St=`${u}${f}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(A?.enabled!==!1){this.builder.addResource(St,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${u}-${f}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:z}],Tags:[{Key:"Name",Value:`${u}-${f}-alb`},{Key:"Environment",Value:f}]}});let Wt=`${u}${f}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),zt=A?.healthCheck?.path||At.healthCheck||"/health";this.builder.addResource(Wt,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${u}-${f}-tg`,Port:Lt,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:zt,HealthCheckIntervalSeconds:A?.healthCheck?.interval||30,HealthyThresholdCount:A?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:A?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${u}-${f}-tg`},{Key:"Environment",Value:f}]}});let jt=`${u}${f}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(T?.enabled&&T?.redirectHttp)this.builder.addResource(jt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:St},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(jt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:St},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Wt}}]}});if(T?.enabled){let Xt=T.certificateArn||(P?{Ref:P}:void 0);if(Xt){let Pr=`${u}${f}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Pr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:St},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Xt}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Wt}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Kt=`${u}${f}${me}Service`.replace(/[^a-zA-Z0-9]/g,""),Sr=At.desiredCount||1;this.builder.addResource(Kt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${f}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:yt},DesiredCount:Sr,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:me,ContainerPort:Lt,TargetGroupArn:{Ref:Wt}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[yt,jt,Wt]});let Or=At.autoScaling;if(Or){let Xt=`${u}${f}${me}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Xt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:Or.max||10,MinCapacity:Or.min||1,ResourceId:{"Fn::Sub":`service/\${${L}}/${u}-${f}-${me}`},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:Kt}),Or.targetCpuUtilization)this.builder.addResource(`${u}${f}${me}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${f}-${me}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Xt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:Or.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(Or.targetMemoryUtilization)this.builder.addResource(`${u}${f}${me}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${f}-${me}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Xt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:Or.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(E?.domain&&E?.hostedZoneId)this.builder.addResource(`${u}${f}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:E.hostedZoneId,Name:`api.${E.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[St,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[St,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[L,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${u}-${f}-${me}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[St,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let Wt=`${u}${f}${me}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Wt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${f}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:yt},DesiredCount:At.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[yt]})}break}}generateServerless(u,f){if(this.mergedConfig.infrastructure?.functions)for(let[R,A]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(A))continue;let{role:T,logicalId:E}=de.createRole({slug:u,environment:f,roleName:`${u}-${f}-${R}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(E,T);let{lambdaFunction:P,logicalId:L}=a.createLambdaFunction({slug:u,environment:f,functionName:`${u}-${f}-${R}`,handler:A.handler||"index.handler",runtime:A.runtime||"nodejs20.x",code:{zipFile:A.code||"export const handler = async () => ({ statusCode: 200 });"},role:E,timeout:A.timeout,memorySize:A.memorySize});this.builder.addResource(L,P)}if(this.mergedConfig.infrastructure?.api){let{restApi:R,logicalId:A}=gl.createRestApi({slug:u,environment:f,apiName:`${u}-${f}-api`});this.builder.addResource(A,R)}}generateServer(u,f){if(!this.mergedConfig.infrastructure?.servers)return;let R=this.mergedConfig.infrastructure.servers,A=this.mergedConfig.infrastructure?.compute,T=this.mergedConfig.infrastructure?.ssl;if(Object.values(R).some((P)=>!P.privateNetwork||P.privateNetwork==="create"))this.generateNetworkInfrastructure(u,f);for(let[P,L]of Object.entries(R)){let z=L.instanceType||L.size||A?.size,me=(z?a.InstanceSize.specs[z]:void 0)?.instanceType||z||"t3.micro",At=L.type||"app",Lt=L.userData||L.startupScript;if(!Lt)Lt=a.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:L.bunVersion||"latest",webServer:"none",domain:L.domain,enableSsl:!!T?.enabled,sslEmail:T?.letsEncrypt?.email,installRedis:At==="cache",installDatabaseClients:!!L.database});let mt=L.privateNetwork&&L.privateNetwork!=="create"?L.privateNetwork:{Ref:"VPC"},Me=L.subnet||{Ref:"PublicSubnet1"},j=!!this.mergedConfig.infrastructure?.email?.server?.enabled,yt=[22,80,443,this.resolveApiOriginPort()];if(j)yt.push(25,465,587,143,993);let G=a.createServerModeStack({slug:`${u}-${P}`,environment:f,vpcId:mt,subnetId:Me,instanceType:me,keyName:L.keyName||`${u}-${f}`,domain:L.domain,userData:Lt,volumeSize:L.diskSize||20,imageId:L.image,allowedPorts:yt});for(let[ht,St]of Object.entries(G.resources))this.builder.addResource(ht,St);this.serverEipLogicalIds.set(P,G.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${P}Instance`,G.outputs.instanceLogicalId),this.builder.addOutput(`${P}InstanceId`,{Value:{Ref:G.outputs.instanceLogicalId},Description:`Instance ID for ${P} server`}),this.builder.addOutput(`${P}PublicIp`,{Value:{Ref:G.outputs.eipLogicalId},Description:`Public IP for ${P} server`})}}generateComputeApp(u,f){let R=this.mergedConfig.infrastructure?.compute;if(!R)return;let A=this.mergedConfig.sites||{},T=Object.entries(A),P=this.mergedConfig.infrastructure?.dns?.domain,L=this.mergedConfig.infrastructure?.database,z=R.size,me=(z?a.InstanceSize.specs[z]:void 0)?.instanceType||z||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(u,f);let At=this.buildCaddyfile(T),Lt=a.UserData.generateBunAppScript({runtime:R.runtime||"bun",runtimeVersion:R.runtimeVersion||"latest",systemPackages:R.systemPackages,database:L,caddyfile:At}),mt=Xs(R.appUpdates),Me=mt.length>0?`${Lt}
11
11
  ${mt.join(`
12
12
  `)}
13
- `:Lt,ze=T.map(([,zt])=>zt.port).filter((zt)=>typeof zt==="number"&&![80,443].includes(zt)),j=this.resolveApiOriginPort(),yt=`${u}${f}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),G=`${u}-${f}-deploy`;this.builder.addResource(yt,{Type:"AWS::S3::Bucket",Properties:{BucketName:G,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:u},{Key:"Environment",Value:f},{Key:"ManagedBy",Value:"ts-cloud"}]}});let ht=a.createServerModeStack({slug:`${u}-app`,environment:f,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:me,keyName:R.allowSsh?`${u}-${f}`:void 0,domain:P,userData:Me,volumeSize:R.disk?.size||20,imageId:R.image,allowedPorts:[...R.allowSsh?[22]:[],80,443,j,...ze]}),St=ht.resources[ht.outputs.instanceLogicalId];if(St?.Properties){let zt=St.Properties.Tags||[];St.Properties.Tags=[...zt,{Key:"Project",Value:u},{Key:"Environment",Value:f},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let Wt=ht.resources[ht.outputs.roleLogicalId];if(Wt?.Properties)Wt.Properties.Policies=Wt.Properties.Policies||[],Wt.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${G}`,`arn:aws:s3:::${G}/*`]}]}});for(let[zt,jt]of Object.entries(ht.resources))this.builder.addResource(zt,jt);this.builder.addOutput("deployBucketName",{Value:{Ref:yt},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:ht.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:ht.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",ht.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",ht.outputs.instanceLogicalId)}jumpBoxFileSystemId(u,f,R){let A=Object.keys(this.mergedConfig.infrastructure?.fileSystem??{});if(typeof R==="string")return A.includes(R)?{Ref:this.fileSystemLogicalId(u,f,R)}:R;if(A.length===1)return{Ref:this.fileSystemLogicalId(u,f,A[0])};throw Error(A.length===0?"infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares no file system. Declare one, or set mountEfs to an EFS id.":`infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares ${A.length} (${A.join(", ")}). Set mountEfs to the name of the one to mount.`)}generateJumpBox(u,f){let R=this.mergedConfig.infrastructure?.jumpBox;if(!R)return;let A=R===!0?{}:R;if(A.enabled===!1)return;this.generateNetworkInfrastructure(u,f);let T=A.size||"micro",P=a.InstanceSize.specs[T]?.instanceType||T||"t3.micro",L=a.createJumpBox({slug:u,environment:f,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:A.keyName,instanceType:P,allowedCidrs:A.allowedCidrs,mountEfs:A.mountEfs?{fileSystemId:this.jumpBoxFileSystemId(u,f,A.mountEfs),mountPath:A.mountPath||"/mnt/efs"}:void 0,databaseTools:A.databaseTools});for(let[z,fe]of Object.entries(L.resources))this.builder.addResource(z,fe);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:L.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(u,f){let R=this.mergedConfig.infrastructure?.ssl,A=this.mergedConfig.infrastructure?.dns,T=A?.domain,E=A?.hostedZoneId,P=[],L,z;if(R?.certificateArn)z=R.certificateArn;else if(R?.enabled&&T&&E){let ze=R.domains||[T],j=ze[0],yt=ze.slice(1).map((St)=>{if(St.includes(".")&&St.endsWith(j))return St.replace(`.${j}`,"");return St}),{certificate:G,logicalId:ht}=C.createCertificate({domain:j,subdomains:yt,slug:u,environment:f,validationMethod:"DNS",hostedZoneId:E});L=ht,this.builder.addResource(ht,G)}if(this.mergedConfig.infrastructure?.storage){let ze=Object.entries(this.mergedConfig.infrastructure.storage).some(([,G])=>G.website),j;if(ze&&(L||z))j=`${u}${f}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(j,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${u}-${f}-s3-oac`,Description:`OAC for ${u} ${f} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let yt=Object.entries(this.mergedConfig.infrastructure.storage).map(([G,ht])=>({name:G,config:ht,mountPath:this.normalizeMountPath(ht),rewriteStyle:ht.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(u,f,G)})).filter((G)=>G.name!=="public"&&G.config.website&&G.mountPath);for(let[G,ht]of Object.entries(this.mergedConfig.infrastructure.storage)){let St=!!(ht.website&&j),Wt=this.storageBucketName(u,f,G),{bucket:zt,logicalId:jt}=xe.createBucket({slug:u,name:G,environment:f,bucketName:Wt,versioning:ht.versioning,encryption:ht.encryption,public:St?!1:ht.public}),Kt=this.normalizeMountPath(ht),Sr;if(ht.failover){let Xt=`infrastructure.storage.${G}`;if(!St||!T||Kt&&G!=="public")throw Error(`${Xt}.failover needs this bucket to be served by its own CloudFront distribution: a website bucket (website: true), not mounted under the path of another site, with infrastructure.dns.domain set and SSL configured (infrastructure.ssl.certificateArn, or ssl.enabled with dns.hostedZoneId).`);if(Sr=lm({failover:ht.failover,primaryBucket:Wt,primaryRegion:this.mergedConfig.project.region||"us-east-1",where:Xt}),Sr.replicate&&zt.Properties){let Pr=`${jt}FailoverReplicationRole`;this.builder.addResource(Pr,gm({primaryBucket:Wt,replicaBucket:Sr.replicaBucket}));let Fr=zt.Properties;Fr.VersioningConfiguration={Status:"Enabled"},Fr.ReplicationConfiguration=pm({replicaBucket:Sr.replicaBucket,roleArn:{"Fn::GetAtt":[Pr,"Arn"]}})}}if(St&&zt.Properties)zt.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(jt,zt),ht.website){let Xt=typeof ht.website==="object"?ht.website:{},Pr=xe.enableWebsiteHosting(zt,Xt.indexDocument||"index.html",Xt.errorDocument);this.builder.addResource(jt,Pr)}let Or=this.normalizeMountPath(ht);if(St&&j&&T&&!(Or&&G!=="public")){let Xt=`${u}${f}${G}CDN`.replace(/[^a-zA-Z0-9]/g,""),Pr=[];if(ht.aliases&&ht.aliases.length>0)Pr.push(...ht.aliases);else if(G==="public"){if(Pr.push(T),R?.domains?.includes(`www.${T}`))Pr.push(`www.${T}`)}else if(G==="docs")Pr.push(`docs.${T}`);else if(G==="blog")Pr.push(`blog.${T}`);let Fr=typeof ht.website==="object"?ht.website:{},Qr=ht.spa===!0,Hr=Fr.errorDocument||(Qr?"index.html":"404.html"),Nr=[];if(Qr)Nr.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else Nr.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${Hr}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${Hr}`,ErrorCachingMinTTL:300});let pn=z&&Pr.length>0?{AcmCertificateArn:z,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:L&&Pr.length>0?{AcmCertificateArn:{Ref:L},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Wn=`S3-${u}-${f}-${G}`,$c=this.mergedConfig.project.region||"us-east-1",Zn;if(!Qr)Zn=`${u}${f}${G}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(Zn,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${f}-${G}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${u} ${f} ${G} - 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 Ei=[{Id:Wn,DomainName:{"Fn::Sub":`\${${jt}}.s3.${$c}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}],ks=[],kc=[];if(this.shouldRouteStorageBucketToCompute(G,ht)){this.appendComputeAppOrigin(Ei,ks,kc,u,f,this.resolveComputeCachePathPatterns(ht.computeRoutes));for(let kr of yt){let Ns=`S3-${u}-${f}-${kr.name}`,Nc=`${u}${f}${kr.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Nc,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${f}-${kr.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${u} ${f} ${kr.name} at ${kr.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(kr.mountPath,kr.rewriteStyle)}}),Ei.push({Id:Ns,DomainName:{"Fn::Sub":`\${${kr.logicalId}}.s3.${$c}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),kc.push(kr.logicalId,Nc);for(let pg of[kr.mountPath,`${kr.mountPath}/*`])ks.push({PathPattern:pg,TargetOriginId:Ns,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Nc,"FunctionARN"]}}]})}}let vs,Yc=Wn;if(Sr){let kr=`${Wn}-failover`;Object.assign(Ei[0],Sr.primaryConnection),Ei.push({Id:kr,DomainName:um(Sr.replicaBucket,Sr.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),vs=an({primaryOriginId:Wn,secondaryOriginId:kr,statusCodes:Sr.statusCodes}),Yc=vs.Items[0].Id}let Oc={Type:"AWS::CloudFront::Distribution",DependsOn:[jt,j,...Zn?[Zn]:[],...kc],Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${f} ${G} site`,DefaultRootObject:"index.html",Origins:Ei,...vs?{OriginGroups:vs}:{},DefaultCacheBehavior:{TargetOriginId:Yc,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...Zn?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Zn,"FunctionARN"]}}]}:{}},...ks.length>0?{CacheBehaviors:ks}:{},...Pr.length>0?{Aliases:Pr}:{},ViewerCertificate:pn,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:Nr}}};if(L)Oc.DependsOn.push(L);if(Sr)wt(Oc.Properties.DistributionConfig,`infrastructure.storage.${G}`),this.storageFailoverReplicas.push({name:G,primaryBucket:Wt,primaryRegion:$c,replicaBucket:Sr.replicaBucket,replicaRegion:Sr.replicaRegion,replicate:Sr.replicate,distributionArnOutput:`${G}CloudFrontDistributionArn`}),this.builder.addOutput(`${G}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`},Description:`CloudFront distribution ARN for ${G} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${G}FailoverBucketName`,{Value:Sr.replicaBucket,Description:`Failover replica bucket for ${G} (${Sr.replicaRegion}), outside this stack`});this.builder.addResource(Xt,Oc);let dg=`${jt}CloudFrontPolicy`;if(this.builder.addResource(dg,{Type:"AWS::S3::BucketPolicy",DependsOn:[jt,Xt],Properties:{Bucket:{Ref:jt},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${jt}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(G,ht))for(let kr of yt){let Ns=`${kr.logicalId}CloudFrontPolicy`;this.builder.addResource(Ns,{Type:"AWS::S3::BucketPolicy",DependsOn:[kr.logicalId,Xt],Properties:{Bucket:{Ref:kr.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:::\${${kr.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`}}}}]}}})}if(Pr.length>0)P.push({name:G,bucketLogicalId:jt,distLogicalId:Xt,oacLogicalId:j,aliases:Pr});this.builder.addOutput(`${G}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Xt,"DomainName"]},Description:`CloudFront domain for ${G}`}),this.builder.addOutput(`${G}CloudFrontDistributionId`,{Value:{Ref:Xt},Description:`CloudFront distribution ID for ${G}`})}if(this.builder.addOutput(`${G}BucketName`,{Value:{Ref:jt},Description:`S3 bucket name for ${G}`}),G==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:jt},Description:"Frontend S3 bucket name"});if(G==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:jt},Description:"Documentation S3 bucket name"});if(G==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:jt},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let ze=this.mergedConfig.infrastructure.sftp,j=rl.create({...ze,storage:this.resolveSftpStorage(ze,u,f)??ze.storage,slug:u,environment:f});for(let[yt,G]of Object.entries(j.resources))this.builder.addResource(yt,G);this.builder.addOutput("SftpServerId",{Value:{Ref:j.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${j.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:j.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(E&&P.length>0)for(let{name:ze,distLogicalId:j,aliases:yt}of P)for(let G of yt){let ht=G.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${ht}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[j],Properties:{HostedZoneId:E,Name:G,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[j,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${ht}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[j],Properties:{HostedZoneId:E,Name:G,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[j,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.databases))if(j.engine==="dynamodb"){let{table:yt,logicalId:G}=or.createTable({slug:u,environment:f,tableName:`${u}-${f}-${ze}`,partitionKey:j.partitionKey||{name:"id",type:"S"},sortKey:j.sortKey});this.builder.addResource(G,yt)}else if(j.engine==="postgres"){let{dbInstance:yt,logicalId:G}=or.createPostgres({slug:u,environment:f,dbInstanceIdentifier:`${u}-${f}-${ze}`,masterUsername:j.username||"admin",masterUserPassword:j.password||"changeme123",allocatedStorage:j.storage||20,dbInstanceClass:j.instanceClass||"db.t3.micro"});this.builder.addResource(G,yt)}else if(j.engine==="mysql"){let{dbInstance:yt,logicalId:G}=or.createMysql({slug:u,environment:f,dbInstanceIdentifier:`${u}-${f}-${ze}`,masterUsername:j.username||"admin",masterUserPassword:j.password||"changeme123",allocatedStorage:j.storage||20,dbInstanceClass:j.instanceClass||"db.t3.micro"});this.builder.addResource(G,yt)}}if(this.mergedConfig.infrastructure?.cdn)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!j.origin)continue;let yt=typeof j.customDomain==="string"?j.customDomain:j.customDomain?.domain||j.domain,G=typeof j.customDomain==="object"?j.customDomain?.certificateArn:j.certificateArn,ht=G||z,St=`${u}${f}${ze}CDN`.replace(/[^a-zA-Z0-9]/g,""),Wt=`S3-${u}-${f}-${ze}-cdn`,zt=[{Id:Wt,DomainName:j.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:j.originShield?{Enabled:!0,OriginShieldRegion:j.originShieldRegion||this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...ce(j,`infrastructure.cdn.${ze}`)}],jt=[],Kt=[],Sr=["GET","HEAD","OPTIONS"],Or=Wt,Xt;if(j.failoverOrigin){Tt(Sr,`the default cache behavior of infrastructure.cdn.${ze}`);let Hr=`${Wt}-failover`,Nr=typeof j.failoverOrigin==="string"?{domain:j.failoverOrigin}:j.failoverOrigin;if(!Nr.domain)throw Error(`infrastructure.cdn.${ze}.failoverOrigin.domain is required`);if(Nr.domain===j.origin)throw Error(`infrastructure.cdn.${ze}: failoverOrigin must differ from origin (both are ${j.origin})`);zt.push({Id:Hr,DomainName:Nr.domain,OriginPath:Nr.originPath||"",...xo(Nr.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...ce(Nr,`infrastructure.cdn.${ze}.failoverOrigin`)}),Xt=an({primaryOriginId:Wt,secondaryOriginId:Hr,statusCodes:j.failoverStatusCodes}),Or=Xt.Items[0].Id}else if(j.failoverStatusCodes)throw Error(`infrastructure.cdn.${ze}: failoverStatusCodes needs failoverOrigin to fail over to`);if(j.routeCompute)this.appendComputeAppOrigin(zt,jt,Kt,u,f,this.resolveComputeCachePathPatterns(j.computeRoutes));let Pr=ht&&yt?{AcmCertificateArn:L&&!G?{Ref:L}:ht,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Fr=[...Kt];if(L&&!G&&yt)Fr.push(L);let Qr={Type:"AWS::CloudFront::Distribution",...Fr.length>0?{DependsOn:Fr}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${f} ${ze} CDN`,DefaultRootObject:"index.html",Origins:zt,...Xt?{OriginGroups:Xt}:{},DefaultCacheBehavior:{TargetOriginId:Or,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:Sr,CachedMethods:["GET","HEAD","OPTIONS"],Compress:j.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...jt.length>0?{CacheBehaviors:jt}:{},...yt&&ht?{Aliases:[yt]}:{},ViewerCertificate:Pr,PriceClass:"PriceClass_100",HttpVersion:j.http3?"http2and3":"http2"}}};if(wt(Qr.Properties.DistributionConfig,`infrastructure.cdn.${ze}`),this.builder.addResource(St,Qr),E&&yt&&ht){let Hr=yt.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Hr}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[St,...L&&!G?[L]:[]],Properties:{HostedZoneId:E,Name:yt,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[St,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(j))continue;let{queue:yt,logicalId:G}=J.createQueue({slug:u,environment:f,name:`${u}-${f}-${ze}`,fifo:j.fifo,visibilityTimeout:j.visibilityTimeout,messageRetentionPeriod:j.messageRetentionPeriod,delaySeconds:j.delaySeconds,maxMessageSize:j.maxMessageSize,receiveMessageWaitTime:j.receiveMessageWaitTime,contentBasedDeduplication:j.contentBasedDeduplication,encrypted:j.encrypted,kmsKeyId:j.kmsKeyId});this.builder.addResource(G,yt);let ht;if(j.deadLetterQueue){let{deadLetterQueue:St,updatedSourceQueue:Wt,deadLetterLogicalId:zt}=J.createDeadLetterQueue(G,{slug:u,environment:f,maxReceiveCount:j.maxReceiveCount});ht=zt,this.builder.addResource(zt,St);let Kt=this.builder.getResources()[G];if(Kt?.Properties)Kt.Properties.RedrivePolicy=Wt.Properties?.RedrivePolicy}if(j.trigger){let St=j.trigger,Wt=`${u}${f}${St.functionName}`.replace(/[^a-zA-Z0-9]/g,""),zt={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[G,"Arn"]},FunctionName:{Ref:Wt},BatchSize:St.batchSize||10,MaximumBatchingWindowInSeconds:St.batchWindow||0,Enabled:!0,...St.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...St.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:St.maxConcurrency}},...St.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(St.filterPattern)}]}}},DependsOn:[G,Wt]};this.builder.addResource(`${G}Trigger`,zt)}if(j.alarms?.enabled){let St=j.alarms,Wt=St.notificationTopicArn;if(!Wt&&St.notificationEmails?.length){let Kt=`${G}AlarmTopic`;this.builder.addResource(Kt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${f}-${ze}-alarms`,DisplayName:`${ze} Queue Alarms`}}),St.notificationEmails.forEach((Sr,Or)=>{this.builder.addResource(`${Kt}Sub${Or}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Kt},Protocol:"email",Endpoint:Sr}})}),Wt={Ref:Kt}}let zt=St.queueDepthThreshold||1000;this.builder.addResource(`${G}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${ze}-queue-depth`,AlarmDescription:`Queue ${ze} depth exceeds ${zt} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:zt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Wt&&{AlarmActions:[Wt],OKActions:[Wt]}}});let jt=St.messageAgeThreshold||3600;if(this.builder.addResource(`${G}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${ze}-message-age`,AlarmDescription:`Queue ${ze} oldest message exceeds ${jt} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:jt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Wt&&{AlarmActions:[Wt],OKActions:[Wt]}}}),ht&&St.dlqAlarm!==!1)this.builder.addResource(`${ht}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${ze}-dlq-messages`,AlarmDescription:`Dead letter queue for ${ze} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ht,"QueueName"]}}],...Wt&&{AlarmActions:[Wt]}}})}if(j.subscribe){let St=j.subscribe,Wt=St.topicArn;if(!Wt&&St.topicName)Wt={Ref:St.topicName};if(Wt){this.builder.addResource(`${G}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:G}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[G,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":Wt}}}]}}});let zt={TopicArn:Wt,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[G,"Arn"]},RawMessageDelivery:St.rawMessageDelivery||!1};if(St.filterPolicy)zt.FilterPolicy=St.filterPolicy,zt.FilterPolicyScope=St.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${G}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:zt,DependsOn:`${G}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(u,f);else this.generateRealtimeResources(u,f);let fe=this.mergedConfig.infrastructure?.redirects;if(fe){let ze=fe.target||this.mergedConfig.infrastructure?.dns?.domain||"",j=fe.protocol||"https";if(fe.domains?.length&&ze)for(let yt of fe.domains){let{bucket:G,bucketPolicy:ht,logicalId:St,policyLogicalId:Wt}=Dt.createDomainRedirectBucket({slug:u,environment:f,sourceDomain:yt,targetDomain:ze,protocol:j});this.builder.addResource(St,G),this.builder.addResource(Wt,ht)}if(fe.paths&&Object.keys(fe.paths).length>0){let yt=Dt.fromMapping(fe.paths,{statusCode:fe.statusCode||301}),{function:G,logicalId:ht}=Dt.createPathRedirectFunction({slug:u,environment:f,rules:yt});this.builder.addResource(ht,G)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:yt,logicalId:G}=Lo.createAlarm({slug:u,environment:f,alarmName:`${u}-${f}-${ze}`,metricName:j.metricName||"Errors",namespace:j.namespace||"AWS/Lambda",threshold:j.threshold||1,comparisonOperator:j.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(G,yt)}let me=this.mergedConfig.infrastructure?.cache;if(me){let ze=me.type||"redis";if(ze==="redis"){this.generateNetworkInfrastructure(u,f);let j=me.redis||{},{replicationGroup:yt,subnetGroup:G,logicalId:ht,subnetGroupId:St}=_o.createRedis({slug:u,environment:f,nodeType:j.nodeType||me.nodeType||"cache.t3.micro",engineVersion:j.engineVersion||"7.1",port:j.port||6379,numCacheClusters:j.numCacheNodes||2,automaticFailover:j.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:j.snapshotRetentionLimit||7,snapshotWindow:j.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(ht,yt),G&&St)this.builder.addResource(St,G);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[ht,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[ht,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(ze==="memcached"){this.generateNetworkInfrastructure(u,f);let j=me.elasticache||{},{cluster:yt,subnetGroup:G,logicalId:ht,subnetGroupId:St}=_o.createMemcached({slug:u,environment:f,nodeType:j.nodeType||me.nodeType||"cache.t3.micro",engineVersion:j.engineVersion||"1.6.22",numCacheNodes:j.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(ht,yt),G&&St)this.builder.addResource(St,G);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[ht,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let At=this.mergedConfig.infrastructure?.email;if(At){let ze=At.domain||this.mergedConfig.infrastructure?.dns?.domain;if(ze){let{emailIdentity:j,logicalId:yt}=m.verifyDomain({domain:ze,slug:u,environment:f,enableDkim:At.enableDkim!==!1,dkimKeyLength:At.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(yt,j),At.configurationSet!==!1){let{configurationSet:St,logicalId:Wt}=m.createConfigurationSet({slug:u,environment:f});this.builder.addResource(Wt,St)}let G=At.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(G){if(At.enableDkim!==!1)for(let Kt=1;Kt<=3;Kt++){let Sr=`DkimRecord${Kt}${ze.replace(/\./g,"")}`;this.builder.addResource(Sr,{Type:"AWS::Route53::RecordSet",DependsOn:[yt],Properties:{HostedZoneId:G,Name:{"Fn::GetAtt":[yt,`DkimDNSTokenName${Kt}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[yt,`DkimDNSTokenValue${Kt}`]}]}})}let{record:St,logicalId:Wt}=m.createSpfRecord(ze,G);this.builder.addResource(Wt,St);let{record:zt,logicalId:jt}=m.createDmarcRecord(ze,G,{policy:"none",reportingEmail:At.dmarcReportingEmail||`dmarc-reports@${ze}`});this.builder.addResource(jt,zt)}this.builder.addOutput("EmailDomain",{Value:ze,Description:"SES verified email domain"});let ht=At.server;if(ht?.enabled&&G){let St=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",Wt=`${u}-${f}-email`,{role:zt,policy:jt,roleLogicalId:Kt,policyLogicalId:Sr}=m.createEmailLambdaRole({slug:u,environment:f,s3BucketArn:`arn:aws:s3:::${Wt}`,sesIdentityArn:`arn:aws:ses:${St}:*:identity/${ze}`});this.builder.addResource(Kt,zt),this.builder.addResource(Sr,jt);let{function:Or,permission:Xt,logicalId:Pr,permissionLogicalId:Fr}=m.createInboundEmailLambda({slug:u,environment:f,roleArn:{"Fn::GetAtt":[Kt,"Arn"]},s3BucketName:Wt,organizedPrefix:"mailboxes/"});this.builder.addResource(Pr,Or),this.builder.addResource(Fr,Xt);let Qr=m.createInboundEmailSetup({slug:u,environment:f,domain:ze,s3BucketName:Wt,s3KeyPrefix:"inbox/",region:St,hostedZoneId:G,lambdaFunctionArn:{"Fn::GetAtt":[Pr,"Arn"]}});for(let[Nr,pn]of Object.entries(Qr.resources)){if(pn.Type==="AWS::SES::ReceiptRule")pn.DependsOn=[Fr,Pr];this.builder.addResource(Nr,pn)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:Pr},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:Wt,Description:"S3 bucket for email storage"});let Hr=this.serverEipLogicalIds.get("app");if(Hr&&G){let pn=`${ht?.subdomain||"mail"}.${ze}`,Wn=pn.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Wn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:G,Name:pn,Type:"A",TTL:"300",ResourceRecords:[{Ref:Hr}]}})}this.builder.addOutput("MailHost",{Value:`mail.${ze}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let Lt=this.mergedConfig.infrastructure?.search;if(Lt){let ze=Lt.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(ze)this.generateNetworkInfrastructure(u,f);let{domain:j,logicalId:yt}=ar.createDomain({slug:u,environment:f,engineVersion:Lt.engineVersion||"OpenSearch_2.11",instanceType:Lt.instanceType||"t3.small.search",instanceCount:Lt.instanceCount||1,volumeSize:Lt.volumeSize||10,volumeType:Lt.volumeType||"gp3",dedicatedMaster:Lt.dedicatedMaster||!1,dedicatedMasterType:Lt.dedicatedMasterType,dedicatedMasterCount:Lt.dedicatedMasterCount||3,multiAz:Lt.multiAz||!1,encryption:Lt.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:Lt.advancedSecurity,autoTune:Lt.autoTune!==!1,vpc:ze});this.builder.addResource(yt,j),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[yt,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[yt,"Arn"]},Description:"OpenSearch domain ARN"})}let mt=this.mergedConfig.infrastructure?.fileSystem;if(mt&&Object.keys(mt).length>0){this.generateNetworkInfrastructure(u,f);for(let[ze,j]of Object.entries(mt)){let{fileSystem:yt,logicalId:G}=Ze.createFileSystem({slug:`${u}-${ze}`,environment:f,encrypted:j.encrypted!==!1,performanceMode:j.performanceMode||"generalPurpose",throughputMode:j.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(G,yt);let{securityGroup:ht,logicalId:St}=Ze.createEfsSecurityGroup({slug:`${u}-${ze}`,environment:f,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(St,ht);let{mountTargets:Wt,logicalIds:zt}=Ze.createMultiAzMountTargets(G,{slug:`${u}-${ze}`,environment:f,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:St}});for(let jt=0;jt<Wt.length;jt++)this.builder.addResource(zt[jt],Wt[jt]);this.builder.addOutput(`${ze}FileSystemId`,{Value:{Ref:G},Description:`EFS file system ID for ${ze}`})}}let Me=this.mergedConfig.infrastructure?.ai;if(Me){let ze=Me.service||"ecs",j=Me.models||["*"],yt=Me.allowStreaming!==!1,G;if(ze==="ecs")G=Oe.enableBedrockForEcs({slug:u,environment:f,models:j,allowStreaming:yt});else if(ze==="ec2")G=Oe.enableBedrockForEc2({slug:u,environment:f,models:j,allowStreaming:yt});else if(ze==="lambda")G=Oe.enableBedrockForLambda({slug:u,environment:f,models:j,allowStreaming:yt});else G=Oe.createBedrockRole(ze,{slug:u,environment:f,models:j,allowStreaming:yt});if(this.builder.addResource(G.logicalId,G.role),Me.allowAsync){let{policy:ht,logicalId:St}=Oe.createBedrockPolicy({slug:u,environment:f,models:j,allowStreaming:yt,allowAsync:!0});this.builder.addResource(St,ht)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[G.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(u,f){let R=this.mergedConfig.infrastructure?.realtime;if(!R)return;let A=R.name||`${u}-${f}-realtime`,T=R.scaling||{},E=R.storage||{type:"dynamodb"},P=T.handlerMemory||256,L=T.handlerTimeout||30,z=`${u}${f}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),fe=`${u}${f}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(E.type==="dynamodb"){let zt=E.dynamodb||{},jt=zt.billingMode||"PAY_PER_REQUEST";this.builder.addResource(z,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${f}-realtime-connections`,BillingMode:jt,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"},...jt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:zt.readCapacity||5,WriteCapacityUnits:zt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...jt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:zt.readCapacity||5,WriteCapacityUnits:zt.writeCapacity||5}},...zt.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${u}-${f}-realtime-connections`},{Key:"Environment",Value:f}]}}),this.builder.addResource(fe,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${f}-realtime-channels`,BillingMode:jt,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"},...jt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:zt.readCapacity||5,WriteCapacityUnits:zt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...jt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:zt.readCapacity||5,WriteCapacityUnits:zt.writeCapacity||5}},Tags:[{Key:"Name",Value:`${u}-${f}-realtime-channels`},{Key:"Environment",Value:f}]}})}let me=`${u}${f}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-realtime-handler-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"RealtimeHandlerPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:UpdateItem"],Resource:[{"Fn::GetAtt":[z,"Arn"]},{"Fn::Sub":`\${${z}.Arn}/index/*`},{"Fn::GetAtt":[fe,"Arn"]},{"Fn::Sub":`\${${fe}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let At=`${u}${f}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),Lt=`${u}${f}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),mt=`${u}${f}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(At,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[me,z]}),this.builder.addResource(Lt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[me,z,fe]}),this.builder.addResource(mt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[me,z,fe]});let Me=`${u}${f}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:A,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:A,Environment:f}}});let ze=`${At}Permission`,j=`${Lt}Permission`,yt=`${mt}Permission`;this.builder.addResource(ze,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:At},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$connect`}}}),this.builder.addResource(j,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Lt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$disconnect`}}}),this.builder.addResource(yt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:mt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$default`}}});let G=`${Me}ConnectInteg`,ht=`${Me}DisconnectInteg`,St=`${Me}MessageInteg`;this.builder.addResource(G,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Me},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${At}.Arn}/invocations`}}}),this.builder.addResource(ht,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Me},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Lt}.Arn}/invocations`}}}),this.builder.addResource(St,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Me},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${mt}.Arn}/invocations`}}}),this.builder.addResource(`${Me}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Me},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${G}}`}}}),this.builder.addResource(`${Me}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Me},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${ht}}`}}}),this.builder.addResource(`${Me}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Me},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${St}}`}}});let Wt=`${Me}Stage`;if(this.builder.addResource(Wt,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Me},StageName:f,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:T.messagesPerSecond||1000,ThrottlingRateLimit:T.messagesPerSecond||1000}}}),R.monitoring?.enabled){let zt=R.monitoring,jt=zt.notificationTopicArn;if(!jt&&zt.notificationEmails?.length){let Kt=`${Me}AlarmTopic`;this.builder.addResource(Kt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${f}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),zt.notificationEmails.forEach((Sr,Or)=>{this.builder.addResource(`${Kt}Sub${Or}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Kt},Protocol:"email",Endpoint:Sr}})}),jt={Ref:Kt}}if(zt.connectionThreshold)this.builder.addResource(`${Me}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${zt.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:zt.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Me}}],...jt&&{AlarmActions:[jt]}}});if(zt.errorThreshold)this.builder.addResource(`${Me}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${zt.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:zt.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Me}}],...jt&&{AlarmActions:[jt]}}})}this.builder.addOutput(`${Me}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${Me}}.execute-api.\${AWS::Region}.amazonaws.com/${f}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${Me}Id`,{Description:"WebSocket API ID",Value:{Ref:Me},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
13
+ `:Lt,ze=T.map(([,zt])=>zt.port).filter((zt)=>typeof zt==="number"&&![80,443].includes(zt)),j=this.resolveApiOriginPort(),yt=`${u}${f}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),G=`${u}-${f}-deploy`;this.builder.addResource(yt,{Type:"AWS::S3::Bucket",Properties:{BucketName:G,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:u},{Key:"Environment",Value:f},{Key:"ManagedBy",Value:"ts-cloud"}]}});let ht=a.createServerModeStack({slug:`${u}-app`,environment:f,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:me,keyName:R.allowSsh?`${u}-${f}`:void 0,domain:P,userData:Me,volumeSize:R.disk?.size||20,imageId:R.image,allowedPorts:[...R.allowSsh?[22]:[],80,443,j,...ze]}),St=ht.resources[ht.outputs.instanceLogicalId];if(St?.Properties){let zt=St.Properties.Tags||[];St.Properties.Tags=[...zt,{Key:"Project",Value:u},{Key:"Environment",Value:f},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let Wt=ht.resources[ht.outputs.roleLogicalId];if(Wt?.Properties)Wt.Properties.Policies=Wt.Properties.Policies||[],Wt.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${G}`,`arn:aws:s3:::${G}/*`]}]}});for(let[zt,jt]of Object.entries(ht.resources))this.builder.addResource(zt,jt);this.builder.addOutput("deployBucketName",{Value:{Ref:yt},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:ht.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:ht.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",ht.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",ht.outputs.instanceLogicalId)}jumpBoxFileSystemId(u,f,R){let A=Object.keys(this.mergedConfig.infrastructure?.fileSystem??{});if(typeof R==="string")return A.includes(R)?{Ref:this.fileSystemLogicalId(u,f,R)}:R;if(A.length===1)return{Ref:this.fileSystemLogicalId(u,f,A[0])};throw Error(A.length===0?"infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares no file system. Declare one, or set mountEfs to an EFS id.":`infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares ${A.length} (${A.join(", ")}). Set mountEfs to the name of the one to mount.`)}generateJumpBox(u,f){let R=this.mergedConfig.infrastructure?.jumpBox;if(!R)return;let A=R===!0?{}:R;if(A.enabled===!1)return;this.generateNetworkInfrastructure(u,f);let T=A.size||"micro",P=a.InstanceSize.specs[T]?.instanceType||T||"t3.micro",L=a.createJumpBox({slug:u,environment:f,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:A.keyName,instanceType:P,allowedCidrs:A.allowedCidrs,mountEfs:A.mountEfs?{fileSystemId:this.jumpBoxFileSystemId(u,f,A.mountEfs),mountPath:A.mountPath||"/mnt/efs"}:void 0,databaseTools:A.databaseTools});for(let[z,fe]of Object.entries(L.resources))this.builder.addResource(z,fe);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:L.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(u,f){let R=this.mergedConfig.infrastructure?.ssl,A=this.mergedConfig.infrastructure?.dns,T=A?.domain,E=A?.hostedZoneId,P=[],L,z;if(R?.certificateArn)z=R.certificateArn;else if(R?.enabled&&T&&E){let ze=R.domains||[T],j=ze[0],yt=ze.slice(1).map((St)=>{if(St.includes(".")&&St.endsWith(j))return St.replace(`.${j}`,"");return St}),{certificate:G,logicalId:ht}=C.createCertificate({domain:j,subdomains:yt,slug:u,environment:f,validationMethod:"DNS",hostedZoneId:E});L=ht,this.builder.addResource(ht,G)}if(this.mergedConfig.infrastructure?.storage){let ze=Object.entries(this.mergedConfig.infrastructure.storage).some(([,G])=>G.website),j;if(ze&&(L||z))j=`${u}${f}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(j,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${u}-${f}-s3-oac`,Description:`OAC for ${u} ${f} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let yt=Object.entries(this.mergedConfig.infrastructure.storage).map(([G,ht])=>({name:G,config:ht,mountPath:this.normalizeMountPath(ht),rewriteStyle:ht.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(u,f,G)})).filter((G)=>G.name!=="public"&&G.config.website&&G.mountPath);for(let[G,ht]of Object.entries(this.mergedConfig.infrastructure.storage)){let St=!!(ht.website&&j),Wt=this.storageBucketName(u,f,G),{bucket:zt,logicalId:jt}=xe.createBucket({slug:u,name:G,environment:f,bucketName:Wt,versioning:ht.versioning,encryption:ht.encryption,public:St?!1:ht.public}),Kt=this.normalizeMountPath(ht),Sr;if(ht.failover){let Xt=`infrastructure.storage.${G}`;if(!St||!T||Kt&&G!=="public")throw Error(`${Xt}.failover needs this bucket to be served by its own CloudFront distribution: a website bucket (website: true), not mounted under the path of another site, with infrastructure.dns.domain set and SSL configured (infrastructure.ssl.certificateArn, or ssl.enabled with dns.hostedZoneId).`);if(Sr=ym({failover:ht.failover,primaryBucket:Wt,primaryRegion:this.mergedConfig.project.region||"us-east-1",where:Xt}),Sr.replicate&&zt.Properties){let Pr=`${jt}FailoverReplicationRole`;this.builder.addResource(Pr,Im({primaryBucket:Wt,replicaBucket:Sr.replicaBucket}));let Vr=zt.Properties;Vr.VersioningConfiguration={Status:"Enabled"},Vr.ReplicationConfiguration=bm({replicaBucket:Sr.replicaBucket,roleArn:{"Fn::GetAtt":[Pr,"Arn"]}})}}if(St&&zt.Properties)zt.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(jt,zt),ht.website){let Xt=typeof ht.website==="object"?ht.website:{},Pr=xe.enableWebsiteHosting(zt,Xt.indexDocument||"index.html",Xt.errorDocument);this.builder.addResource(jt,Pr)}let Or=this.normalizeMountPath(ht);if(St&&j&&T&&!(Or&&G!=="public")){let Xt=`${u}${f}${G}CDN`.replace(/[^a-zA-Z0-9]/g,""),Pr=[];if(ht.aliases&&ht.aliases.length>0)Pr.push(...ht.aliases);else if(G==="public"){if(Pr.push(T),R?.domains?.includes(`www.${T}`))Pr.push(`www.${T}`)}else if(G==="docs")Pr.push(`docs.${T}`);else if(G==="blog")Pr.push(`blog.${T}`);let Vr=typeof ht.website==="object"?ht.website:{},Gr=ht.spa===!0,Hr=Vr.errorDocument||(Gr?"index.html":"404.html"),Nr=[];if(Gr)Nr.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else Nr.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${Hr}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${Hr}`,ErrorCachingMinTTL:300});let mn=z&&Pr.length>0?{AcmCertificateArn:z,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:L&&Pr.length>0?{AcmCertificateArn:{Ref:L},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Jn=`S3-${u}-${f}-${G}`,Ic=this.mergedConfig.project.region||"us-east-1",si;if(!Gr)si=`${u}${f}${G}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(si,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${f}-${G}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${u} ${f} ${G} - 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 Di=[{Id:Jn,DomainName:{"Fn::Sub":`\${${jt}}.s3.${Ic}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}],Ps=[],Oc=[];if(this.shouldRouteStorageBucketToCompute(G,ht)){this.appendComputeAppOrigin(Di,Ps,Oc,u,f,this.resolveComputeCachePathPatterns(ht.computeRoutes));for(let kr of yt){let Os=`S3-${u}-${f}-${kr.name}`,Mc=`${u}${f}${kr.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Mc,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${f}-${kr.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${u} ${f} ${kr.name} at ${kr.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(kr.mountPath,kr.rewriteStyle)}}),Di.push({Id:Os,DomainName:{"Fn::Sub":`\${${kr.logicalId}}.s3.${Ic}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),Oc.push(kr.logicalId,Mc);for(let fp of[kr.mountPath,`${kr.mountPath}/*`])Ps.push({PathPattern:fp,TargetOriginId:Os,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":[Mc,"FunctionARN"]}}]})}}let ks,Xc=Jn;if(Sr){let kr=`${Jn}-failover`;Object.assign(Di[0],Sr.primaryConnection),Di.push({Id:kr,DomainName:Sm(Sr.replicaBucket,Sr.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),ks=cn({primaryOriginId:Jn,secondaryOriginId:kr,statusCodes:Sr.statusCodes}),Xc=ks.Items[0].Id}let xc={Type:"AWS::CloudFront::Distribution",DependsOn:[jt,j,...si?[si]:[],...Oc],Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${f} ${G} site`,DefaultRootObject:"index.html",Origins:Di,...ks?{OriginGroups:ks}:{},DefaultCacheBehavior:{TargetOriginId:Xc,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...si?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[si,"FunctionARN"]}}]}:{}},...Ps.length>0?{CacheBehaviors:Ps}:{},...Pr.length>0?{Aliases:Pr}:{},ViewerCertificate:mn,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:Nr}}};if(L)xc.DependsOn.push(L);if(Sr)wt(xc.Properties.DistributionConfig,`infrastructure.storage.${G}`),this.storageFailoverReplicas.push({name:G,primaryBucket:Wt,primaryRegion:Ic,replicaBucket:Sr.replicaBucket,replicaRegion:Sr.replicaRegion,replicate:Sr.replicate,distributionArnOutput:`${G}CloudFrontDistributionArn`}),this.builder.addOutput(`${G}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`},Description:`CloudFront distribution ARN for ${G} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${G}FailoverBucketName`,{Value:Sr.replicaBucket,Description:`Failover replica bucket for ${G} (${Sr.replicaRegion}), outside this stack`});this.builder.addResource(Xt,xc);let gp=`${jt}CloudFrontPolicy`;if(this.builder.addResource(gp,{Type:"AWS::S3::BucketPolicy",DependsOn:[jt,Xt],Properties:{Bucket:{Ref:jt},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${jt}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(G,ht))for(let kr of yt){let Os=`${kr.logicalId}CloudFrontPolicy`;this.builder.addResource(Os,{Type:"AWS::S3::BucketPolicy",DependsOn:[kr.logicalId,Xt],Properties:{Bucket:{Ref:kr.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:::\${${kr.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`}}}}]}}})}if(Pr.length>0)P.push({name:G,bucketLogicalId:jt,distLogicalId:Xt,oacLogicalId:j,aliases:Pr});this.builder.addOutput(`${G}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Xt,"DomainName"]},Description:`CloudFront domain for ${G}`}),this.builder.addOutput(`${G}CloudFrontDistributionId`,{Value:{Ref:Xt},Description:`CloudFront distribution ID for ${G}`})}if(this.builder.addOutput(`${G}BucketName`,{Value:{Ref:jt},Description:`S3 bucket name for ${G}`}),G==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:jt},Description:"Frontend S3 bucket name"});if(G==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:jt},Description:"Documentation S3 bucket name"});if(G==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:jt},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let ze=this.mergedConfig.infrastructure.sftp,j=ul.create({...ze,storage:this.resolveSftpStorage(ze,u,f)??ze.storage,slug:u,environment:f});for(let[yt,G]of Object.entries(j.resources))this.builder.addResource(yt,G);this.builder.addOutput("SftpServerId",{Value:{Ref:j.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${j.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:j.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(E&&P.length>0)for(let{name:ze,distLogicalId:j,aliases:yt}of P)for(let G of yt){let ht=G.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${ht}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[j],Properties:{HostedZoneId:E,Name:G,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[j,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${ht}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[j],Properties:{HostedZoneId:E,Name:G,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[j,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.databases))if(j.engine==="dynamodb"){let{table:yt,logicalId:G}=or.createTable({slug:u,environment:f,tableName:`${u}-${f}-${ze}`,partitionKey:j.partitionKey||{name:"id",type:"S"},sortKey:j.sortKey});this.builder.addResource(G,yt)}else if(j.engine==="postgres"){let{dbInstance:yt,logicalId:G}=or.createPostgres({slug:u,environment:f,dbInstanceIdentifier:`${u}-${f}-${ze}`,masterUsername:j.username||"admin",masterUserPassword:j.password||"changeme123",allocatedStorage:j.storage||20,dbInstanceClass:j.instanceClass||"db.t3.micro"});this.builder.addResource(G,yt)}else if(j.engine==="mysql"){let{dbInstance:yt,logicalId:G}=or.createMysql({slug:u,environment:f,dbInstanceIdentifier:`${u}-${f}-${ze}`,masterUsername:j.username||"admin",masterUserPassword:j.password||"changeme123",allocatedStorage:j.storage||20,dbInstanceClass:j.instanceClass||"db.t3.micro"});this.builder.addResource(G,yt)}}if(this.mergedConfig.infrastructure?.cdn)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!j.origin)continue;let yt=typeof j.customDomain==="string"?j.customDomain:j.customDomain?.domain||j.domain,G=typeof j.customDomain==="object"?j.customDomain?.certificateArn:j.certificateArn,ht=G||z,St=`${u}${f}${ze}CDN`.replace(/[^a-zA-Z0-9]/g,""),Wt=`S3-${u}-${f}-${ze}-cdn`,zt=[{Id:Wt,DomainName:j.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:j.originShield?{Enabled:!0,OriginShieldRegion:j.originShieldRegion||this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...ce(j,`infrastructure.cdn.${ze}`)}],jt=[],Kt=[],Sr=["GET","HEAD","OPTIONS"],Or=Wt,Xt;if(j.failoverOrigin){Tt(Sr,`the default cache behavior of infrastructure.cdn.${ze}`);let Hr=`${Wt}-failover`,Nr=typeof j.failoverOrigin==="string"?{domain:j.failoverOrigin}:j.failoverOrigin;if(!Nr.domain)throw Error(`infrastructure.cdn.${ze}.failoverOrigin.domain is required`);if(Nr.domain===j.origin)throw Error(`infrastructure.cdn.${ze}: failoverOrigin must differ from origin (both are ${j.origin})`);zt.push({Id:Hr,DomainName:Nr.domain,OriginPath:Nr.originPath||"",...Fo(Nr.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...ce(Nr,`infrastructure.cdn.${ze}.failoverOrigin`)}),Xt=cn({primaryOriginId:Wt,secondaryOriginId:Hr,statusCodes:j.failoverStatusCodes}),Or=Xt.Items[0].Id}else if(j.failoverStatusCodes)throw Error(`infrastructure.cdn.${ze}: failoverStatusCodes needs failoverOrigin to fail over to`);if(j.routeCompute)this.appendComputeAppOrigin(zt,jt,Kt,u,f,this.resolveComputeCachePathPatterns(j.computeRoutes));let Pr=ht&&yt?{AcmCertificateArn:L&&!G?{Ref:L}:ht,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Vr=[...Kt];if(L&&!G&&yt)Vr.push(L);let Gr={Type:"AWS::CloudFront::Distribution",...Vr.length>0?{DependsOn:Vr}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${f} ${ze} CDN`,DefaultRootObject:"index.html",Origins:zt,...Xt?{OriginGroups:Xt}:{},DefaultCacheBehavior:{TargetOriginId:Or,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:Sr,CachedMethods:["GET","HEAD","OPTIONS"],Compress:j.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...jt.length>0?{CacheBehaviors:jt}:{},...yt&&ht?{Aliases:[yt]}:{},ViewerCertificate:Pr,PriceClass:"PriceClass_100",HttpVersion:j.http3?"http2and3":"http2"}}};if(wt(Gr.Properties.DistributionConfig,`infrastructure.cdn.${ze}`),this.builder.addResource(St,Gr),E&&yt&&ht){let Hr=yt.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Hr}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[St,...L&&!G?[L]:[]],Properties:{HostedZoneId:E,Name:yt,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[St,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(j))continue;let{queue:yt,logicalId:G}=J.createQueue({slug:u,environment:f,name:`${u}-${f}-${ze}`,fifo:j.fifo,visibilityTimeout:j.visibilityTimeout,messageRetentionPeriod:j.messageRetentionPeriod,delaySeconds:j.delaySeconds,maxMessageSize:j.maxMessageSize,receiveMessageWaitTime:j.receiveMessageWaitTime,contentBasedDeduplication:j.contentBasedDeduplication,encrypted:j.encrypted,kmsKeyId:j.kmsKeyId});this.builder.addResource(G,yt);let ht;if(j.deadLetterQueue){let{deadLetterQueue:St,updatedSourceQueue:Wt,deadLetterLogicalId:zt}=J.createDeadLetterQueue(G,{slug:u,environment:f,maxReceiveCount:j.maxReceiveCount});ht=zt,this.builder.addResource(zt,St);let Kt=this.builder.getResources()[G];if(Kt?.Properties)Kt.Properties.RedrivePolicy=Wt.Properties?.RedrivePolicy}if(j.trigger){let St=j.trigger,Wt=`${u}${f}${St.functionName}`.replace(/[^a-zA-Z0-9]/g,""),zt={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[G,"Arn"]},FunctionName:{Ref:Wt},BatchSize:St.batchSize||10,MaximumBatchingWindowInSeconds:St.batchWindow||0,Enabled:!0,...St.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...St.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:St.maxConcurrency}},...St.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(St.filterPattern)}]}}},DependsOn:[G,Wt]};this.builder.addResource(`${G}Trigger`,zt)}if(j.alarms?.enabled){let St=j.alarms,Wt=St.notificationTopicArn;if(!Wt&&St.notificationEmails?.length){let Kt=`${G}AlarmTopic`;this.builder.addResource(Kt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${f}-${ze}-alarms`,DisplayName:`${ze} Queue Alarms`}}),St.notificationEmails.forEach((Sr,Or)=>{this.builder.addResource(`${Kt}Sub${Or}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Kt},Protocol:"email",Endpoint:Sr}})}),Wt={Ref:Kt}}let zt=St.queueDepthThreshold||1000;this.builder.addResource(`${G}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${ze}-queue-depth`,AlarmDescription:`Queue ${ze} depth exceeds ${zt} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:zt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Wt&&{AlarmActions:[Wt],OKActions:[Wt]}}});let jt=St.messageAgeThreshold||3600;if(this.builder.addResource(`${G}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${ze}-message-age`,AlarmDescription:`Queue ${ze} oldest message exceeds ${jt} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:jt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Wt&&{AlarmActions:[Wt],OKActions:[Wt]}}}),ht&&St.dlqAlarm!==!1)this.builder.addResource(`${ht}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${ze}-dlq-messages`,AlarmDescription:`Dead letter queue for ${ze} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ht,"QueueName"]}}],...Wt&&{AlarmActions:[Wt]}}})}if(j.subscribe){let St=j.subscribe,Wt=St.topicArn;if(!Wt&&St.topicName)Wt={Ref:St.topicName};if(Wt){this.builder.addResource(`${G}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:G}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[G,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":Wt}}}]}}});let zt={TopicArn:Wt,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[G,"Arn"]},RawMessageDelivery:St.rawMessageDelivery||!1};if(St.filterPolicy)zt.FilterPolicy=St.filterPolicy,zt.FilterPolicyScope=St.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${G}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:zt,DependsOn:`${G}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(u,f);else this.generateRealtimeResources(u,f);let fe=this.mergedConfig.infrastructure?.redirects;if(fe){let ze=fe.target||this.mergedConfig.infrastructure?.dns?.domain||"",j=fe.protocol||"https";if(fe.domains?.length&&ze)for(let yt of fe.domains){let{bucket:G,bucketPolicy:ht,logicalId:St,policyLogicalId:Wt}=Dt.createDomainRedirectBucket({slug:u,environment:f,sourceDomain:yt,targetDomain:ze,protocol:j});this.builder.addResource(St,G),this.builder.addResource(Wt,ht)}if(fe.paths&&Object.keys(fe.paths).length>0){let yt=Dt.fromMapping(fe.paths,{statusCode:fe.statusCode||301}),{function:G,logicalId:ht}=Dt.createPathRedirectFunction({slug:u,environment:f,rules:yt});this.builder.addResource(ht,G)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:yt,logicalId:G}=Ho.createAlarm({slug:u,environment:f,alarmName:`${u}-${f}-${ze}`,metricName:j.metricName||"Errors",namespace:j.namespace||"AWS/Lambda",threshold:j.threshold||1,comparisonOperator:j.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(G,yt)}let me=this.mergedConfig.infrastructure?.cache;if(me){let ze=me.type||"redis";if(ze==="redis"){this.generateNetworkInfrastructure(u,f);let j=me.redis||{},{replicationGroup:yt,subnetGroup:G,logicalId:ht,subnetGroupId:St}=Qo.createRedis({slug:u,environment:f,nodeType:j.nodeType||me.nodeType||"cache.t3.micro",engineVersion:j.engineVersion||"7.1",port:j.port||6379,numCacheClusters:j.numCacheNodes||2,automaticFailover:j.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:j.snapshotRetentionLimit||7,snapshotWindow:j.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(ht,yt),G&&St)this.builder.addResource(St,G);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[ht,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[ht,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(ze==="memcached"){this.generateNetworkInfrastructure(u,f);let j=me.elasticache||{},{cluster:yt,subnetGroup:G,logicalId:ht,subnetGroupId:St}=Qo.createMemcached({slug:u,environment:f,nodeType:j.nodeType||me.nodeType||"cache.t3.micro",engineVersion:j.engineVersion||"1.6.22",numCacheNodes:j.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(ht,yt),G&&St)this.builder.addResource(St,G);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[ht,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let At=this.mergedConfig.infrastructure?.email;if(At){let ze=At.domain||this.mergedConfig.infrastructure?.dns?.domain;if(ze){let{emailIdentity:j,logicalId:yt}=m.verifyDomain({domain:ze,slug:u,environment:f,enableDkim:At.enableDkim!==!1,dkimKeyLength:At.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(yt,j),At.configurationSet!==!1){let{configurationSet:St,logicalId:Wt}=m.createConfigurationSet({slug:u,environment:f});this.builder.addResource(Wt,St)}let G=At.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(G){if(At.enableDkim!==!1)for(let Kt=1;Kt<=3;Kt++){let Sr=`DkimRecord${Kt}${ze.replace(/\./g,"")}`;this.builder.addResource(Sr,{Type:"AWS::Route53::RecordSet",DependsOn:[yt],Properties:{HostedZoneId:G,Name:{"Fn::GetAtt":[yt,`DkimDNSTokenName${Kt}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[yt,`DkimDNSTokenValue${Kt}`]}]}})}let{record:St,logicalId:Wt}=m.createSpfRecord(ze,G);this.builder.addResource(Wt,St);let{record:zt,logicalId:jt}=m.createDmarcRecord(ze,G,{policy:"none",reportingEmail:At.dmarcReportingEmail||`dmarc-reports@${ze}`});this.builder.addResource(jt,zt)}this.builder.addOutput("EmailDomain",{Value:ze,Description:"SES verified email domain"});let ht=At.server;if(ht?.enabled&&G){let St=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",Wt=`${u}-${f}-email`,{role:zt,policy:jt,roleLogicalId:Kt,policyLogicalId:Sr}=m.createEmailLambdaRole({slug:u,environment:f,s3BucketArn:`arn:aws:s3:::${Wt}`,sesIdentityArn:`arn:aws:ses:${St}:*:identity/${ze}`});this.builder.addResource(Kt,zt),this.builder.addResource(Sr,jt);let{function:Or,permission:Xt,logicalId:Pr,permissionLogicalId:Vr}=m.createInboundEmailLambda({slug:u,environment:f,roleArn:{"Fn::GetAtt":[Kt,"Arn"]},s3BucketName:Wt,organizedPrefix:"mailboxes/"});this.builder.addResource(Pr,Or),this.builder.addResource(Vr,Xt);let Gr=m.createInboundEmailSetup({slug:u,environment:f,domain:ze,s3BucketName:Wt,s3KeyPrefix:"inbox/",region:St,hostedZoneId:G,lambdaFunctionArn:{"Fn::GetAtt":[Pr,"Arn"]}});for(let[Nr,mn]of Object.entries(Gr.resources)){if(mn.Type==="AWS::SES::ReceiptRule")mn.DependsOn=[Vr,Pr];this.builder.addResource(Nr,mn)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:Pr},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:Wt,Description:"S3 bucket for email storage"});let Hr=this.serverEipLogicalIds.get("app");if(Hr&&G){let mn=`${ht?.subdomain||"mail"}.${ze}`,Jn=mn.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Jn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:G,Name:mn,Type:"A",TTL:"300",ResourceRecords:[{Ref:Hr}]}})}this.builder.addOutput("MailHost",{Value:`mail.${ze}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let Lt=this.mergedConfig.infrastructure?.search;if(Lt){let ze=Lt.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(ze)this.generateNetworkInfrastructure(u,f);let{domain:j,logicalId:yt}=ar.createDomain({slug:u,environment:f,engineVersion:Lt.engineVersion||"OpenSearch_2.11",instanceType:Lt.instanceType||"t3.small.search",instanceCount:Lt.instanceCount||1,volumeSize:Lt.volumeSize||10,volumeType:Lt.volumeType||"gp3",dedicatedMaster:Lt.dedicatedMaster||!1,dedicatedMasterType:Lt.dedicatedMasterType,dedicatedMasterCount:Lt.dedicatedMasterCount||3,multiAz:Lt.multiAz||!1,encryption:Lt.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:Lt.advancedSecurity,autoTune:Lt.autoTune!==!1,vpc:ze});this.builder.addResource(yt,j),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[yt,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[yt,"Arn"]},Description:"OpenSearch domain ARN"})}let mt=this.mergedConfig.infrastructure?.fileSystem;if(mt&&Object.keys(mt).length>0){this.generateNetworkInfrastructure(u,f);for(let[ze,j]of Object.entries(mt)){let{fileSystem:yt,logicalId:G}=Ze.createFileSystem({slug:`${u}-${ze}`,environment:f,encrypted:j.encrypted!==!1,performanceMode:j.performanceMode||"generalPurpose",throughputMode:j.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(G,yt);let{securityGroup:ht,logicalId:St}=Ze.createEfsSecurityGroup({slug:`${u}-${ze}`,environment:f,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(St,ht);let{mountTargets:Wt,logicalIds:zt}=Ze.createMultiAzMountTargets(G,{slug:`${u}-${ze}`,environment:f,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:St}});for(let jt=0;jt<Wt.length;jt++)this.builder.addResource(zt[jt],Wt[jt]);this.builder.addOutput(`${ze}FileSystemId`,{Value:{Ref:G},Description:`EFS file system ID for ${ze}`})}}let Me=this.mergedConfig.infrastructure?.ai;if(Me){let ze=Me.service||"ecs",j=Me.models||["*"],yt=Me.allowStreaming!==!1,G;if(ze==="ecs")G=Oe.enableBedrockForEcs({slug:u,environment:f,models:j,allowStreaming:yt});else if(ze==="ec2")G=Oe.enableBedrockForEc2({slug:u,environment:f,models:j,allowStreaming:yt});else if(ze==="lambda")G=Oe.enableBedrockForLambda({slug:u,environment:f,models:j,allowStreaming:yt});else G=Oe.createBedrockRole(ze,{slug:u,environment:f,models:j,allowStreaming:yt});if(this.builder.addResource(G.logicalId,G.role),Me.allowAsync){let{policy:ht,logicalId:St}=Oe.createBedrockPolicy({slug:u,environment:f,models:j,allowStreaming:yt,allowAsync:!0});this.builder.addResource(St,ht)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[G.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(u,f){let R=this.mergedConfig.infrastructure?.realtime;if(!R)return;let A=R.name||`${u}-${f}-realtime`,T=R.scaling||{},E=R.storage||{type:"dynamodb"},P=T.handlerMemory||256,L=T.handlerTimeout||30,z=`${u}${f}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),fe=`${u}${f}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(E.type==="dynamodb"){let zt=E.dynamodb||{},jt=zt.billingMode||"PAY_PER_REQUEST";this.builder.addResource(z,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${f}-realtime-connections`,BillingMode:jt,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"},...jt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:zt.readCapacity||5,WriteCapacityUnits:zt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...jt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:zt.readCapacity||5,WriteCapacityUnits:zt.writeCapacity||5}},...zt.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${u}-${f}-realtime-connections`},{Key:"Environment",Value:f}]}}),this.builder.addResource(fe,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${f}-realtime-channels`,BillingMode:jt,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"},...jt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:zt.readCapacity||5,WriteCapacityUnits:zt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...jt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:zt.readCapacity||5,WriteCapacityUnits:zt.writeCapacity||5}},Tags:[{Key:"Name",Value:`${u}-${f}-realtime-channels`},{Key:"Environment",Value:f}]}})}let me=`${u}${f}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-realtime-handler-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"RealtimeHandlerPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:UpdateItem"],Resource:[{"Fn::GetAtt":[z,"Arn"]},{"Fn::Sub":`\${${z}.Arn}/index/*`},{"Fn::GetAtt":[fe,"Arn"]},{"Fn::Sub":`\${${fe}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let At=`${u}${f}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),Lt=`${u}${f}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),mt=`${u}${f}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(At,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[me,z]}),this.builder.addResource(Lt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[me,z,fe]}),this.builder.addResource(mt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[me,z,fe]});let Me=`${u}${f}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:A,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:A,Environment:f}}});let ze=`${At}Permission`,j=`${Lt}Permission`,yt=`${mt}Permission`;this.builder.addResource(ze,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:At},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$connect`}}}),this.builder.addResource(j,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Lt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$disconnect`}}}),this.builder.addResource(yt,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:mt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$default`}}});let G=`${Me}ConnectInteg`,ht=`${Me}DisconnectInteg`,St=`${Me}MessageInteg`;this.builder.addResource(G,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Me},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${At}.Arn}/invocations`}}}),this.builder.addResource(ht,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Me},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Lt}.Arn}/invocations`}}}),this.builder.addResource(St,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Me},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${mt}.Arn}/invocations`}}}),this.builder.addResource(`${Me}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Me},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${G}}`}}}),this.builder.addResource(`${Me}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Me},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${ht}}`}}}),this.builder.addResource(`${Me}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Me},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${St}}`}}});let Wt=`${Me}Stage`;if(this.builder.addResource(Wt,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Me},StageName:f,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:T.messagesPerSecond||1000,ThrottlingRateLimit:T.messagesPerSecond||1000}}}),R.monitoring?.enabled){let zt=R.monitoring,jt=zt.notificationTopicArn;if(!jt&&zt.notificationEmails?.length){let Kt=`${Me}AlarmTopic`;this.builder.addResource(Kt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${f}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),zt.notificationEmails.forEach((Sr,Or)=>{this.builder.addResource(`${Kt}Sub${Or}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Kt},Protocol:"email",Endpoint:Sr}})}),jt={Ref:Kt}}if(zt.connectionThreshold)this.builder.addResource(`${Me}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${zt.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:zt.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Me}}],...jt&&{AlarmActions:[jt]}}});if(zt.errorThreshold)this.builder.addResource(`${Me}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${zt.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:zt.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Me}}],...jt&&{AlarmActions:[jt]}}})}this.builder.addOutput(`${Me}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${Me}}.execute-api.\${AWS::Region}.amazonaws.com/${f}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${Me}Id`,{Description:"WebSocket API ID",Value:{Ref:Me},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
15
15
  const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
16
16
  const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb');
17
17
 
@@ -219,7 +219,7 @@ ${f.loadManagement?.enabled?`
219
219
  },
220
220
  `:""}
221
221
  } satisfies BroadcastConfig
222
- `}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function kg(u){let f=[],R=[];if(!u.AWSTemplateFormatVersion)f.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(u.AWSTemplateFormatVersion!=="2010-09-09")R.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!u.Resources||Object.keys(u.Resources).length===0)f.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[A,T]of Object.entries(u.Resources))vg(A,T,f,R);if(u.Resources){let A=xg(u.Resources);if(A.length>0)f.push({path:"Resources",message:`Circular dependencies detected: ${A.join(" -> ")}`,severity:"error"})}if(u.Parameters)for(let[A,T]of Object.entries(u.Parameters))Og(A,T,f,R);if(u.Outputs)for(let[A,T]of Object.entries(u.Outputs))Ng(A,T,f,R);return{valid:f.length===0,errors:f,warnings:R}}function vg(u,f,R,A){if(!f.Type)R.push({path:`Resources.${u}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(u))A.push({path:`Resources.${u}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(f.Type&&!f.Type.startsWith("AWS::")&&!f.Type.startsWith("Custom::"))R.push({path:`Resources.${u}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(f.Properties){for(let[T,E]of Object.entries(f.Properties))if(E===void 0||E===null)A.push({path:`Resources.${u}.Properties.${T}`,message:"Property has undefined or null value",severity:"warning"})}if(f.DependsOn){if(typeof f.DependsOn==="string"){if(f.DependsOn===u)R.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(f.DependsOn)){if(f.DependsOn.includes(u))R.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function Og(u,f,R,A){if(!f.Type)R.push({path:`Parameters.${u}.Type`,message:"Parameter Type is required",severity:"error"});let T=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(f.Type&&!T.includes(f.Type)&&!f.Type.startsWith("AWS::"))A.push({path:`Parameters.${u}.Type`,message:`Uncommon parameter type: ${f.Type}`,severity:"warning"});if(f.NoEcho&&f.Default)A.push({path:`Parameters.${u}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function Ng(u,f,R,A){if(!f.Value)R.push({path:`Outputs.${u}.Value`,message:"Output Value is required",severity:"error"})}function xg(u){let f={};for(let[P,L]of Object.entries(u)){if(f[P]=[],L.DependsOn){if(typeof L.DependsOn==="string")f[P].push(L.DependsOn);else if(Array.isArray(L.DependsOn))f[P].push(...L.DependsOn)}let z=Fc(L);f[P].push(...z)}let R=new Set,A=new Set,T=[];function E(P,L){R.add(P),A.add(P),L.push(P);let z=f[P]||[];for(let fe of z)if(!R.has(fe)){if(E(fe,L))return!0}else if(A.has(fe)){let me=L.indexOf(fe);return T.push(...L.slice(me),fe),!0}return L.pop(),A.delete(P),!1}for(let P of Object.keys(f))if(!R.has(P)){if(E(P,[]))return T}return[]}function Fc(u,f=[]){if(typeof u!=="object"||u===null)return f;if(Array.isArray(u)){for(let R of u)Fc(R,f);return f}if(u.Ref&&typeof u.Ref==="string"&&!u.Ref.startsWith("AWS::"))f.push(u.Ref);if(u["Fn::GetAtt"]){let R=u["Fn::GetAtt"];if(Array.isArray(R)&&R.length>0)f.push(R[0])}for(let R of Object.values(u))Fc(R,f);return f}function Lg(u){let f=[],R=[],A=new TextEncoder().encode(u).length,T=51200,E=460800;if(A>51200)if(A>460800)f.push({path:"template",message:`Template size (${A} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else R.push({path:"template",message:`Template size (${A} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:f.length===0,errors:f,warnings:R}}function Fg(u){let f=[],R=[],A=u.Resources?Object.keys(u.Resources).length:0,T=u.Parameters?Object.keys(u.Parameters).length:0,E=u.Outputs?Object.keys(u.Outputs).length:0;if(A>500)f.push({path:"Resources",message:`Template has ${A} resources, exceeding the limit of 500`,severity:"error"});else if(A>200)R.push({path:"Resources",message:`Template has ${A} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(T>200)f.push({path:"Parameters",message:`Template has ${T} parameters, exceeding the limit of 200`,severity:"error"});if(E>200)f.push({path:"Outputs",message:`Template has ${E} outputs, exceeding the limit of 200`,severity:"error"});return{valid:f.length===0,errors:f,warnings:R}}function nR(u){let{domains:f,email:R,staging:A=!1,challengeType:T="http-01",certPath:E="/etc/letsencrypt/live",autoRenew:P=!0}=u,L=f[0],z=f.map((me)=>`-d ${me}`).join(" "),fe=A?"--staging":"";if(T==="http-01")return _g({domains:f,email:R,staging:A,certPath:E,autoRenew:P,domainFlags:z,stagingFlag:fe,primaryDomain:L});else{let me=u.dnsProvider?.provider||(u.hostedZoneId?"route53":void 0);return Mg({domains:f,email:R,staging:A,certPath:E,autoRenew:P,domainFlags:z,stagingFlag:fe,primaryDomain:L,hostedZoneId:u.hostedZoneId,dnsProvider:u.dnsProvider,dnsProviderType:me})}}function _g(u){let{email:f,certPath:R,autoRenew:A,domainFlags:T,stagingFlag:E,primaryDomain:P}=u;return`
222
+ `}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function Cg(u){let f=[],R=[];if(!u.AWSTemplateFormatVersion)f.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(u.AWSTemplateFormatVersion!=="2010-09-09")R.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!u.Resources||Object.keys(u.Resources).length===0)f.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[A,T]of Object.entries(u.Resources))Sg(A,T,f,R);if(u.Resources){let A=vg(u.Resources);if(A.length>0)f.push({path:"Resources",message:`Circular dependencies detected: ${A.join(" -> ")}`,severity:"error"})}if(u.Parameters)for(let[A,T]of Object.entries(u.Parameters))bg(A,T,f,R);if(u.Outputs)for(let[A,T]of Object.entries(u.Outputs))$g(A,T,f,R);return{valid:f.length===0,errors:f,warnings:R}}function Sg(u,f,R,A){if(!f.Type)R.push({path:`Resources.${u}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(u))A.push({path:`Resources.${u}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(f.Type&&!f.Type.startsWith("AWS::")&&!f.Type.startsWith("Custom::"))R.push({path:`Resources.${u}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(f.Properties){for(let[T,E]of Object.entries(f.Properties))if(E===void 0||E===null)A.push({path:`Resources.${u}.Properties.${T}`,message:"Property has undefined or null value",severity:"warning"})}if(f.DependsOn){if(typeof f.DependsOn==="string"){if(f.DependsOn===u)R.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(f.DependsOn)){if(f.DependsOn.includes(u))R.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function bg(u,f,R,A){if(!f.Type)R.push({path:`Parameters.${u}.Type`,message:"Parameter Type is required",severity:"error"});let T=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(f.Type&&!T.includes(f.Type)&&!f.Type.startsWith("AWS::"))A.push({path:`Parameters.${u}.Type`,message:`Uncommon parameter type: ${f.Type}`,severity:"warning"});if(f.NoEcho&&f.Default)A.push({path:`Parameters.${u}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function $g(u,f,R,A){if(!f.Value)R.push({path:`Outputs.${u}.Value`,message:"Output Value is required",severity:"error"})}function vg(u){let f={};for(let[P,L]of Object.entries(u)){if(f[P]=[],L.DependsOn){if(typeof L.DependsOn==="string")f[P].push(L.DependsOn);else if(Array.isArray(L.DependsOn))f[P].push(...L.DependsOn)}let z=Vc(L);f[P].push(...z)}let R=new Set,A=new Set,T=[];function E(P,L){R.add(P),A.add(P),L.push(P);let z=f[P]||[];for(let fe of z)if(!R.has(fe)){if(E(fe,L))return!0}else if(A.has(fe)){let me=L.indexOf(fe);return T.push(...L.slice(me),fe),!0}return L.pop(),A.delete(P),!1}for(let P of Object.keys(f))if(!R.has(P)){if(E(P,[]))return T}return[]}function Vc(u,f=[]){if(typeof u!=="object"||u===null)return f;if(Array.isArray(u)){for(let R of u)Vc(R,f);return f}if(u.Ref&&typeof u.Ref==="string"&&!u.Ref.startsWith("AWS::"))f.push(u.Ref);if(u["Fn::GetAtt"]){let R=u["Fn::GetAtt"];if(Array.isArray(R)&&R.length>0)f.push(R[0])}for(let R of Object.values(u))Vc(R,f);return f}function Eg(u){let f=[],R=[],A=new TextEncoder().encode(u).length,T=51200,E=460800;if(A>51200)if(A>460800)f.push({path:"template",message:`Template size (${A} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else R.push({path:"template",message:`Template size (${A} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:f.length===0,errors:f,warnings:R}}function Og(u){let f=[],R=[],A=u.Resources?Object.keys(u.Resources).length:0,T=u.Parameters?Object.keys(u.Parameters).length:0,E=u.Outputs?Object.keys(u.Outputs).length:0;if(A>500)f.push({path:"Resources",message:`Template has ${A} resources, exceeding the limit of 500`,severity:"error"});else if(A>200)R.push({path:"Resources",message:`Template has ${A} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(T>200)f.push({path:"Parameters",message:`Template has ${T} parameters, exceeding the limit of 200`,severity:"error"});if(E>200)f.push({path:"Outputs",message:`Template has ${E} outputs, exceeding the limit of 200`,severity:"error"});return{valid:f.length===0,errors:f,warnings:R}}function cR(u){let{domains:f,email:R,staging:A=!1,challengeType:T="http-01",certPath:E="/etc/letsencrypt/live",autoRenew:P=!0}=u,L=f[0],z=f.map((me)=>`-d ${me}`).join(" "),fe=A?"--staging":"";if(T==="http-01")return xg({domains:f,email:R,staging:A,certPath:E,autoRenew:P,domainFlags:z,stagingFlag:fe,primaryDomain:L});else{let me=u.dnsProvider?.provider||(u.hostedZoneId?"route53":void 0);return Lg({domains:f,email:R,staging:A,certPath:E,autoRenew:P,domainFlags:z,stagingFlag:fe,primaryDomain:L,hostedZoneId:u.hostedZoneId,dnsProvider:u.dnsProvider,dnsProviderType:me})}}function xg(u){let{email:f,certPath:R,autoRenew:A,domainFlags:T,stagingFlag:E,primaryDomain:P}=u;return`
223
223
  # ==========================================
224
224
  # Let's Encrypt Certificate Setup (HTTP-01)
225
225
  # ==========================================
@@ -253,11 +253,11 @@ else
253
253
  echo "Failed to obtain certificate!"
254
254
  fi
255
255
 
256
- ${A?_c(P):"# Auto-renewal disabled"}
256
+ ${A?zc(P):"# Auto-renewal disabled"}
257
257
 
258
258
  # Restart the application
259
259
  systemctl start stacks
260
- `}function Mg(u){let{email:f,certPath:R,autoRenew:A,domainFlags:T,stagingFlag:E,primaryDomain:P,hostedZoneId:L,dnsProvider:z,dnsProviderType:fe}=u;if(fe==="route53"||L){if(!L)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
260
+ `}function Lg(u){let{email:f,certPath:R,autoRenew:A,domainFlags:T,stagingFlag:E,primaryDomain:P,hostedZoneId:L,dnsProvider:z,dnsProviderType:fe}=u;if(fe==="route53"||L){if(!L)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
261
261
  # ==========================================
262
262
  # Let's Encrypt Certificate Setup (DNS-01 via Route53)
263
263
  # ==========================================
@@ -288,8 +288,8 @@ else
288
288
  echo "Failed to obtain certificate!"
289
289
  fi
290
290
 
291
- ${A?_c(P):"# Auto-renewal disabled"}
292
- `}if(!z)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let me=z.provider.toUpperCase(),At=Bg(z);return`
291
+ ${A?zc(P):"# Auto-renewal disabled"}
292
+ `}if(!z)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let me=z.provider.toUpperCase(),At=Fg(z);return`
293
293
  # ==========================================
294
294
  # Let's Encrypt Certificate Setup (DNS-01 via ${me})
295
295
  # ==========================================
@@ -312,7 +312,7 @@ DOMAIN="$CERTBOT_DOMAIN"
312
312
  VALIDATION="$CERTBOT_VALIDATION"
313
313
  RECORD_NAME="_acme-challenge.$DOMAIN"
314
314
 
315
- ${Wg(z)}
315
+ ${_g(z)}
316
316
 
317
317
  # Wait for DNS propagation
318
318
  echo "Waiting 60 seconds for DNS propagation..."
@@ -331,7 +331,7 @@ DOMAIN="$CERTBOT_DOMAIN"
331
331
  VALIDATION="$CERTBOT_VALIDATION"
332
332
  RECORD_NAME="_acme-challenge.$DOMAIN"
333
333
 
334
- ${Vg(z)}
334
+ ${Mg(z)}
335
335
  CLEANUPHOOK
336
336
 
337
337
  chmod +x /etc/letsencrypt/hooks/cleanup-hook.sh
@@ -362,8 +362,8 @@ else
362
362
  echo "Failed to obtain certificate!"
363
363
  fi
364
364
 
365
- ${A?_c(P):"# Auto-renewal disabled"}
366
- `}function Bg(u){switch(u.provider){case"porkbun":return`
365
+ ${A?zc(P):"# Auto-renewal disabled"}
366
+ `}function Fg(u){switch(u.provider){case"porkbun":return`
367
367
  # Porkbun API credentials
368
368
  export PORKBUN_API_KEY="${u.apiKey}"
369
369
  export PORKBUN_SECRET_KEY="${u.secretKey}"
@@ -374,7 +374,7 @@ export GODADDY_API_SECRET="${u.apiSecret}"
374
374
  export GODADDY_ENV="${u.environment||"production"}"
375
375
  `;case"route53":return`
376
376
  # Route53 uses IAM role credentials
377
- `;default:return""}}function Wg(u){switch(u.provider){case"porkbun":return`
377
+ `;default:return""}}function _g(u){switch(u.provider){case"porkbun":return`
378
378
  # Extract root domain (last two parts)
379
379
  ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
380
380
  SUBDOMAIN="_acme-challenge"
@@ -418,7 +418,7 @@ curl -s -X PATCH "$API_URL/v1/domains/$ROOT_DOMAIN/records" \\
418
418
  "data": "'"$VALIDATION"'",
419
419
  "ttl": 600
420
420
  }]'
421
- `;default:return'echo "Unsupported DNS provider"'}}function Vg(u){switch(u.provider){case"porkbun":return`
421
+ `;default:return'echo "Unsupported DNS provider"'}}function Mg(u){switch(u.provider){case"porkbun":return`
422
422
  # Extract root domain, and the challenge's subdomain the way the auth hook did
423
423
  ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
424
424
  SUBDOMAIN="_acme-challenge"
@@ -470,7 +470,7 @@ fi
470
470
 
471
471
  curl -s -X DELETE "$API_URL/v1/domains/$ROOT_DOMAIN/records/TXT/$RECORD_NAME" \\
472
472
  -H "Authorization: sso-key $GODADDY_API_KEY:$GODADDY_API_SECRET"
473
- `;default:return'echo "Unsupported DNS provider"'}}function _c(u){return`
473
+ `;default:return'echo "Unsupported DNS provider"'}}function zc(u){return`
474
474
  # ==========================================
475
475
  # Certificate Auto-Renewal Setup
476
476
  # ==========================================
@@ -515,7 +515,7 @@ systemctl enable certbot-renewal.timer
515
515
  systemctl start certbot-renewal.timer
516
516
 
517
517
  echo "Certificate auto-renewal configured"
518
- `}function iR(u){let{httpPort:f=80,httpsPort:R=443,certPath:A="/etc/ssl/stacks",redirectHttp:T=!0}=u;return`
518
+ `}function lR(u){let{httpPort:f=80,httpsPort:R=443,certPath:A="/etc/ssl/stacks",redirectHttp:T=!0}=u;return`
519
519
  // HTTPS Server with Let's Encrypt certificates
520
520
  import { existsSync } from 'node:fs'
521
521
 
@@ -601,5 +601,5 @@ async function handleRequest(request: Request): Promise<Response> {
601
601
  // Implement your request handling here
602
602
  return new Response('Hello from Stacks!')
603
603
  }
604
- `}async function zg(u,f,R){let A=`_acme-challenge.${f}`;if(await Ug(u,f,A,R))return;let T=await u.createRecord(f,{name:A,type:"TXT",content:R,ttl:60});if(!T.success)throw Error(`Failed to create DNS challenge record: ${T.message}`)}async function Hg(u,f,R){let A=await u.deleteRecord(f,{name:`_acme-challenge.${f}`,type:"TXT",content:R});if(!A.success)console.warn(`Failed to delete DNS challenge record: ${A.message}`)}async function Ug(u,f,R,A){try{let T=await u.listRecords(f,"TXT"),E=R.replace(/\.$/,"").toLowerCase();return(T.records??[]).some((P)=>P.name.replace(/\.$/,"").toLowerCase()===E&&P.content.replace(/^"|"$/g,"")===A)}catch{return!1}}function Gu(u){let{hostedZoneId:f,dnsProvider:R,region:A="us-east-1"}=u;if(R)return k(R);if(f)return new ie(A,f);throw Error("Either dnsProvider or hostedZoneId must be provided")}async function oR(u){await zg(Gu(u),u.domain,u.challengeValue)}async function sR(u){await Hg(Gu(u),u.domain,u.challengeValue)}function aR(u){try{let{execSync:f}=nt("node:child_process"),R=f(`openssl x509 -checkend 2592000 -noout -in ${u}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as ju,createSign as Gg,generateKeyPairSync as Ku}from"node:crypto";var Qu={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class jg{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(u){this.directoryUrl=u.staging?Qu.staging:Qu.production,this.email=u.email,this.accountKey=u.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:u}=Ku("ec",{namedCurve:"P-256"});return u.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let u=await fetch(this.directoryUrl);if(!u.ok)throw Error(`Failed to fetch ACME directory: ${u.status}`);return this.directory=await u.json(),this.directory}async getNonce(){if(this.nonce){let A=this.nonce;return this.nonce=null,A}let u=await this.getDirectory(),R=(await fetch(u.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!R)throw Error("Failed to get nonce from ACME server");return R}getJwk(){let u=this.accountKey.split(`
605
- `).filter((E)=>!E.startsWith("-----")).join(""),f=Buffer.from(u,"base64"),R=f.length-65,A=f.subarray(R+1,R+33),T=f.subarray(R+33,R+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(A),y:this.base64UrlEncode(T)}}getJwkThumbprint(){let u=this.getJwk(),f=JSON.stringify({crv:u.crv,kty:u.kty,x:u.x,y:u.y}),R=ju("sha256").update(f).digest();return this.base64UrlEncode(R)}base64UrlEncode(u){return(typeof u==="string"?Buffer.from(u):u).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(u,f){let R=await this.getNonce(),A=this.getJwk(),T={alg:"ES256",nonce:R,url:u};if(this.accountUrl)T.kid=this.accountUrl;else T.jwk=A;let E=this.base64UrlEncode(JSON.stringify(T)),P=f===""?"":this.base64UrlEncode(JSON.stringify(f)),L=`${E}.${P}`,z=Gg("SHA256");z.update(L);let fe=z.sign(this.accountKey),me=fe.subarray(4,4+fe[3]),At=4+fe[3]+2,Lt=fe.subarray(At,At+fe[At-1]),mt=Buffer.alloc(32),Me=Buffer.alloc(32);me.copy(mt,32-me.length),Lt.copy(Me,32-Lt.length);let ze=Buffer.concat([mt,Me]);return JSON.stringify({protected:E,payload:P,signature:this.base64UrlEncode(ze)})}async acmeRequest(u,f){let R=await this.signPayload(u,f),A=await fetch(u,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:R}),T=A.headers.get("replay-nonce");if(T)this.nonce=T;let E,P=A.headers.get("content-type");if(P?.includes("application/json")||P?.includes("application/problem+json"))E=await A.json();else E=await A.text();if(!A.ok)throw Error(`ACME request failed: ${JSON.stringify(E)}`);return{body:E,headers:A.headers}}async registerAccount(){let u=await this.getDirectory(),{body:f,headers:R}=await this.acmeRequest(u.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),A=R.get("location");if(!A)throw Error("No account URL returned");return this.accountUrl=A,A}async createOrder(u){if(!this.accountUrl)await this.registerAccount();let f=await this.getDirectory(),{body:R,headers:A}=await this.acmeRequest(f.newOrder,{identifiers:u.map((E)=>({type:"dns",value:E}))}),T=A.get("location");if(!T)throw Error("No order URL returned");return{orderUrl:T,authorizations:R.authorizations,finalize:R.finalize}}async getAuthorization(u){let{body:f}=await this.acmeRequest(u,""),R=f.identifier.value,A=this.getJwkThumbprint(),T=f.challenges.filter((E)=>E.type==="http-01"||E.type==="dns-01").map((E)=>{let P=`${E.token}.${A}`;if(E.type==="http-01")return{type:"http-01",token:E.token,keyAuthorization:P,identifier:`/.well-known/acme-challenge/${E.token}`};else{let L=this.base64UrlEncode(ju("sha256").update(P).digest());return{type:"dns-01",token:E.token,keyAuthorization:P,identifier:`_acme-challenge.${R}`,dnsValue:L}}});return{domain:R,challenges:T}}async respondToChallenge(u){await this.acmeRequest(u,{})}async waitForAuthorization(u,f=30){for(let R=0;R<f;R++){let{body:A}=await this.acmeRequest(u,"");if(A.status==="valid")return;if(A.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(A)}`);await new Promise((T)=>setTimeout(T,2000))}throw Error("Authorization timed out")}generateCsr(u){let{privateKey:f}=Ku("rsa",{modulusLength:2048}),R=f.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(u,f),privateKey:R}}createSimpleCsr(u,f){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(u,f){let{csr:R,privateKey:A}=this.generateCsr(f),{body:T}=await this.acmeRequest(u,{csr:this.base64UrlEncode(Buffer.from(R,"base64"))}),E=T.certificate;if(!E)throw Error("Certificate not immediately available - polling not implemented");let L=await(await fetch(E)).text(),z=L.split(/(?=-----BEGIN CERTIFICATE-----)/g),fe=z[0],me=z.slice(1).join("");return{certificate:fe,privateKey:A,chain:me,fullchain:L,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var Gr=(u)=>u===void 0?void 0:u?"on":"off";function Mc(u){let f={ssl:u.ssl,always_use_https:Gr(u.alwaysUseHttps),automatic_https_rewrites:Gr(u.automaticHttpsRewrites),min_tls_version:u.minTlsVersion,tls_1_3:Gr(u.tls13),brotli:Gr(u.brotli),http3:Gr(u.http3),"0rtt":Gr(u.zeroRtt),early_hints:Gr(u.earlyHints),browser_cache_ttl:u.browserCacheTtl,always_online:Gr(u.alwaysOnline),websockets:Gr(u.websockets),email_obfuscation:Gr(u.emailObfuscation)};if(u.hsts)f.security_header={strict_transport_security:{enabled:u.hsts.enabled,max_age:u.hsts.maxAge??31536000,include_subdomains:u.hsts.includeSubdomains??!1,preload:u.hsts.preload??!1,nosniff:u.hsts.noSniff??!0}};for(let R of Object.keys(f))if(f[R]===void 0)delete f[R];return{...f,...u.raw??{}}}var so={ssl:"strict",alwaysUseHttps:!0,automaticHttpsRewrites:!0,minTlsVersion:"1.2",tls13:!0,brotli:!0,http3:!0,earlyHints:!0,alwaysOnline:!0,emailObfuscation:!1,browserCacheTtl:0};import{connect as qg}from"node:tls";async function Bc(u){let{address:f,serverName:R,port:A=443,timeoutMs:T=5000}=u;return new Promise((E)=>{let P=!1,L=(fe)=>{if(P)return;P=!0;try{z.destroy()}catch{}E(fe)},z=qg({host:f,port:A,servername:R,rejectUnauthorized:!1,timeout:T});z.once("secureConnect",()=>{if(z.authorized){L({reachable:!0,trusted:!0});return}L({reachable:!0,trusted:!1,reason:z.authorizationError?String(z.authorizationError):"origin certificate is not trusted for this hostname"})}),z.once("timeout",()=>{L({reachable:!1,trusted:!1,reason:`no TLS handshake within ${T}ms`})}),z.once("error",(fe)=>{L({reachable:!1,trusted:!1,reason:fe.message})})})}function Zg(u,f){let R=f.replace(/\.$/,"").toLowerCase();return u.some((A)=>{let T=A.replace(/\.$/,"").toLowerCase();if(T===R)return!0;if(!T.startsWith("*."))return!1;let E=T.slice(2);if(!R.endsWith(`.${E}`))return!1;return!R.slice(0,R.length-E.length-1).includes(".")})}async function Jg(u){let{provider:f,zone:R,hosts:A,ipv4:T,ipv6:E,proxied:P=!0,settings:L=so,cache:z,originGuard:fe,purge:me=!0,ttl:At=300,skipOriginProbe:Lt=!1,skipEdgeCertificateCheck:mt=!1}=u,Me={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(A.length===0)return Me;let ze=[],j=P&&!mt?await f.listEdgeCertificateHosts(R):null;for(let G of A){let ht=P;if(ht&&j&&!Zg(j,G)){ht=!1;let Wt=j.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${j.join(", ")})`;Me.deferredProxy.push({host:G,reason:Wt}),Me.warnings.push(`${G}: publishing DNS-only — ${Wt}. Proxying it would make Cloudflare terminate TLS with no certificate for the name, which fails the handshake outright rather than degrading. Universal SSL covers the apex and ONE level of subdomain, so a deeper name needs its own certificate; otherwise re-run the deploy once the certificate is active.`)}if(ht&&!Lt){let Wt=await Bc({address:T,serverName:G});if(!Wt.trusted){ht=!1;let zt=Wt.reason||"origin is not serving a trusted certificate";Me.deferredProxy.push({host:G,reason:zt}),Me.warnings.push(`${G}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${zt}). 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(ht)ze.push(G);let St=[{type:"A",content:T}];if(E&&Kn(G))St.push({type:"AAAA",content:E});for(let{type:Wt,content:zt}of St){let jt=await f.upsertRecord(R,{name:G,type:Wt,content:zt,ttl:At,proxied:ht});if(jt.success)Me.records.push({host:G,type:Wt,content:zt,proxied:ht});else Me.warnings.push(`${G} ${Wt} → ${zt} failed: ${jt.message||"unknown provider error"}`)}}if(ze.length===0){if(P)Me.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return Me}try{let G=Mc(L),ht=await f.applyZoneSettings(R,G);Me.settingsChanged=ht.changed;for(let St of ht.failed)Me.warnings.push(`zone setting '${St.id}' could not be applied: ${St.error}`)}catch(G){Me.warnings.push(`zone settings could not be read: ${G instanceof Error?G.message:String(G)}`)}let yt=Ic(ze,z);if(yt.length>0){let G=await f.putManagedPhaseRules(R,"http_request_cache_settings",yt);if(G.success)Me.cacheRules=yt.length;else Me.warnings.push(`cache rules could not be written: ${G.message}`)}if(fe){let G=bc(ze,fe.header,fe.value);if(G.length>0){let ht=await f.putManagedPhaseRules(R,"http_request_late_transform",G);if(ht.success)Me.originGuard=!0;else Me.warnings.push(`origin guard header could not be written: ${ht.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(me){if(Me.purged=await f.purgeCache(R,{hosts:ze}),!Me.purged)Me.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Me}var Yg=(u)=>process.env[u];function ed(u,f){let R=u.replace(/\.$/,"").toLowerCase();if(f){let A=f.replace(/\.$/,"").toLowerCase();if(R===A||R.endsWith(`.${A}`))return A}return R.split(".").slice(-2).join(".")}function Xg(u,f={}){let R=f.env??Yg,A=u.infrastructure?.compute?.proxy?.cdn,T=[];if(!A||A.provider!=="cloudflare")return{plan:null,errors:T};if(A.originDomain)T.push(`compute.proxy.cdn.originDomain (${A.originDomain}) is ignored for Cloudflare: the proxy forwards to the address in the record it fronts, `+"so no separate origin hostname is needed — and publishing one gives clients a documented way around the edge.");let E=R("CLOUDFLARE_API_TOKEN");if(!E)return T.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:T};let P=u.sites??{},L=A.frontedHosts?.length?[...new Set(A.frontedHosts.map((Lt)=>Lt.toLowerCase()))]:io(P,{autoWww:u.infrastructure?.compute?.proxy?.autoWww!==!1});if(L.length===0)return T.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:T};let z=u.infrastructure?.dns?.domain,fe=new Set(L.map((Lt)=>ed(Lt,z)));if(fe.size>1)return T.push(`Fronted hosts span more than one zone (${[...fe].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:T};let me=A.cloudflare??{},At=A.secret?{header:A.secretHeader??"X-Origin-Verify",value:A.secret}:void 0;return{plan:{zone:[...fe][0],hosts:L,apiToken:E,zoneId:me.zoneId??R("CLOUDFLARE_ZONE_ID"),accountId:me.accountId??R("CLOUDFLARE_ACCOUNT_ID"),proxied:me.proxied!==!1,settings:me.settings??so,cache:me.cache,originGuard:At,purge:me.purgeOnDeploy!==!1,skipOriginProbe:me.skipOriginProbe===!0},errors:T}}var Qg=26214400;var th=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class td{name="cloudflare-pages";apiToken;accountId;constructor(u){if(!u.apiToken)throw Error("Cloudflare Pages needs an API token");if(!u.accountId)throw Error("Cloudflare Pages needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId}async request(u,f,R){return Ks(u,`/accounts/${this.accountId}${f}`,`Bearer ${this.apiToken}`,R)}async getProject(u){try{return await this.request("GET",`/pages/projects/${u}`)}catch(f){if(f instanceof Error&&/\b8000007\b|not found/i.test(f.message))return null;throw f}}async ensureProject(u,f="main"){let R=await this.getProject(u);if(R)return R;return this.request("POST","/pages/projects",{name:u,production_branch:f})}async uploadToken(u){return(await this.request("GET",`/pages/projects/${u}/upload-token`)).jwt}async missingHashes(u,f){let R=await Ks("POST","/pages/assets/check-missing",`Bearer ${u}`,{hashes:f});return new Set(R)}async upsertHashes(u,f){await Ks("POST","/pages/assets/upsert-hashes",`Bearer ${u}`,{hashes:f})}async uploadBatch(u,f){let R=f.map((A)=>({key:A.hash,value:A.base64,metadata:{contentType:nh(A.extension)},base64:!0}));await Ks("POST","/pages/assets/upload",`Bearer ${u}`,R)}async createDeployment(u,f,R){let A={};for(let E of f)A[E.path]=E.hash;let T=new FormData;if(T.append("manifest",JSON.stringify(A)),R)T.append("branch",R);return this.request("POST",`/pages/projects/${u}/deployments`,T)}async deployDirectory(u){let f=await ep(u.directory);if(f.length===0)throw Error(`No files to deploy in ${u.directory}`);let R=await this.uploadToken(u.project),A=await this.missingHashes(R,f.map((z)=>z.hash)),T=f.filter((z)=>A.has(z.hash)),E=[];for(let z=0;z<T.length;z+=100)E.push(T.slice(z,z+100));let P=0;for(let z=0;z<E.length;z+=4){let fe=E.slice(z,z+4);await Promise.all(fe.map((me)=>this.uploadBatch(R,me))),P+=fe.reduce((me,At)=>me+At.length,0),u.onProgress?.(P,T.length)}return await this.upsertHashes(R,f.map((z)=>z.hash)),{deployment:await this.createDeployment(u.project,f,u.branch),total:f.length,uploaded:T.length,uploadedBytes:T.reduce((z,fe)=>z+fe.size,0)}}async listCustomDomains(u){return(await this.request("GET",`/pages/projects/${u}/domains`)).map((R)=>R.name)}async attachCustomDomain(u,f){if((await this.listCustomDomains(u)).includes(f))return!1;return await this.request("POST",`/pages/projects/${u}/domains`,{name:f}),!0}}function rh(u,f){return{type:"CNAME",name:u,value:f.endsWith(".pages.dev")?f:`${f}.pages.dev`,ttl:1,proxied:!0}}async function rd(u,f){let{blake3:R}=await import("./chunk-4yqd62rd.js").then((m)=>SS(m.default,1));return(await R(u+f)).slice(0,32)}async function ep(u){let{readdir:f}=await import("node:fs/promises"),{join:R,relative:A,sep:T}=await import("node:path"),E=[];async function P(L){let z=await f(L,{withFileTypes:!0});for(let fe of z){let me=R(L,fe.name);if(fe.isDirectory()){await P(me);continue}if(!fe.isFile())continue;let At=`/${A(u,me).split(T).join("/")}`;if(th.has(At))continue;let Lt=await Bun.file(me).bytes();if(Lt.byteLength>26214400)throw Error(`${At} is ${Lt.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let mt=Buffer.from(Lt).toString("base64"),Me=fe.name.lastIndexOf("."),ze=Me>0?fe.name.slice(Me+1):"";E.push({path:At,hash:await rd(mt,ze),base64:mt,extension:ze,size:Lt.byteLength})}}return await P(u),E.sort((L,z)=>L.path.localeCompare(z.path)),E}function nh(u){return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",mjs:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",map:"application/json; charset=utf-8",xml:"application/xml; charset=utf-8",txt:"text/plain; charset=utf-8",svg:"image/svg+xml",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",avif:"image/avif",ico:"image/x-icon",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",pdf:"application/pdf",webmanifest:"application/manifest+json"}[u.toLowerCase()]||"application/octet-stream"}async function Ks(u,f,R,A){let T={Authorization:R},E;if(A instanceof FormData)E=A;else if(A!==void 0)T["Content-Type"]="application/json",E=JSON.stringify(A);let P=await fetch(`https://api.cloudflare.com/client/v4${f}`,{method:u,headers:T,body:E}),L=await P.text(),z;try{z=JSON.parse(L)}catch{throw Error(`Cloudflare Pages API returned ${P.status} with a non-JSON body: ${L.slice(0,200)}`)}if(!z.success){let fe=(z.errors??[]).map((me)=>`${me.code}: ${me.message}`).join(", ");throw Error(`Cloudflare Pages API error (${P.status}): ${fe||L.slice(0,200)}`)}return z.result}import{createHash as ih}from"node:crypto";var rp="https://api.cloudflare.com/client/v4",np=10042,oh=10006,sh=10059;class Fn extends Error{status;errors;constructor(u,f,R=[]){super(u);this.name="R2ApiError",this.status=f,this.errors=R}hasCode(u){return this.errors.some((f)=>f.code===u)}}class Pn extends Fn{accountId;constructor(u,f,R=[]){super(`R2 is not enabled on Cloudflare account ${u}. Enable it once in the Cloudflare dashboard (R2 Object Storage, then follow the prompt to activate it), then re-run the deploy.`,f,R);this.name="R2NotEnabledError",this.accountId=u}}class oi{name="cloudflare-r2";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare R2 needs an API token");if(!u.accountId)throw Error("Cloudflare R2 needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((f,R)=>fetch(f,R))}async requestEnvelope(u,f,R,A={}){let T={Authorization:`Bearer ${this.apiToken}`};if(R!==void 0)T["Content-Type"]="application/json";if(A.jurisdiction&&A.jurisdiction!=="default")T["cf-r2-jurisdiction"]=A.jurisdiction;let E=await this.fetchImpl(`${rp}/accounts/${this.accountId}/r2${f}`,{method:u,headers:T,body:R===void 0?void 0:JSON.stringify(R)}),P=await E.text(),L;try{L=JSON.parse(P)}catch{throw new Fn(`Cloudflare R2 API returned ${E.status} with a non-JSON body: ${P.slice(0,200)}`,E.status)}if(!L.success){let z=L.errors??[];if(z.some((me)=>me.code===np))throw new Pn(this.accountId,E.status,z);let fe=z.map((me)=>`${me.code}: ${me.message}`).join(", ");throw new Fn(`Cloudflare R2 API error (${E.status}) on ${u} ${f}: ${fe||P.slice(0,200)}`,E.status,z)}return L}async request(u,f,R,A){return(await this.requestEnvelope(u,f,R,A)).result}bucketPath(u){return`/buckets/${encodeURIComponent(u)}`}async listBuckets(u={}){let f=[],R;do{let A=new URLSearchParams({per_page:"1000"});if(R)A.set("cursor",R);let T=await this.requestEnvelope("GET",`/buckets?${A}`,void 0,u),E=T.result?.buckets??[];f.push(...E),R=E.length>0?T.result_info?.cursor||void 0:void 0}while(R);return f}async getBucket(u,f={}){try{return await this.request("GET",this.bucketPath(u),void 0,f)}catch(R){if(R instanceof Pn)throw R;if(R instanceof Fn&&(R.hasCode(oh)||R.status===404))return null;throw R}}async ensureBucket(u,f={}){let R={jurisdiction:f.jurisdiction},A=await this.getBucket(u,R);if(A)return{bucket:A,created:!1};let T={name:u};if(f.locationHint)T.locationHint=f.locationHint;let E=await this.request("POST","/buckets",T,R);return{bucket:{...E,name:E?.name||u},created:!0}}async getCors(u,f={}){try{return(await this.request("GET",`${this.bucketPath(u)}/cors`,void 0,f))?.rules??[]}catch(R){if(R instanceof Fn&&!(R instanceof Pn)&&(R.hasCode(sh)||R.status===404))return[];throw R}}async putCors(u,f,R={}){if(f.length===0){await this.request("DELETE",`${this.bucketPath(u)}/cors`,void 0,R);return}await this.request("PUT",`${this.bucketPath(u)}/cors`,{rules:f},R)}async ensureCors(u,f,R={}){let A=await this.getCors(u,R);if(qs(A,f))return!1;return await this.putCors(u,f,R),!0}async getLifecycle(u,f={}){return(await this.request("GET",`${this.bucketPath(u)}/lifecycle`,void 0,f))?.rules??[]}async putLifecycle(u,f,R={}){await this.request("PUT",`${this.bucketPath(u)}/lifecycle`,{rules:f},R)}async ensureLifecycle(u,f,R={}){let A=await this.getLifecycle(u,R);if(Ga(A,f))return!1;return await this.putLifecycle(u,f,R),!0}async listCustomDomains(u,f={}){return(await this.request("GET",`${this.bucketPath(u)}/domains/custom`,void 0,f))?.domains??[]}async attachCustomDomain(u,f,R={}){return this.request("POST",`${this.bucketPath(u)}/domains/custom`,{domain:f.domain,zoneId:f.zoneId,enabled:f.enabled??!0,minTLS:f.minTLS??"1.2"},R)}async updateCustomDomain(u,f,R,A={}){return this.request("PUT",`${this.bucketPath(u)}/domains/custom/${encodeURIComponent(f)}`,R,A)}async ensureCustomDomain(u,f,R={},A){let T=f.minTLS??"1.2",P=(A??await this.listCustomDomains(u,R)).find((fe)=>fe.domain.toLowerCase()===f.domain.toLowerCase());if(!P){let fe=await this.attachCustomDomain(u,{...f,minTLS:T,enabled:!0},R);return{action:"attached",domain:{...fe,domain:fe?.domain||f.domain}}}let L=P.minTLS??"1.0";if(P.enabled&&L===T)return{action:"unchanged",domain:P};let z=await this.updateCustomDomain(u,P.domain,{enabled:!0,minTLS:T},R);return{action:"updated",domain:{...P,...z}}}async getManagedDomain(u,f={}){return this.request("GET",`${this.bucketPath(u)}/domains/managed`,void 0,f)}async setManagedDomain(u,f,R={}){let A=await this.getManagedDomain(u,R);if(A?.enabled===f)return{changed:!1,domain:A};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(u)}/domains/managed`,{enabled:f},R)}}}function ip(u){return`https://${u}.r2.cloudflarestorage.com`}async function ah(u){let{apiToken:f,accountId:R}=u;if(!f)throw Error("r2S3Credentials needs an API token");if(!R)throw Error("r2S3Credentials needs an account id");let A=u.fetch??((P,L)=>fetch(P,L)),T=[],E;for(let P of[`/accounts/${R}/tokens/verify`,"/user/tokens/verify"]){let L=await A(`${rp}${P}`,{method:"GET",headers:{Authorization:`Bearer ${f}`}}),z=await L.json().catch(()=>null);if(L.ok&&z?.success&&z.result?.id){E=z.result.id;break}let fe=z?.errors?.map((me)=>`${me.code}: ${me.message}`).join(", ");T.push(`${P} -> ${L.status}${fe?` (${fe})`:""}`)}if(!E)throw Error(`Could not verify the Cloudflare API token to derive R2 credentials: ${T.join("; ")}`);return{accessKeyId:E,secretAccessKey:ih("sha256").update(f).digest("hex"),endpoint:ip(R),region:"auto"}}function ms(u){if(Array.isArray(u))return`[${u.map(ms).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,R])=>R!==void 0).sort(([R],[A])=>R.localeCompare(A)).map(([R,A])=>`${JSON.stringify(R)}:${ms(A)}`).join(",")}}`;return JSON.stringify(u)}function tp(u,f){let R=(A)=>A&&A.length>0?[...A].map(String).sort():void 0;return{id:f?u.id:void 0,allowed:{origins:R(u.allowed?.origins),methods:R(u.allowed?.methods?.map((A)=>A.toUpperCase())),headers:R(u.allowed?.headers?.map((A)=>A.toLowerCase()))},exposeHeaders:R(u.exposeHeaders?.map((A)=>A.toLowerCase())),maxAgeSeconds:u.maxAgeSeconds}}function qs(u,f){if(u.length!==f.length)return!1;return f.every((R,A)=>{let T=R.id!==void 0;return ms(tp(u[A],T))===ms(tp(R,T))})}function Ga(u,f){if(u.length!==f.length)return!1;let R=(A)=>ms([...A].map((T)=>({...T,storageClassTransitions:T.storageClassTransitions?.length?T.storageClassTransitions:void 0})).sort((T,E)=>T.id.localeCompare(E.id)));return R(u)===R(f)}var uh="r2 cache",ph=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function mh(u,f={}){let R=f.log??(()=>{}),A={buckets:[],warnings:[]},T=u.infrastructure?.r2??u.r2,E=Object.entries(T?.buckets??{});if(E.length===0)return R("R2: no buckets declared, skipping."),A;if(!f.apiToken||!f.accountId){let me=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),At=`R2: ${E.length} bucket(s) declared but ${me} is not set, skipping.`;return R(At),A.warnings.push(At),A}let P=f.dryRun===!0,L=new oi({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),z=new H(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),fe=new Map;for(let[me,At]of E){let Lt=At?.name;if(!Lt||!ph.test(Lt)){A.warnings.push(`R2: bucket '${me}' has an invalid name '${Lt??""}' (3-63 chars: lowercase letters, digits, hyphens), skipping.`);continue}R(`R2: ${P?"checking":"reconciling"} bucket ${Lt}...`);let mt={name:Lt,changes:[],domains:[]};if(A.buckets.push(mt),await gh(At,{r2:L,cloudflare:z,dryRun:P,summary:mt,warnings:A.warnings,claimed:fe,log:R}),mt.changes.length===0)R(`R2: ${Lt} is in sync.`);else for(let Me of mt.changes)R(`R2: ${Lt}: ${Me}`)}return A}async function gh(u,f){let{r2:R,dryRun:A,summary:T,warnings:E}=f,P=u.name,L={jurisdiction:u.jurisdiction},z=(mt,Me)=>{let ze=A?Me&&`would ${Me}`:mt;if(ze)T.changes.push(ze)},fe;if(A)fe=await R.getBucket(P,L)!==null;else{let{created:mt}=await R.ensureBucket(P,{locationHint:u.locationHint,jurisdiction:u.jurisdiction});if(fe=!0,mt)z("created","")}if(!fe)z("","create bucket");let me=hh(u.customDomains);await hs(f,`cors on ${P}`,async()=>{if(!u.cors)return;if(!fe){z("cors updated","set cors");return}let mt=await R.getCors(P,L);if(qs(mt,u.cors))return;if(!A)await R.putCors(P,u.cors,L);z(u.cors.length===0?"cors removed":"cors updated",u.cors.length===0?"remove cors":"update cors")}),await hs(f,`lifecycle on ${P}`,async()=>{if(!u.lifecycle)return;let mt=u.lifecycle.map(cp);if(fe){let Me=await R.getLifecycle(P,L);if(Ga(Me,mt))return}if(!A)await R.putLifecycle(P,mt,L);z("lifecycle updated","update lifecycle")}),await hs(f,`r2.dev URL on ${P}`,async()=>{let mt=u.publicDevUrl===!0;if(!fe){if(mt)z("r2.dev URL enabled","enable r2.dev URL");return}if((await R.getManagedDomain(P,L))?.enabled===mt)return;if(!A)await R.setManagedDomain(P,mt,L);z(mt?"r2.dev URL enabled":"r2.dev URL disabled",mt?"enable r2.dev URL":"disable r2.dev URL")});let At=[];if(me.length>0&&fe)try{At=await R.listCustomDomains(P,L)}catch(mt){if(mt instanceof Pn)throw mt;E.push(`R2: could not list custom domains on ${P}: ${Gc(mt)}`)}let Lt=new Map;for(let{domain:mt,minTLS:Me}of me){let ze=f.claimed.get(mt);if(ze&&ze!==P){E.push(`R2: ${mt} is declared on both ${ze} and ${P}; leaving it on ${ze}.`);continue}f.claimed.set(mt,P);let j=At.find((G)=>G.domain.toLowerCase()===mt),yt=Me??"1.2";if(j&&j.enabled&&(j.minTLS??"1.0")===yt){if(T.domains.push({domain:mt,status:Hc(j)}),j.zoneId)Lt.set(mt,j.zoneId);continue}await hs(f,`custom domain ${mt} on ${P}`,async()=>{if(j){if(!A)await R.updateCustomDomain(P,j.domain,{enabled:!0,minTLS:yt},L);if(z(`custom domain ${mt} updated`,`update custom domain ${mt}`),T.domains.push({domain:mt,status:Hc({...j,enabled:!0})}),j.zoneId)Lt.set(mt,j.zoneId);return}let G=await f.cloudflare.zoneIdFor(mt);if(Lt.set(mt,G),!A)await R.ensureCustomDomain(P,{domain:mt,zoneId:G,minTLS:yt},L,At);z(`custom domain ${mt} attached`,`attach custom domain ${mt}`),T.domains.push({domain:mt,status:A?"not attached":"pending"})},()=>T.domains.push({domain:mt,status:"error"}))}if(u.cache&&me.length>0)await fh(u,me.map((mt)=>mt.domain).filter((mt)=>f.claimed.get(mt)===P),Lt,f,z)}async function fh(u,f,R,A,T){let E=op(u.cache);if(!E||f.length===0)return;let P=new Map;for(let L of f){let z=R.get(L);if(!z)try{z=await A.cloudflare.zoneIdFor(L)}catch(fe){A.warnings.push(`R2: could not resolve the zone for ${L}, cache rule skipped: ${Gc(fe)}`);continue}P.set(z,[...P.get(z)??[],L])}for(let L of P.values()){let z={action:"set_cache_settings",description:`${Gt} ${uh}`,expression:`(${Ht(L)})`,enabled:!0,action_parameters:E};await hs(A,`cache rule for ${L.join(", ")}`,async()=>{let fe=await A.cloudflare.getPhaseRules(L[0],"http_request_cache_settings");if(ap(fe,z))return;if(!A.dryRun){let me=await A.cloudflare.putManagedPhaseRules(L[0],"http_request_cache_settings",[z]);if(!me.success)throw Error(me.message||"cache rule write failed")}T(`cache rule updated for ${L.join(", ")}`,`update cache rule for ${L.join(", ")}`)})}}function op(u){if(u.edgeTtl===void 0&&u.browserTtl===void 0)return null;let f={cache:!0};if(u.edgeTtl!==void 0)f.edge_ttl={mode:"override_origin",default:u.edgeTtl};if(u.browserTtl!==void 0)f.browser_ttl={mode:"override_origin",default:u.browserTtl};return f}function ap(u,f){let R=Vt(f.expression),A=Vn(f.expression),T=(L)=>(L.description||"").startsWith(Gt),E=(L)=>L.action===f.action&&L.description===f.description&&(L.enabled??!0)===(f.enabled??!0)&&Vn(L.expression)===A&&Qa(L.action_parameters)===Qa(f.action_parameters),P=!1;for(let L of u){if(!T(L))continue;let z=Vt(L.expression);if(!R.some((me)=>z.includes(me)))continue;if(E(L)&&R.every((me)=>z.includes(me))&&!P){P=!0;continue}return!1}return P}function cp(u){let f={id:u.id,enabled:u.enabled??!0,conditions:{prefix:u.prefix??""}};if(u.expireAfterDays!==void 0)f.deleteObjectsTransition={condition:{type:"Age",maxAge:Vc(u.expireAfterDays)}};else if(u.expireOn!==void 0)f.deleteObjectsTransition={condition:{type:"Date",date:u.expireOn}};if(u.abortMultipartUploadsAfterDays!==void 0)f.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:Vc(u.abortMultipartUploadsAfterDays)}};if(u.infrequentAccessAfterDays!==void 0)f.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:Vc(u.infrequentAccessAfterDays)}}];return f}function Vc(u){return Math.round(u*86400)}function hh(u){let f=new Set,R=[];for(let A of u??[]){let T=typeof A==="string"?{domain:A}:A,E=T.domain?.trim().replace(/\.$/,"").toLowerCase();if(!E||f.has(E))continue;f.add(E),R.push({domain:E,minTLS:T.minTLS})}return R}function Hc(u){if(!u.enabled)return"disabled";let f=u.status?.ownership,R=u.status?.ssl;if(f==="active"&&R==="active")return"active";for(let A of[f,R])if(A==="error"||A==="blocked"||A==="deactivated")return A;return"pending"}async function hs(u,f,R,A){try{await R()}catch(T){if(T instanceof Pn)throw T;u.warnings.push(`R2: ${f} failed: ${Gc(T)}`),A?.()}}function Gc(u){return u instanceof Error?u.message:String(u)}function Qa(u){if(Array.isArray(u))return`[${u.map(Qa).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,R])=>R!==void 0).sort(([R],[A])=>R.localeCompare(A)).map(([R,A])=>`${JSON.stringify(R)}:${Qa(A)}`).join(",")}}`;return JSON.stringify(u)}import{basename as Th,extname as Ph}from"node:path";import{createHash as yh}from"node:crypto";var Ch="https://api.cloudflare.com/client/v4",On="TS_CLOUD_CONTENT_HASH",Ts="2025-09-01",qc="application/javascript+module",Sh=10007,Rh=[1e4,9109];class si extends Error{status;errors;constructor(u,f,R=[]){super(u);this.name="WorkersApiError",this.status=f,this.errors=R}hasCode(u){return this.errors.some((f)=>f.code===u)}}class mc extends si{permission;constructor(u,f,R,A=[]){super(`The Cloudflare API token is missing the "${u}" permission (${f}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,R,A);this.name="WorkersPermissionError",this.permission=u}}class hc{name="cloudflare-workers";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare Workers needs an API token");if(!u.accountId)throw Error("Cloudflare Workers needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((f,R)=>fetch(f,R))}async request(u,f,R){let A={Authorization:`Bearer ${this.apiToken}`},T;if(R instanceof FormData)T=R;else if(R!==void 0)A["Content-Type"]="application/json",T=JSON.stringify(R);let E=await this.fetchImpl(`${Ch}/accounts/${this.accountId}/workers${f}`,{method:u,headers:A,body:T}),P=await E.text(),L;try{L=JSON.parse(P)}catch{throw new si(`Cloudflare Workers API returned ${E.status} with a non-JSON body: ${P.slice(0,200)}`,E.status)}if(!L.success){let z=L.errors??[],fe=z.map((me)=>`${me.code}: ${me.message}`).join(", ");if(bh(E.status,z))throw new mc(Ah(f),`${u} ${f} -> ${E.status}${fe?`, ${fe}`:""}`,E.status,z);throw new si(`Cloudflare Workers API error (${E.status}) on ${u} ${f}: ${fe||P.slice(0,200)}`,E.status,z)}return L.result}scriptPath(u){return`/scripts/${encodeURIComponent(u)}`}async getSettings(u){try{return await this.request("GET",`${this.scriptPath(u)}/settings`)}catch(f){if(f instanceof mc)throw f;if(f instanceof si&&(f.hasCode(Sh)||f.status===404))return null;throw f}}async getScript(u){return this.getSettings(u)}async uploadModuleScript(u,f){return this.request("PUT",this.scriptPath(u),dp(f))}async ensureModuleScript(u,f){let R=Ps(f),A=await this.getSettings(u);if(A&&Pc(A,f,R))return{action:"unchanged",hash:R};return await this.uploadModuleScript(u,eg(f,R)),{action:A?"updated":"created",hash:R}}async listCustomDomains(u={}){let f=new URLSearchParams;if(u.service)f.set("service",u.service);if(u.hostname)f.set("hostname",u.hostname);if(u.zoneId)f.set("zone_id",u.zoneId);let R=f.toString(),A=R?`?${R}`:"";return await this.request("GET",`/domains${A}`)??[]}async attachCustomDomain(u,f){let R={hostname:u,service:f.service,environment:f.environment??"production"};if(f.zoneId)R.zone_id=f.zoneId;return this.request("PUT","/domains",R)}async detachCustomDomain(u){await this.request("DELETE",`/domains/${encodeURIComponent(u)}`)}async ensureCustomDomain(u,f,R){let T=(R??await this.listCustomDomains({hostname:u})).find((P)=>P.hostname.toLowerCase()===u.toLowerCase());if(T&&T.service===f.service)return{action:"unchanged",domain:T};if(T)throw Error(`${u} is attached to the Worker '${T.service}'. Detach it there first (Workers & Pages, ${T.service}, Settings, Domains & Routes); ts-cloud does not move it.`);let E=await this.attachCustomDomain(u,f);return{action:"attached",domain:{...E,hostname:E?.hostname||u}}}}function bh(u,f){if(f.some((R)=>Rh.includes(R.code)))return!0;return(u===401||u===403)&&f.length===0}function Ah(u){if(u.startsWith("/domains"))return"Workers Routes: Edit (zone, for Workers custom domains) and Workers Scripts: Edit (account)";return"Workers Scripts: Edit (account)"}function dp(u){if(!u.modules.some((A)=>A.name===u.mainModule))throw Error(`Worker main module '${u.mainModule}' is not one of the uploaded modules`);let f={main_module:u.mainModule,bindings:u.bindings??[],compatibility_date:u.compatibilityDate??Ts,compatibility_flags:u.compatibilityFlags??[],keep_bindings:["secret_text"]},R=new FormData;R.append("metadata",JSON.stringify(f));for(let A of u.modules)R.append(A.name,new Blob([A.content],{type:A.type}),A.name);return R}function Ps(u){let f={mainModule:u.mainModule,modules:[...u.modules].sort((R,A)=>R.name.localeCompare(A.name)).map((R)=>({name:R.name,type:R.type,sha256:lp(R.content)})),bindings:[...u.bindings??[]].filter((R)=>R.name!==On).sort((R,A)=>R.name.localeCompare(A.name)),compatibilityDate:u.compatibilityDate??Ts,compatibilityFlags:[...u.compatibilityFlags??[]].sort()};return lp(jc(f))}function eg(u,f=Ps(u)){return{...u,bindings:[...(u.bindings??[]).filter((R)=>R.name!==On),{type:"plain_text",name:On,text:f}]}}function Pc(u,f,R){let A=u.bindings??[],T=A.find((E)=>E.name===On&&E.type==="plain_text");if(!T||T.text!==R)return!1;return(f.bindings??[]).every((E)=>{let P=A.find((z)=>z.name===E.name);if(!P||P.type!==E.type)return!1;let L=E.type==="r2_bucket"?"bucket_name":E.type==="plain_text"?"text":void 0;return!L||P[L]===E[L]})}function lp(u){return yh("sha256").update(u).digest("hex")}function jc(u){if(Array.isArray(u))return`[${u.map(jc).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,R])=>R!==void 0).sort(([R],[A])=>R.localeCompare(A)).map(([R,A])=>`${JSON.stringify(R)}:${jc(A)}`).join(",")}}`;return JSON.stringify(u)}async function Zc(u){if(!await Bun.file(u).exists())throw Error(`Worker entry not found: ${u}`);let f;try{f=await Bun.build({entrypoints:[u],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(T){throw Error(`Bundling Worker ${u} failed: ${$h(T)}`)}if(!f.success)throw Error(`Bundling Worker ${u} failed: ${f.logs.map((T)=>String(T.message??T)).join("; ")}`);if(f.outputs.length!==1)throw Error(`Bundling Worker ${u} produced ${f.outputs.length} files (${f.outputs.map((T)=>T.path).join(", ")}); a Worker is uploaded as a single module, so remove the dynamic imports or asset imports that split it.`);let R=f.outputs[0];if(R.kind!=="entry-point")throw Error(`Bundling Worker ${u} produced a ${R.kind} instead of an entry module`);let A=await R.text();return{name:`${Th(u,Ph(u))}.js`,content:A,type:qc,size:new TextEncoder().encode(A).byteLength}}function $h(u){if(u instanceof AggregateError&&u.errors.length>0)return u.errors.map((f)=>f instanceof Error?f.message:String(f?.message??f)).join("; ");return u instanceof Error?u.message:String(u)}import{isAbsolute as wh,resolve as Ih}from"node:path";var Dh="https://api.cloudflare.com/client/v4",kh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function vh(u,f={}){let R=f.log??(()=>{}),A={workers:[],warnings:[]},T=Object.entries(u.infrastructure?.workers??u.workers??{});if(T.length===0)return R("Workers: none declared, skipping."),A;if(!f.apiToken||!f.accountId){let L=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),z=`Workers: ${T.length} Worker(s) declared but ${L} is not set, skipping.`;return R(z),A.warnings.push(z),A}let E=u.infrastructure?.r2??u.r2,P={workers:new hc({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),r2:new oi({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),cloudflare:new H(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),apiToken:f.apiToken,fetch:f.fetch??((L,z)=>fetch(L,z)),projectRoot:f.projectRoot??process.cwd(),dryRun:f.dryRun===!0,warnings:A.warnings,log:R,r2ConfigDomains:_h(E),r2Buckets:E,claimed:new Map};for(let[L,z]of T){let fe=z?.name;if(!fe||!kh.test(fe)){A.warnings.push(`Workers: '${L}' has an invalid name '${fe??""}' (1-63 chars: lowercase letters, digits, '-' and '_'), skipping.`);continue}if(!z.entry){A.warnings.push(`Workers: ${fe} has no entry, skipping.`);continue}R(`Workers: ${P.dryRun?"checking":"reconciling"} ${fe}...`);let me={name:fe,changes:[],domains:[]};A.workers.push(me),await Oh(z,me,P);for(let At of me.changes)R(`Workers: ${fe}: ${At}`)}return A}async function Oh(u,f,R){let A=u.name,T=wh(u.entry)?u.entry:Ih(R.projectRoot,u.entry),E;try{E=await Zc(T)}catch(L){throw Error(`Worker ${A}: ${mi(L)}`)}f.changes.push(`bundled ${Bh(E.size)}`);let P={mainModule:E.name,modules:[{name:E.name,content:E.content,type:E.type}],bindings:tg(u,R),compatibilityDate:u.compatibilityDate??Ts,compatibilityFlags:u.compatibilityFlags??[]};if(R.dryRun){let L=await R.workers.getSettings(A);f.changes.push(L&&Pc(L,P,Ps(P))?"unchanged":"would upload")}else{let{action:L}=await R.workers.ensureModuleScript(A,P);f.changes.push(L==="unchanged"?"unchanged":"uploaded")}for(let L of Mh(u.customDomains))await Nh(A,L,f,R)}async function Nh(u,f,R,A){let T=(mt)=>{R.domains.push({domain:f,status:mt})},E=(mt)=>{A.warnings.push(`Workers: ${mt}`),T("conflict")},P=A.claimed.get(f);if(P&&P!==u){E(`${f} is declared on both ${P} and ${u}; leaving it on ${P}.`);return}A.claimed.set(f,u);let L=A.r2ConfigDomains.get(f);if(L){E(`${f} is also declared as a custom domain of the R2 bucket '${L}' (r2.buckets). A hostname serves either a bucket or a Worker. Remove it from the bucket's customDomains and detach it in the dashboard (R2, ${L}, Settings, Custom Domains) first; to serve the bucket through the Worker, bind it with bindings.r2Buckets instead.`);return}let z=await xh(A);if(z===null){T("error");return}let fe=z.find((mt)=>mt.hostname.toLowerCase()===f);if(fe?.service===u){T("active");return}if(fe){E(`${f} is attached to the Worker '${fe.service}'. Detach it there first (Workers & Pages, ${fe.service}, Settings, Domains & Routes); it is not moved automatically.`);return}let me=(await Lh(A))?.get(f);if(me){E(`${f} is attached to the R2 bucket '${me}' as a custom domain. Detach it first (R2, ${me}, Settings, Custom Domains, then re-run the deploy); it is not detached automatically. To serve the bucket through the Worker, bind it with bindings.r2Buckets.`);return}let At;try{At=await A.cloudflare.zoneIdFor(f)}catch(mt){A.warnings.push(`Workers: could not resolve the zone for ${f}, not attached: ${mi(mt)}`),T("error");return}let Lt=await Fh(A,At,f);if(Lt.length>0){let mt=Lt.map((Me)=>`${Me.type} ${Me.content}`).join(", ");E(`${f} already has a DNS record (${mt}). A Worker custom domain creates its own record, so Cloudflare will not attach over it. Delete the record first (DNS, Records), then re-run the deploy; it is not deleted automatically.`);return}if(A.dryRun){R.changes.push(`would attach custom domain ${f}`),T("not attached");return}try{await A.workers.ensureCustomDomain(f,{service:u,zoneId:At},z),R.changes.push(`custom domain ${f} attached`),z.push({id:"",hostname:f,service:u,zone_id:At}),T("pending")}catch(mt){A.warnings.push(`Workers: custom domain ${f} on ${u} failed: ${mi(mt)}`),T("error")}}async function xh(u){if(u.attached!==void 0)return u.attached;try{u.attached=await u.workers.listCustomDomains()}catch(f){u.warnings.push(`Workers: could not list Worker custom domains, none attached: ${mi(f)}`),u.attached=null}return u.attached}async function Lh(u){if(u.r2AccountDomains!==void 0)return u.r2AccountDomains;let f=new Map;try{let R=(await u.r2.listBuckets()).map((A)=>({name:A.name}));for(let A of Object.values(u.r2Buckets?.buckets??{}))if(A.jurisdiction&&A.jurisdiction!=="default")R.push({name:A.name,jurisdiction:A.jurisdiction});for(let A of R){let T=await u.r2.listCustomDomains(A.name,{jurisdiction:A.jurisdiction}).catch(()=>[]);for(let E of T)f.set(E.domain.toLowerCase(),A.name)}u.r2AccountDomains=f}catch(R){u.log(`Workers: could not check R2 custom domains (${mi(R)}); relying on the DNS check.`),u.r2AccountDomains=null}return u.r2AccountDomains}async function Fh(u,f,R){try{let A=await u.fetch(`${Dh}/zones/${f}/dns_records?name=${encodeURIComponent(R)}&per_page=100`,{method:"GET",headers:{Authorization:`Bearer ${u.apiToken}`}}),T=await A.json();if(!T?.success)throw Error(`HTTP ${A.status}`);return(T.result??[]).filter((E)=>E.name?.toLowerCase()===R).map((E)=>({type:E.type??"?",content:E.content??""}))}catch(A){return u.log(`Workers: could not read DNS records for ${R} (${mi(A)}); attaching anyway.`),[]}}function tg(u,f){let R=[],A=new Set,T=(P)=>{if(P===On)return f.warnings.push(`Workers: ${u.name}: binding name ${On} is reserved for ts-cloud, ignored.`),!1;if(A.has(P))return f.warnings.push(`Workers: ${u.name}: binding ${P} is declared twice; the first one wins.`),!1;return A.add(P),!0},E=new Map;for(let P of Object.values(f.r2Buckets?.buckets??{}))if(P.jurisdiction&&P.jurisdiction!=="default")E.set(P.name,P.jurisdiction);for(let[P,L]of Object.entries(u.bindings?.r2Buckets??{})){if(!T(P))continue;let z=E.get(L);R.push(z?{type:"r2_bucket",name:P,bucket_name:L,jurisdiction:z}:{type:"r2_bucket",name:P,bucket_name:L})}for(let[P,L]of Object.entries(u.bindings?.vars??{}))if(T(P))R.push({type:"plain_text",name:P,text:String(L)});return R}function _h(u){let f=new Map;for(let R of Object.values(u?.buckets??{}))for(let A of R?.customDomains??[]){let T=lg(typeof A==="string"?A:A.domain);if(T)f.set(T,R.name)}return f}function Mh(u){return[...new Set((u??[]).map(lg).filter(Boolean))]}function lg(u){return(u??"").trim().replace(/\.$/,"").toLowerCase()}function Bh(u){if(u<1024)return`${u} B`;if(u<1048576)return`${(u/1024).toFixed(1)} KB`;return`${(u/1024/1024).toFixed(1)} MB`}function mi(u){return u instanceof Error?u.message:String(u)}export{yl as ABTestManager,ye as ACMClient,Dr as ACMDnsValidator,Qu as ACME_DIRECTORIES,Oe as AI,eu as API_IDEMPOTENCY_TTL_MS,Yl as API_TOKEN_DEFAULT_TTL_MS,Zl as API_TOKEN_MAX_TTL_MS,os as API_VERSION,Ie as AUTHORIZATION_CAPABILITIES,Kl as AUTH_ACTION_TOKEN_TTL_MS,Wl as AUTH_MFA_CHALLENGE_TTL_MS,Jl as AUTH_OIDC_TRANSACTION_TTL_MS,it as AUTH_SESSION_ABSOLUTE_TTL_MS,zl as AUTH_SESSION_IDLE_TTL_MS,ly as AWSAPIError,n as AWSClient,h as AWSCloudFormationClient,S as AWSCloudFrontClient,ml as AWSConfigManager,$I as AWS_PSEUDO_PARAMETERS,_e as AWS_REGIONS,jg as AcmeClient,en as AlertEvaluator,_i as AlertStore,Co as AnomalyConfigStore,nl as ApiGateway,i as ApiServiceError,fc as ApplicationAutoScalingClient,cn as Arn,_ as AssetHasher,Y as Auth,ts as AuthenticationStore,Ui as AutomationApiService,rs as AutomationIdentityStore,Ea as AwsAuroraDataAdapter,Da as AwsAuroraTransport,ja as AwsDatabaseBackupSource,Br as AwsDriver,va as AwsElastiCacheDataAdapter,Pa as AwsElastiCacheTransport,Mf as AwsIamCapabilityScanner,Xa as AwsInfrastructureBackupSource,Ca as AwsRdsDataAdapter,Ra as AwsRdsTransport,Xf as AwsRegionalDriver,Za as AwsSecretsManagerConfigurationBackend,em as AwsSpendTransport,ec as AwsSsmConfigurationBackend,As as BackupCoordinator,gl as BackupManager,Va as BackupStore,pf as BatchProcessingManager,Mn as BedrockClient,$n as BedrockRuntimeClient,au as BitbucketSourceAdapter,Al as BlueGreenManager,rf as BounceComplaintHandler,zm as BuildOptimizationManager,Pu as BunDockerRuntime,sg as BunDockerVolumeRuntime,ig as BunFilesystemArchiveRuntime,Ce as CDN,Qo as CHAIN_HEADER,Gt as CLOUDFLARE_MANAGED_RULE_PREFIX,Yd as CLOUDFRONT_FAILOVER_STATUS_CODES,EC as COMMON_CROSS_ACCOUNT_ROLES,On as CONTENT_HASH_BINDING,Ke as CONTROL_PLANE_SCHEMA_VERSION,_o as Cache,Ki as CanaryManager,Vm as CertificateManager,bA as CloudBlockVolumeDriver,Js as CloudDriverFactory,tt as CloudError,Am as CloudFormationBuilder,h as CloudFormationClient,S as CloudFrontClient,fl as CloudTrailManager,we as CloudWatchLogsClient,td as CloudflarePagesProvider,H as CloudflareProvider,ky as CommandHistory,ee as Communication,Wr as ComposeApplicationService,tr as ComposeApplicationStore,Mt as ComprehendClient,a as Compute,tm as ComputeSpendTransport,Mo as ConfigurationError,rc as ConfigurationService,Ya as ConfigurationStore,_n as ConnectClient,wa as ContainerDataAdapter,El as ContainerRegistryManager,Ja as ControlPlaneBackupSource,Ua as ControlPlaneCleanupDriver,Di as ControlPlaneStore,So as CounterTracker,Pt as CredentialError,Bm as CrossRegionReferenceManager,JA as DASHBOARD_ENTRY,XA as DASHBOARD_PORT_BASE,YA as DASHBOARD_PORT_SPAN,WA as DASHBOARD_STATE_DIR,Jo as DEFAULT_ATTACK_MODE_HOURS,Ts as DEFAULT_COMPATIBILITY_DATE,Qd as DEFAULT_DDOS_THRESHOLDS,sm as DEFAULT_FAILOVER_STATUS_CODES,Cd as DEFAULT_METER_MAPPINGS,Id as DEFAULT_PRICE_BOOK,un as DEFAULT_RECURSION_LIMITS,to as DEFAULT_RPX_CERTS_DIR,te as DEFAULT_SERVICE_LIMITS,qd as DEFAULT_STATE_DIR,yg as DEFAULT_STATIC_ASSET_EXTENSIONS,qA as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,OA as DEFAULT_TELEMETRY_POLICY,Mp as DEFAULT_THRESHOLDS,hA as DEPLOYMENT_QUEUE_KINDS,Uo as DEPTH_HEADER,Yr as DETECTABLE_SIGNALS,vu as DIAGNOSTIC_PRESETS,gf as DLQMonitoringManager,W as DNS,ef as DNSSECManager,ls as DataServiceLifecycle,ba as DataServiceStore,or as Database,Hm as DatabaseUserManager,q as DebugLogger,VA as DependencyGraph,Z as Deployment,dy as DeploymentError,pl as DisasterRecoveryManager,zn as DnsProviderFactory,fr as DockerDataTransport,fa as DockerDiscoveryAdapter,Kr as DockerNamedVolumeDriver,Wa as DockerVolumeBackupSource,c as DurableOperationQueue,go as DurableQueueWorker,Ue as DynamoDBClient,Ur as EC2Client,He as ECRClient,dt as ECSClient,vr as EFSClient,uc as ELBv2Client,EA as ENFORCEMENT_ACTIONS,xi as ENFORCEMENT_DESCRIPTIONS,O as ENFORCEMENT_SEVERITY,gp as ENVIRONMENT_LABEL,Cu as EcsRuntimeAdapter,Wo as EdgeRateLimiter,ut as ElastiCacheClient,m as Email,af as EmailAdvanced,nf as EmailAnalyticsManager,Gn as EmailClient,cf as EmailHandlers,of as EmailTemplateManager,Na as EncryptedDataSecretStore,uy as ErrorCodes,Cr as EventBridgeClient,Kf as EventBridgeJobAdapter,tc as ExternalConfigurationBackend,Oo as FAILOVER_REPLICA_POLICY_SID,uf as FIFOQueueManager,Uh as FLY_MACHINES_API,jp as FOCUS_VERSION,ol as FileCache,Ze as FileSystem,za as FilesystemBackupSource,Ba as FleetService,ka as FleetStore,Ws as FlyApiError,mg as FlyClient,e as Fn,cu as GiteaSourceAdapter,su as GithubSourceAdapter,ou as GitlabSourceAdapter,xm as GlobalResourceManager,Ge as GoDaddyProvider,hl as GuardDutyManager,It as HOST_SITES_DIR,fy as HashCache,Tf as HealthCheckManager,Je as HealthCheckRunner,Lr as HetznerClient,Pe as HetznerDriver,Re as IAMClient,Tc as IPV6_EXCLUDED_HOST_LABELS,jm as ImageScanningManager,Dg as InfrastructureGenerator,dd as InvalidOperationTransitionError,Rt as JobLoader,Wf as JobProviderReconciler,Sa as JobService,Ia as JobStore,br as KendraClient,Ef as LARAVEL_SERVERLESS_BUILD_STEPS,v as LambdaClient,Jm as LambdaConcurrencyManager,Zm as LambdaDLQManager,Xm as LambdaDestinationsManager,Km as LambdaLayersManager,Eu as LambdaRuntimeAdapter,Ym as LambdaVPCManager,Wm as LambdaVersionsManager,Nn as LocalEncryptedConfigurationBackend,Ka as LogicalDatabaseBackupSource,Il as LogsManager,Yy as MANAGED_NODE_VERSIONS,zc as MANAGEMENT_DASHBOARD_SITE,ym as MANAGEMENT_DASHBOARD_SITE_PREFIX,Zi as MAX_CONTROL_HOURS,ld as MAX_CONTROL_PLANE_ERROR_BYTES,xp as MAX_CONTROL_PLANE_JSON_BYTES,ho as METERS,CA as METER_KEYS,vA as MICRO_CENTS,Fp as MIN_PROJECTION_CONFIDENCE,Eg as MTA_STS_PORT,Fa as MaintenanceService,Ma as MaintenanceStore,le as Messaging,Fm as MetricsManager,Um as MigrationManager,Rm as MockCloudFormation,Pm as MockDynamoDB,Dm as MockS3,Lo as Monitoring,Lm as MultiAccountManager,km as MultiRegionManager,Ty as MultiStepProgress,y as Network,wf as NetworkSecurityManager,Li as NotificationRouter,cm as ORIGIN_CONNECTION_ATTEMPTS,dm as ORIGIN_CONNECTION_TIMEOUT,om as ORIGIN_GROUP_ALLOWED_METHODS,OI as ORIGIN_GROUP_ID_SUFFIX,am as ORIGIN_GROUP_SELECTION_CRITERIA,gc as OpenSearchClient,bt as OptimisticConcurrencyError,$m as OrganizationManager,Qg as PAGES_MAX_FILE_BYTES,cS as PHP_DEFAULT_EXCLUDES,Zy as PHP_LAYER_EXTENSIONS,up as PROJECT_LABEL,pt as PROXIABLE_RECORD_TYPES,D as ParameterStore,Qm as PerformanceManager,de as Permissions,pc as PersonalizeClient,et as Phone,df as PhoneAdvanced,fm as PhoneHandlers,Oa as PlacementService,xa as PlacementStore,Un as PollyClient,he as PorkbunProvider,Sn as PreDeployScanner,ll as PreviewEnvironmentManager,zr as PreviewEnvironmentService,We as PreviewEnvironmentStore,ul as PreviewNotificationService,vy as ProgressBar,Sl as ProgressiveDeploymentManager,Xo as ProtectionControlStore,GA as Pseudo,J as Queue,Pi as QueueCancellationError,mf as QueueManagementManager,EI as QueuePresets,uo as QueueTimeoutError,Fn as R2ApiError,Pn as R2NotEnabledError,oi as R2Provider,np as R2_NOT_ENABLED_ERROR_CODE,Fl as RATE_LIMIT_KEY_SEPARATOR,ne as RDSClient,xy as RECOMMENDED_ACCOUNT_STRUCTURES,CC as RECOMMENDED_SCPS,Of as RELEASE_QUEUE_KINDS,Dy as REPL,Ny as REPLCommandBuilder,Py as REPLContext,pp as ROLE_LABEL,hy as RateLimiter,vI as RealtimePresets,zp as RecordingSpendTransport,Ji as RecursionGuard,Dt as Redirects,Om as RegionPairManager,La as RegionService,_a as RegionStore,Ye as Registry,Ft as RekognitionClient,Nt as ReleaseService,oa as ReleaseStore,Jf as RemoteBuildService,bl as ReplicaManager,Rf as ResourceManagementManager,ae as RetryableOperationError,I as Route53Client,lc as Route53DomainsClient,ie as Route53Provider,tf as Route53ResolverManager,Tl as Route53RoutingManager,ve as RuntimeOperationService,Aa as RuntimeStreamRegistry,qa as S3BackupDestinationAdapter,o as S3Client,V as S3Error,uu as SECRET_PATTERNS,Vp as SENSITIVITY_THRESHOLDS,gt as SESClient,X as SMS,lt as SNSClient,Zp as SPEND_CYCLE_SECONDS,_d as SPEND_GATE_SETTING,MA as SPEND_LEASE_SETTING,pe as SQSClient,Ne as SSH_BOOTSTRAP_VERSION,di as SSH_PREFLIGHT_SCRIPT,Be as SSMClient,nm as STATE_DIR_ENV_VAR,so as STATIC_SITE_ZONE_SETTINGS,el as STORAGE_FAILOVER_METADATA_KEY,Te as STSClient,Qn as SchedulerClient,ar as Search,In as SecretFindingScanner,Vi as Secrets,Cl as SecretsManager,re as SecretsManagerClient,Gm as SecretsRotationManager,C as Security,lr as SecurityHubManager,yn as SecurityPostureStore,kt as SecurityScannerRunner,qm as SecurityScanningManager,sf as SenderReputationManager,zf as ServerCronJobAdapter,Ta as ServerDataAdapter,fo as ServerPathVolumeDriver,vl as ServiceMeshManager,rl as Sftp,vo as SignalSource,lf as SmsAdvanced,Qt as SmsClient,hm as SmsHandlers,yc as SmsVoiceClient,aa as SourceConnectionStore,pr as SourceProviderError,Ld as SpendCapError,Zr as SpendGate,Xp as SpendLoopLease,Po as SpendNotificationRouter,Yp as SpendRunner,nr as SpendService,ki as SpendStore,wy as Spinner,Mr as SshDriver,En as SshFleetDriver,_m as StackDependencyManager,LI as StacksIntegration,vf as StaticSiteManager,xe as Storage,Ll as StorageAdvancedManager,Hn as SupportClient,ur as SyntheticsManager,Nu as SystemFleetSshTransport,$r as SystemSshTransport,ha as SystemdDiscoveryAdapter,Ho as TRACE_HEADER,Ry as TaskList,vt as TelemetryStore,Jd as TemplateBuilder,al as TemplateCache,Ut as TextractClient,Ln as TranscribeClient,Ir as TranslateClient,eh as TransportDisasterRecoveryDriver,Zf as TransportPlatformMaintenanceDriver,us as TransportRemoteBuildDriver,pa as TrivyImageScanner,sa as TsCloudApiError,tu as TsCloudClient,$A as URGENT_SPEND_EVENTS,Up as USER_VISIBLE_ACTIONS,$a as UnavailableRegionalDriver,Ae as UnifiedDnsValidator,ao as UnsupportedSchemaVersionError,Cm as ValidationError,Er as VoiceClient,mo as VolumeService,er as VolumeStore,qc as WORKER_MODULE_TYPE,si as WorkersApiError,mc as WorkersPermissionError,hc as WorkersProvider,KA as Workflow,Mm as XRayManager,Hy as abTestManager,ru as activateImmutableRelease,zg as addDns01ChallengeRecord,Tn as addSiteToCloudConfig,xt as ageSeconds,vd as aggregateDeltas,Np as allocateSitePorts,mm as amazonLinuxImageId,zA as amazonLinuxImageParameter,BI as analyzeStackDiff,Oi as anomalyOptionsForSignal,Yo as applyControlsToDdos,Vl as applyControlsToRateLimits,Ls as applyDeclaredZoneSettings,nn as applyMitigationFactor,Xh as applyPlan,Us as applyZoneMigration,wl as artifactKey,Tt as assertOriginGroupMethods,ns as assertReleaseStrategy,xA as assertSpendAllows,rA as attachConflicts,nA as attachIsViable,tA as attachPreconditions,hu as attachProvenanceToRelease,ma as attachSbomToRelease,mu as attachVulnerabilitySummary,Bf as authEncryptionKeyFile,x as authorizeOrganization,qf as authorizeRuntimePath,Yb as autocomplete,Ly as awsConfigManager,rg as backupCredentialStatus,Oy as backupManager,Eb as batch,pE as batchProcessingManager,na as beginOidcAuthorization,Uy as blueGreenManager,aE as bounceComplaintHandler,Ct as budgetWindow,ac as buildAndPushServerlessImage,hE as buildBunRuntimeLayerZip,dA as buildCertificatePackScript,oA as buildCertificateStateScript,lA as buildCertificateUnpackScript,il as buildCloudFormationTemplate,Uc as buildCloudInitFirstBoot,md as buildComposeLogsCommand,bI as buildComposeRuntimeCommand,CI as buildComposeScaleCommand,fd as buildComposeShellCommand,Rp as buildDrainSourceScript,Hh as buildDrainedSiteScanScript,tl as buildFailoverReplicaPolicyStatement,Ar as buildFunctionEnv,wp as buildHealthGateScript,ti as buildHostCleanupDeployScript,zs as buildHostCleanupInstallScript,ei as buildHostCleanupScript,wi as buildHostSitePortsScript,Hi as buildMailEnv,Ys as buildManagementDashboardArtifact,HS as buildMediaCdnPlan,Cg as buildMtaStsPolicy,Eh as buildMtaStsServer,fE as buildNodeRuntimeLayerZip,YC as buildOptimizationManager,Zd as buildOriginGroup,an as buildOriginGroups,bc as buildOriginGuardRule,Sp as buildPauseWorkersScript,IE as buildPhpRuntimeLayerZip,pm as buildReplicationConfiguration,gm as buildReplicationRole,Ep as buildRestoreScript,B as buildRpxConfig,ke as buildRpxFragmentRefreshScript,Zh as buildSetHostnameScript,ni as buildSiteDeployScript,Cp as buildSnapshotScript,Dp as buildSourceStateScript,Xn as buildSshArgs,ai as buildSshBootstrapScript,Ic as buildStaticSiteCacheRules,ii as buildStaticSiteDeployScript,vp as buildTargetStateScript,dp as buildUploadForm,Ip as buildWorkersStateScript,Zc as bundleWorker,yu as bytes,op as cacheRuleParameters,Qy as canaryManager,vn as canonicalJson,Bt as capabilities,hr as capacity,Bb as categorizeChanges,WC as certificateManager,cA as certificatesMatch,pb as checkIAMPermissions,Sf as checkInvocation,fb as checkServiceQuotas,Ay as chunk,sR as cleanupDns01Challenge,fS as clearSigningKeyCache,da as cloneSourceBinding,yy as cloudConfigSchema,Kg as cloudDrivers,$y as cloudTrailManager,ep as collectAssets,jo as collectPhpAppEntries,Sg as collectServerDnsDomains,Op as completeComposeVolumeDeletion,ia as completeOidcAuthorization,tb as composePresets,lo as composeProjectName,Dl as composeServerlessAppTemplate,UA as compositeSpendTransport,$t as compressBackup,CS as config,Sc as configOrigins,Ru as connectionGuidance,Ky as containerRegistryManager,mA as controlPlaneDatabaseFile,ad as controlPlaneMigrations,GI as createApiBackendPreset,ga as createApiV1Handler,kS as createAsgBuildDriver,ng as createBackupQueueHandlers,aS as createCliHandler,F as createCloudDriver,Uu as createCloudFrontPolicy,db as createCredentialProvider,ZI as createDashboardSite,KI as createDataPipelinePreset,Du as createDataServiceQueueHandlers,hd as createDeploymentQueueHandlers,k as createDnsProvider,NS as createEcsBuildDriver,$d as createEnforcementHandlers,Em as createError,sl as createExistingStaticFullStackPreset,ku as createFleetQueueHandlers,HI as createFullStackAppPreset,Gs as createGoDaddyValidator,SE as createHandlers,sS as createHttpHandler,qI as createJamstackPreset,wu as createJobQueueHandlers,XI as createLaravelPreset,WI as createMLApiPreset,Mu as createMaintenanceQueueHandlers,WS as createMediaAccessToken,jI as createMicroservicesPreset,Ub as createMockAWS,FI as createNodeJsServerPreset,UI as createNodeJsServerlessPreset,Ds as createObjectStorageClient,Hs as createPorkbunValidator,rb as createPreset,zo as createPresignedUrl,lS as createPresignedUrlAsync,oS as createQueueHandler,zI as createRealtimeAppPreset,xu as createRegionQueueHandlers,fu as createReleaseProvenance,iu as createReleaseQueueHandlers,DS as createRemoteBuildQueueHandlers,Vs as createRoute53Validator,Vf as createRuntimeAdapters,cy as createS3Client,PS as createServerBuildDriver,YI as createServerlessLaravelPreset,QI as createServerlessNodePreset,Ag as createSmsInfrastructure,ot as createSourceAdapter,MI as createStaticSitePreset,JI as createTraditionalWebAppPreset,Ad as createVolumeQueueHandlers,VI as createWordPressPreset,rt as createZip,oC as crossRegionReferenceManager,kn as dashboardActions,Xs as dashboardCredentialsFile,Cn as dataServiceCapabilities,zC as databaseUserManager,jl as decodeBase32,Fe as decompressBackup,lh as decryptBackup,Zo as defaultConfig,wm as defaultLocalConfig,Ql as defaultRateLimitRules,Rr as delegateZone,Os as delegateZoneFromConfig,Yu as deleteFailoverReplicaBuckets,sc as deleteStaticSite,Wc as deployAllComputeSites,Ha as deployServerlessApp,Zu as deploySite,Zs as deploySiteRelease,bs as deployStaticSite,oc as deployStaticSiteFull,Bn as deployStaticSiteWithExternalDns,xn as deployStaticSiteWithExternalDnsFull,IS as deployToFly,Wd as deploymentCoexistenceError,ZA as deriveManagementDashboardPort,_s as describeDelegation,Gl as describePosture,$s as describeZoneSettings,jf as desiredJobProviderState,Gp as detectAnomalies,im as detectDeploymentTargets,Cc as detectDnsProvider,Bd as detectLatestAnomaly,ub as detectMisconfigurations,$l as detectServiceRegion,gd as diffCompose,Pb as diffTemplates,ca as discoverGitRefs,ra as discoverOidcProvider,Su as discoverRuntimeInventory,gE as dlqMonitoringManager,Ec as dnsProviders,sE as dnssecManager,Qf as dockerWorkloads,gs as documentDigest,Hc as domainStatus,_y as drManager,qe as driverStatePath,Iu as ecsWorkloads,Zt as effectiveCapabilities,cE as emailAnalyticsManager,lE as emailTemplateManager,es as encodeBase32,dh as encryptBackup,Au as ensureDefaultSecurityPolicies,Wu as ensureFailoverReplicaBuckets,hi as ensureFirewall,Si as ensureManagementDashboard,Ai as ensureServer,fi as ensureSshKey,oe as escapeSecLang,wd as evaluateBudget,ui as evaluatePreflight,Do as evaluateTelemetryAlertRules,Tu as eventBridgeScheduleInput,iS as eventToRequest,NA as ewma,ud as exportCompose,Ms as exportRoute53Zone,Im as extendPreset,uE as fifoQueueManager,Cb as findChangedFiles,Lp as findMapping,_p as findPriceEntry,$S as flyDeployOptions,Qc as flyIpType,fg as flyMachineConfig,RC as formatAccountStructure,iA as formatAttachPlan,Vb as formatBytes,tn as formatCents,xI as formatDiff,Vh as formatDrainedSiteRefusal,qb as formatDuration,eC as formatFlagSuggestions,nC as formatHistory,iC as formatHistoryStats,Kh as formatInventory,zb as formatKeyValue,jb as formatList,Jh as formatPlan,pi as formatPreflightFindings,Gb as formatProgressBar,By as formatRegion,yC as formatRegionList,$f as formatScanResults,Kb as formatSuggestion,Qb as formatTable,Xr as formatTimeToExhaustion,Hb as formatTree,iy as fromEC2Metadata,sy as fromECSMetadata,ry as fromEnvironment,ny as fromSharedCredentials,oy as fromWebIdentity,kl as functionFingerprint,io as gatewayHostnames,Nl as generateAppImageDockerfile,QC as generateApprovalConfig,ff as generateBootstrap,by as generateCleanupWorkflow,Cy as generateCostReportWorkflow,TC as generateCrossAccountRoleCF,gu as generateCycloneDxSbom,MC as generateDeploymentConfig,xC as generateDeploymentPipeline,DC as generateDeploymentWorkflow,ic as generateExternalDnsStaticSiteTemplate,iR as generateHttpsServerCode,pu as generateImageSbom,nR as generateLetsEncryptUserData,t as generateLogicalId,$C as generateManualPipeline,BC as generateMatrixWorkflow,FC as generateMultiEnvConfig,OC as generateMultiEnvPipeline,PC as generateMultiEnvWorkflow,NC as generatePRPreviewWorkflow,HC as generateParallelConfig,Cf as generatePhpFpmConfig,hf as generatePhpLayerDockerfile,_C as generatePreviewPipeline,Iy as generatePreviewWorkflow,r as generateResourceName,UC as generateScheduledConfig,LC as generateScheduledPipeline,kC as generateScheduledWorkflow,Is as generateStaticSiteTemplate,M as generateUbuntuAppCloudInit,bm as getAccountId,lC as getAllRegions,fC as getClosestRegion,tC as getCommandUsage,fA as getComposeTemplate,Pf as getConfig,Jb as getContextualHelp,ji as getCredentials,xb as getDeploymentStrategy,Ob as getDiffStats,Nb as getDiffSummary,gy as getErrorDetails,dl as getLocalConfig,Mb as getLocalCredentials,$b as getLocalEndpoint,Fb as getLocalEnvVars,hb as getQuotaUsageSummary,vC as getRecommendedStructure,zi as getRegion,SC as getRegionStats,gC as getRegionsByCompliance,uC as getRegionsByLocation,pC as getRegionsByPricingTier,py as getRequiredPermissions,hS as getSigningKeyCacheSize,hg as getSmsInfrastructureStatus,TI as getTimestamp,Ko as globMatches,eo as globToRegex,aC as globalResourceManager,Bi as governingLimitCents,Ju as grantFailoverReplicaAccess,My as guardDutyManager,No as handleSpendRequest,no as hasAutoWwwVariant,cr as hasManagementDashboardSite,od as hasProxyUpstream,yb as hashBuffer,Sb as hashDirectory,vm as hashFile,Ib as hashManifest,Tm as hashString,CE as healthCheckManager,Kn as hostAcceptsIpv6,Ht as hostCondition,ea as hotp,Jr as hourBucket,PA as hourBucketsBetween,XC as imageScanningManager,fs as infraEnvFromOutputs,xl as inspectInvocation,rS as installRecursionFetch,Es as invalidateCache,yf as invocationContext,jA as isArmInstanceType,Wb as isLikelyTypo,Jn as isLocalDatabase,Lb as isLocalDevelopment,dr as isManagementDashboardSiteName,Tr as isNameserverRegistrar,AS as isNodeCryptoAvailable,kd as isOperationAllowed,Ro as isQuietHours,xo as isS3RestEndpoint,bi as isSafePattern,zd as isStateDirConfigured,Kd as isStatePath,rn as isValidCidr,mC as isValidRegion,Ni as isValidTimeZone,yS as isWebCryptoAvailable,wr as isZoneHost,bn as jobProviderCapability,Rs as keyMatchesFilters,tE as lambdaConcurrencyManager,iE as lambdaDLQManager,rE as lambdaDestinationsManager,ZC as lambdaLayersManager,nE as lambdaVPCManager,eE as lambdaVersionsManager,bu as lambdaWorkloads,Ol as laravelServerlessEnvDefaults,jr as listComposeTemplates,ss as listSourceReferences,ql as loadCloudConfig,ir as loadTelemetryPolicy,Vy as logsManager,xd as lookbackHoursForSignal,HA as mailEnabled,Xe as mailFirewallPorts,on as mailWebmailSites,Yf as maintenanceWindowOpen,Df as makeAWSRequest,gS as makeAWSRequestAsync,uS as makeAWSRequestOnce,ap as managedRuleInSync,Sm as managementDashboardSiteName,Ou as manifestDigest,mn as matchTotpCounter,zS as mediaObjectHeaders,bo as median,Qp as medianAbsoluteDeviation,Rd as mergeDecisions,dn as mergeInfrastructure,RA as mergePriceBooks,Ed as meterTelemetry,VC as metricsManager,ug as migrateObjectStorage,qC as migrationManager,IC as multiAccountManager,sC as multiRegionManager,aR as needsRenewal,EE as networkSecurityManager,Ot as nextScheduleRuns,De as normalizePublicIpv6,Le as normalizeRuntimeStatus,at as normalizeScheduleExpression,_f as normalizeSourceEvent,Ve as normalizeSshPublicKey,Kp as normalizeTelemetryPolicy,Ti as occupiedHostPorts,ua as openApiDocument,To as optionsForSignal,bC as organizationManager,_l as packagePhpApp,ln as packageServerlessApp,rd as pagesAssetHash,rh as pagesDnsRecord,cl as parallel,vb as parallelMap,Tb as parallelWithRetry,aA as parseCertificateState,Bl as parseChain,qr as parseCompose,SI as parseComposeCatalog,Uf as parseDockerInspect,og as parseDotenv,Gh as parseDrainedSites,Ri as parseHostSiteFragments,mS as parseJSONResponse,li as parsePreflightFacts,Pp as parseSourceDrained,Hf as parseSystemdRecords,Tp as parseTargetReady,sd as parseUpstreamPort,bp as parseWorkersPaused,pS as parseXMLResponse,Mi as pathTemplate,nd as pendingSteps,Io as percentOfLimit,jC as performanceManager,Pl as phpLayerBuildStage,eS as phpLayerPackages,gn as phpRuntimeLayerAssets,II as planComposeTemplateUpgrade,Dd as planEnforcement,Ap as planIsDestructive,rm as planMitigation,Yh as planServerRename,uA as planSiteMove,Fs as planZoneMigration,qt as policyTag,gi as preflightFailed,Sy as previewManager,Ey as previewNotifications,_t as previewSchedule,DA as previousBudgetWindow,Ao as priceUsage,TA as priceUsageLines,jh as probeHostRoutes,Bc as probeOriginTls,Db as processInChunks,du as processSourceWebhook,cs as productionChangeReview,Gy as progressiveDeploymentManager,Td as projectSpend,Go as propagationHeaders,cc as providerEndpoint,_u as publicKeyFingerprint,qn as qualifyName,mE as queueManagementManager,bb as quickHash,ip as r2Endpoint,ah as r2S3Credentials,Ul as rateLimitHeaders,Yi as rateLimitKey,je as readDriverState,zh as reconcile,bg as reconcileAddressRecords,Jg as reconcileCloudflareCdn,vh as reconcileCloudflareWorkers,xs as reconcileDeclaredRecords,RS as reconcileJobObservation,mh as reconcileR2Buckets,An as reconcileSourceWebhook,as as recordDashboardHostPosture,vS as recordPreDeploySecretScan,TS as recordSkippedSecretScan,Vo as recursionBlockedResponse,$e as redactRuntimeConfig,Ud as redactTelemetryText,$i as redactTelemetryValue,Rn as redeployServerlessApp,cC as regionPairManager,hn as releaseStrategyCapabilities,xf as releaseTrafficPlan,Ii as reloadRpxGateway,ws as remapKey,Ig as removeAddressRecords,Hg as removeDns01ChallengeRecord,wn as removeSiteFromCloudConfig,lu as removeSourceWebhook,vc as removeStaleServerAddressRecords,pd as renderComposeTemplate,Qi as renderDdosInstallScript,Vd as renderNftablesRuleset,ds as renderServerCron,Gd as renderSysctlFile,Xc as renderWafConfig,Ci as renderWafInstallScript,Jc as renewRpxCertificates,jy as replicaManager,QA as requestHash,kb as requiresReplacement,AE as resetRecursionRuntime,yE as resolveApp,g as resolveAppDatabase,eA as resolveAttachTarget,st as resolveAuthEncryptionKey,be as resolveCloudProvider,Xg as resolveCloudflareCdnPlan,$o as resolveCredentials,Ss as resolveDashboardAction,Kc as resolveDashboardAuth,ey as resolveDashboardDomain,ty as resolveDashboardDomains,Bs as resolveDeclaredRecords,kI as resolveDeployBucketName,K as resolveDeploymentMode,ri as resolveExecStart,Bo as resolveFailoverStatusCodes,xc as resolveHetznerApiToken,_r as resolveHostCleanupConfig,w as resolveMailProxy,b as resolveMailService,eb as resolveManagementDashboardSite,qi as resolveManagementDashboardSites,dc as resolveObjectStorage,ce as resolveOriginConnection,Wh as resolvePlan,p as resolveProjectStackName,Vr as resolveProxyUpstreams,Rl as resolveQueueNames,AA as resolveQueuedDeploymentCommand,gr as resolveQueues,tS as resolveRecursionConfig,ay as resolveRegion,ge as resolveRuntimeInventory,sr as resolveServerlessAppStackName,Xd as resolveServerlessArtifactBucketName,Gi as resolveServerlessAssetBucketName,Wi as resolveServerlessRuntime,PI as resolveSiteBucketName,oo as resolveSiteDeployTarget,d as resolveSiteKind,DI as resolveSiteResourceName,RI as resolveSiteStackName,ci as resolveSshSettings,l as resolveStatePath,NI as resolveStorageBucketName,lm as resolveStorageFailover,Jt as resolveUiSource,ed as resolveZoneApex,vE as resourceManagementManager,bf as responseToResult,Hp as robustZScore,Yt as roleCapabilities,nu as rollbackImmutableRelease,Dn as rollbackServerlessApp,wA as roundCents,oE as route53ResolverManager,Jy as route53RoutingManager,qp as routeMatches,mp as routesFromFragments,Xi as ruleMatches,Xy as runBuildHooks,Pd as runEnforcement,qo as runPhpBuildHooks,ct as runRemoteCommand,Ee as runtimeId,Qe as s3OriginBucket,um as s3RegionalDomain,qs as sameCorsRules,Ga as sameLifecycleRules,jn as sameNameservers,ys as sanitizeCloudConfig,s as sanitizeControlPlaneValue,wI as sanitizeName,Xl as sanitizeOidcReturnPath,Md as saveTelemetryPolicy,Lf as scanForSecrets,cd as scopeContains,Et as scopeKey,Rc as scpUpload,Xb as searchCommands,co as searchControlPlane,zy as secretsManager,KC as secretsRotationManager,wS as secureContainerRelease,Fy as securityHubManager,JC as securityScanningManager,ue as securityScope,Xu as seedFailoverReplicas,fn as sendAuthenticationEmail,dE as senderReputationManager,wb as sequence,ag as serializeDotenv,yi as serverPublicIpv4,Wy as serviceMeshManager,qu as setAttachToInCloudConfig,yr as setMaintenance,ps as setSitePropertyInCloudConfig,jd as setStateDir,oR as setupDns01Challenge,Ac as setupSmsInfrastructure,Fo as sha256,nS as sharedRecursionGuard,Af as sharedRuntimeLoop,Bp as shipsARelease,BS as signCloudFrontCookies,MS as signCloudFrontUrl,N as signRequest,Ml as signRequestAsync,Eo as signalDefinition,U as siteInstallBase,vi as siteMoveArchivePath,sA as siteMoveCertArchivePath,id as siteUnitGlob,Jp as spendNotificationText,ko as spendOpenApiPaths,xr as sshExec,Se as sshExecOrThrow,dC as stackDependencyManager,nc as startLocalDashboardServer,FA as startSpendLoop,sn as stateDir,Q as statePath,bE as staticSiteManager,dS as storageAdvancedManager,_I as storageFailoverReplicasFromTemplate,kA as streamFocusJsonl,Nd as strongestActiveAction,Nm as suggestCommand,Zb as suggestFlags,mb as suggestIAMPolicy,Ab as suggestQuotaIncrease,AC as suggestRegionPairs,hC as suggestRegions,is as syncSourceRepositories,yd as synchronizeComposeVolumes,cg as synchronizeConfiguredConfiguration,ya as synchronizeConfiguredJobs,qy as syntheticsManager,Hd as sysctlHardening,Gf as systemdWorkloads,LA as telemetryBucketLabel,Fi as telemetryCursor,Fd as telemetryEstimatedMonthlyCost,_A as telemetryPercentile,Wp as telemetryPolicyKey,my as templateCache,fp as tenantsOf,la as testSourceConnection,Sd as tieredMicroCents,cp as toApiLifecycleRule,Mc as toCloudflareZoneSettings,wo as toFocusJsonl,Od as toFocusRecords,qh as toInventoryServer,Nf as totp,ta as totpUri,hp as unaccountedSites,Ff as unsupportedCapabilities,yA as unsupportedVolumeCapabilities,$u as updateCompatibility,Fu as updateSiteInCloudConfig,Cs as uploadStaticFiles,$p as usageDeltaKey,rr as utcInstantOfLocal,wC as validateAccountStructure,_b as validateAgainstSchema,IA as validateAttachment,ch as validateBackupDestination,rC as validateCommand,lb as validateConfiguration,gb as validateCredentials,kp as validateDeploymentConfig,SA as validateMountPath,wt as validateOriginGroups,Fg as validateResourceLimits,yp as validateServerName,kg as validateTemplate,Lg as validateTemplateSize,wc as verifyAddressRecord,ES as verifyArtifactSignature,VS as verifyMediaAccessToken,kf as verifyTotp,Lu as verifyUpdateSignature,Qs as verifyZoneParity,po as volumeCapabilities,sp as wafEventTelemetry,Dc as waitForCloudInit,Yn as waitForSsh,mr as webhookEndpoint,ab as withCDN,ob as withCache,eg as withContentHash,sb as withDatabase,If as withInvocation,nb as withMonitoring,cb as withQueue,ib as withSecurity,Rb as withTimeout,tg as workerBindings,Ps as workerContentHash,Pc as workerInSync,se as wrapCloudInitUserData,ft as writeDriverState,GC as xrayManager,Bu as zeroCapacity,BA as zeroFill,bd as zoneOffsetMs,yo as zonedParts};
604
+ `}async function Wg(u,f,R){let A=`_acme-challenge.${f}`;if(await zg(u,f,A,R))return;let T=await u.createRecord(f,{name:A,type:"TXT",content:R,ttl:60});if(!T.success)throw Error(`Failed to create DNS challenge record: ${T.message}`)}async function Vg(u,f,R){let A=await u.deleteRecord(f,{name:`_acme-challenge.${f}`,type:"TXT",content:R});if(!A.success)console.warn(`Failed to delete DNS challenge record: ${A.message}`)}async function zg(u,f,R,A){try{let T=await u.listRecords(f,"TXT"),E=R.replace(/\.$/,"").toLowerCase();return(T.records??[]).some((P)=>P.name.replace(/\.$/,"").toLowerCase()===E&&P.content.replace(/^"|"$/g,"")===A)}catch{return!1}}function Xu(u){let{hostedZoneId:f,dnsProvider:R,region:A="us-east-1"}=u;if(R)return N(R);if(f)return new ie(A,f);throw Error("Either dnsProvider or hostedZoneId must be provided")}async function uR(u){await Wg(Xu(u),u.domain,u.challengeValue)}async function dR(u){await Vg(Xu(u),u.domain,u.challengeValue)}function pR(u){try{let{execSync:f}=nt("node:child_process"),R=f(`openssl x509 -checkend 2592000 -noout -in ${u}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as ed,createSign as Hg,generateKeyPairSync as td}from"node:crypto";var ad={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class Ug{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(u){this.directoryUrl=u.staging?ad.staging:ad.production,this.email=u.email,this.accountKey=u.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:u}=td("ec",{namedCurve:"P-256"});return u.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let u=await fetch(this.directoryUrl);if(!u.ok)throw Error(`Failed to fetch ACME directory: ${u.status}`);return this.directory=await u.json(),this.directory}async getNonce(){if(this.nonce){let A=this.nonce;return this.nonce=null,A}let u=await this.getDirectory(),R=(await fetch(u.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!R)throw Error("Failed to get nonce from ACME server");return R}getJwk(){let u=this.accountKey.split(`
605
+ `).filter((E)=>!E.startsWith("-----")).join(""),f=Buffer.from(u,"base64"),R=f.length-65,A=f.subarray(R+1,R+33),T=f.subarray(R+33,R+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(A),y:this.base64UrlEncode(T)}}getJwkThumbprint(){let u=this.getJwk(),f=JSON.stringify({crv:u.crv,kty:u.kty,x:u.x,y:u.y}),R=ed("sha256").update(f).digest();return this.base64UrlEncode(R)}base64UrlEncode(u){return(typeof u==="string"?Buffer.from(u):u).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(u,f){let R=await this.getNonce(),A=this.getJwk(),T={alg:"ES256",nonce:R,url:u};if(this.accountUrl)T.kid=this.accountUrl;else T.jwk=A;let E=this.base64UrlEncode(JSON.stringify(T)),P=f===""?"":this.base64UrlEncode(JSON.stringify(f)),L=`${E}.${P}`,z=Hg("SHA256");z.update(L);let fe=z.sign(this.accountKey),me=fe.subarray(4,4+fe[3]),At=4+fe[3]+2,Lt=fe.subarray(At,At+fe[At-1]),mt=Buffer.alloc(32),Me=Buffer.alloc(32);me.copy(mt,32-me.length),Lt.copy(Me,32-Lt.length);let ze=Buffer.concat([mt,Me]);return JSON.stringify({protected:E,payload:P,signature:this.base64UrlEncode(ze)})}async acmeRequest(u,f){let R=await this.signPayload(u,f),A=await fetch(u,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:R}),T=A.headers.get("replay-nonce");if(T)this.nonce=T;let E,P=A.headers.get("content-type");if(P?.includes("application/json")||P?.includes("application/problem+json"))E=await A.json();else E=await A.text();if(!A.ok)throw Error(`ACME request failed: ${JSON.stringify(E)}`);return{body:E,headers:A.headers}}async registerAccount(){let u=await this.getDirectory(),{body:f,headers:R}=await this.acmeRequest(u.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),A=R.get("location");if(!A)throw Error("No account URL returned");return this.accountUrl=A,A}async createOrder(u){if(!this.accountUrl)await this.registerAccount();let f=await this.getDirectory(),{body:R,headers:A}=await this.acmeRequest(f.newOrder,{identifiers:u.map((E)=>({type:"dns",value:E}))}),T=A.get("location");if(!T)throw Error("No order URL returned");return{orderUrl:T,authorizations:R.authorizations,finalize:R.finalize}}async getAuthorization(u){let{body:f}=await this.acmeRequest(u,""),R=f.identifier.value,A=this.getJwkThumbprint(),T=f.challenges.filter((E)=>E.type==="http-01"||E.type==="dns-01").map((E)=>{let P=`${E.token}.${A}`;if(E.type==="http-01")return{type:"http-01",token:E.token,keyAuthorization:P,identifier:`/.well-known/acme-challenge/${E.token}`};else{let L=this.base64UrlEncode(ed("sha256").update(P).digest());return{type:"dns-01",token:E.token,keyAuthorization:P,identifier:`_acme-challenge.${R}`,dnsValue:L}}});return{domain:R,challenges:T}}async respondToChallenge(u){await this.acmeRequest(u,{})}async waitForAuthorization(u,f=30){for(let R=0;R<f;R++){let{body:A}=await this.acmeRequest(u,"");if(A.status==="valid")return;if(A.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(A)}`);await new Promise((T)=>setTimeout(T,2000))}throw Error("Authorization timed out")}generateCsr(u){let{privateKey:f}=td("rsa",{modulusLength:2048}),R=f.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(u,f),privateKey:R}}createSimpleCsr(u,f){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(u,f){let{csr:R,privateKey:A}=this.generateCsr(f),{body:T}=await this.acmeRequest(u,{csr:this.base64UrlEncode(Buffer.from(R,"base64"))}),E=T.certificate;if(!E)throw Error("Certificate not immediately available - polling not implemented");let L=await(await fetch(E)).text(),z=L.split(/(?=-----BEGIN CERTIFICATE-----)/g),fe=z[0],me=z.slice(1).join("");return{certificate:fe,privateKey:A,chain:me,fullchain:L,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var Ur=(u)=>u===void 0?void 0:u?"on":"off";function Hc(u){let f={ssl:u.ssl,always_use_https:Ur(u.alwaysUseHttps),automatic_https_rewrites:Ur(u.automaticHttpsRewrites),min_tls_version:u.minTlsVersion,tls_1_3:Ur(u.tls13),brotli:Ur(u.brotli),http3:Ur(u.http3),"0rtt":Ur(u.zeroRtt),early_hints:Ur(u.earlyHints),browser_cache_ttl:u.browserCacheTtl,always_online:Ur(u.alwaysOnline),websockets:Ur(u.websockets),email_obfuscation:Ur(u.emailObfuscation)};if(u.hsts)f.security_header={strict_transport_security:{enabled:u.hsts.enabled,max_age:u.hsts.maxAge??31536000,include_subdomains:u.hsts.includeSubdomains??!1,preload:u.hsts.preload??!1,nosniff:u.hsts.noSniff??!0}};for(let R of Object.keys(f))if(f[R]===void 0)delete f[R];return{...f,...u.raw??{}}}var to={ssl:"strict",alwaysUseHttps:!0,automaticHttpsRewrites:!0,minTlsVersion:"1.2",tls13:!0,brotli:!0,http3:!0,earlyHints:!0,alwaysOnline:!0,emailObfuscation:!1,browserCacheTtl:0};import{connect as Gg}from"node:tls";async function Uc(u){let{address:f,serverName:R,port:A=443,timeoutMs:T=5000}=u;return new Promise((E)=>{let P=!1,L=(fe)=>{if(P)return;P=!0;try{z.destroy()}catch{}E(fe)},z=Gg({host:f,port:A,servername:R,rejectUnauthorized:!1,timeout:T});z.once("secureConnect",()=>{if(z.authorized){L({reachable:!0,trusted:!0});return}L({reachable:!0,trusted:!1,reason:z.authorizationError?String(z.authorizationError):"origin certificate is not trusted for this hostname"})}),z.once("timeout",()=>{L({reachable:!1,trusted:!1,reason:`no TLS handshake within ${T}ms`})}),z.once("error",(fe)=>{L({reachable:!1,trusted:!1,reason:fe.message})})})}function jg(u,f){let R=f.replace(/\.$/,"").toLowerCase();return u.some((A)=>{let T=A.replace(/\.$/,"").toLowerCase();if(T===R)return!0;if(!T.startsWith("*."))return!1;let E=T.slice(2);if(!R.endsWith(`.${E}`))return!1;return!R.slice(0,R.length-E.length-1).includes(".")})}async function Kg(u){let{provider:f,zone:R,hosts:A,ipv4:T,ipv6:E,proxied:P=!0,settings:L=to,cache:z,originGuard:fe,purge:me=!0,ttl:At=300,skipOriginProbe:Lt=!1,skipEdgeCertificateCheck:mt=!1}=u,Me={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(A.length===0)return Me;let ze=[],j=P&&!mt?await f.listEdgeCertificateHosts(R):null;for(let G of A){let ht=P;if(ht&&j&&!jg(j,G)){ht=!1;let Wt=j.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${j.join(", ")})`;Me.deferredProxy.push({host:G,reason:Wt}),Me.warnings.push(`${G}: publishing DNS-only — ${Wt}. Proxying it would make Cloudflare terminate TLS with no certificate for the name, which fails the handshake outright rather than degrading. Universal SSL covers the apex and ONE level of subdomain, so a deeper name needs its own certificate; otherwise re-run the deploy once the certificate is active.`)}if(ht&&!Lt){let Wt=await Uc({address:T,serverName:G});if(!Wt.trusted){ht=!1;let zt=Wt.reason||"origin is not serving a trusted certificate";Me.deferredProxy.push({host:G,reason:zt}),Me.warnings.push(`${G}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${zt}). 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(ht)ze.push(G);let St=[{type:"A",content:T}];if(E&&Wn(G))St.push({type:"AAAA",content:E});for(let{type:Wt,content:zt}of St){let jt=await f.upsertRecord(R,{name:G,type:Wt,content:zt,ttl:At,proxied:ht});if(jt.success)Me.records.push({host:G,type:Wt,content:zt,proxied:ht});else Me.warnings.push(`${G} ${Wt} → ${zt} failed: ${jt.message||"unknown provider error"}`)}}if(ze.length===0){if(P)Me.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return Me}try{let G=Hc(L),ht=await f.applyZoneSettings(R,G);Me.settingsChanged=ht.changed;for(let St of ht.failed)Me.warnings.push(`zone setting '${St.id}' could not be applied: ${St.error}`)}catch(G){Me.warnings.push(`zone settings could not be read: ${G instanceof Error?G.message:String(G)}`)}let yt=wc(ze,z);if(yt.length>0){let G=await f.putManagedPhaseRules(R,"http_request_cache_settings",yt);if(G.success)Me.cacheRules=yt.length;else Me.warnings.push(`cache rules could not be written: ${G.message}`)}if(fe){let G=Rc(ze,fe.header,fe.value);if(G.length>0){let ht=await f.putManagedPhaseRules(R,"http_request_late_transform",G);if(ht.success)Me.originGuard=!0;else Me.warnings.push(`origin guard header could not be written: ${ht.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(me){if(Me.purged=await f.purgeCache(R,{hosts:ze}),!Me.purged)Me.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Me}var qg=(u)=>process.env[u];function cd(u,f){let R=u.replace(/\.$/,"").toLowerCase();if(f){let A=f.replace(/\.$/,"").toLowerCase();if(R===A||R.endsWith(`.${A}`))return A}return R.split(".").slice(-2).join(".")}function Zg(u,f={}){let R=f.env??qg,A=u.infrastructure?.compute?.proxy?.cdn,T=[];if(!A||A.provider!=="cloudflare")return{plan:null,errors:T};if(A.originDomain)T.push(`compute.proxy.cdn.originDomain (${A.originDomain}) is ignored for Cloudflare: the proxy forwards to the address in the record it fronts, `+"so no separate origin hostname is needed — and publishing one gives clients a documented way around the edge.");let E=R("CLOUDFLARE_API_TOKEN");if(!E)return T.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:T};let P=u.sites??{},L=A.frontedHosts?.length?[...new Set(A.frontedHosts.map((Lt)=>Lt.toLowerCase()))]:uo(P,{autoWww:u.infrastructure?.compute?.proxy?.autoWww!==!1});if(L.length===0)return T.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:T};let z=u.infrastructure?.dns?.domain,fe=new Set(L.map((Lt)=>cd(Lt,z)));if(fe.size>1)return T.push(`Fronted hosts span more than one zone (${[...fe].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:T};let me=A.cloudflare??{},At=A.secret?{header:A.secretHeader??"X-Origin-Verify",value:A.secret}:void 0;return{plan:{zone:[...fe][0],hosts:L,apiToken:E,zoneId:me.zoneId??R("CLOUDFLARE_ZONE_ID"),accountId:me.accountId??R("CLOUDFLARE_ACCOUNT_ID"),proxied:me.proxied!==!1,settings:me.settings??to,cache:me.cache,originGuard:At,purge:me.purgeOnDeploy!==!1,skipOriginProbe:me.skipOriginProbe===!0},errors:T}}var Jg=26214400;var Yg=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class ld{name="cloudflare-pages";apiToken;accountId;constructor(u){if(!u.apiToken)throw Error("Cloudflare Pages needs an API token");if(!u.accountId)throw Error("Cloudflare Pages needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId}async request(u,f,R){return _s(u,`/accounts/${this.accountId}${f}`,`Bearer ${this.apiToken}`,R)}async getProject(u){try{return await this.request("GET",`/pages/projects/${u}`)}catch(f){if(f instanceof Error&&/\b8000007\b|not found/i.test(f.message))return null;throw f}}async ensureProject(u,f="main"){let R=await this.getProject(u);if(R)return R;return this.request("POST","/pages/projects",{name:u,production_branch:f})}async uploadToken(u){return(await this.request("GET",`/pages/projects/${u}/upload-token`)).jwt}async missingHashes(u,f){let R=await _s("POST","/pages/assets/check-missing",`Bearer ${u}`,{hashes:f});return new Set(R)}async upsertHashes(u,f){await _s("POST","/pages/assets/upsert-hashes",`Bearer ${u}`,{hashes:f})}async uploadBatch(u,f){let R=f.map((A)=>({key:A.hash,value:A.base64,metadata:{contentType:Qg(A.extension)},base64:!0}));await _s("POST","/pages/assets/upload",`Bearer ${u}`,R)}async createDeployment(u,f,R){let A={};for(let E of f)A[E.path]=E.hash;let T=new FormData;if(T.append("manifest",JSON.stringify(A)),R)T.append("branch",R);return this.request("POST",`/pages/projects/${u}/deployments`,T)}async deployDirectory(u){let f=await dd(u.directory);if(f.length===0)throw Error(`No files to deploy in ${u.directory}`);let R=await this.uploadToken(u.project),A=await this.missingHashes(R,f.map((z)=>z.hash)),T=f.filter((z)=>A.has(z.hash)),E=[];for(let z=0;z<T.length;z+=100)E.push(T.slice(z,z+100));let P=0;for(let z=0;z<E.length;z+=4){let fe=E.slice(z,z+4);await Promise.all(fe.map((me)=>this.uploadBatch(R,me))),P+=fe.reduce((me,At)=>me+At.length,0),u.onProgress?.(P,T.length)}return await this.upsertHashes(R,f.map((z)=>z.hash)),{deployment:await this.createDeployment(u.project,f,u.branch),total:f.length,uploaded:T.length,uploadedBytes:T.reduce((z,fe)=>z+fe.size,0)}}async listCustomDomains(u){return(await this.request("GET",`/pages/projects/${u}/domains`)).map((R)=>R.name)}async attachCustomDomain(u,f){if((await this.listCustomDomains(u)).includes(f))return!1;return await this.request("POST",`/pages/projects/${u}/domains`,{name:f}),!0}}function Xg(u,f){return{type:"CNAME",name:u,value:f.endsWith(".pages.dev")?f:`${f}.pages.dev`,ttl:1,proxied:!0}}async function ud(u,f){let{blake3:R}=await import("./chunk-v4vz0e85.js").then((m)=>vS(m.default,1));return(await R(u+f)).slice(0,32)}async function dd(u){let{readdir:f}=await import("node:fs/promises"),{join:R,relative:A,sep:T}=await import("node:path"),E=[];async function P(L){let z=await f(L,{withFileTypes:!0});for(let fe of z){let me=R(L,fe.name);if(fe.isDirectory()){await P(me);continue}if(!fe.isFile())continue;let At=`/${A(u,me).split(T).join("/")}`;if(Yg.has(At))continue;let Lt=await Bun.file(me).bytes();if(Lt.byteLength>26214400)throw Error(`${At} is ${Lt.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let mt=Buffer.from(Lt).toString("base64"),Me=fe.name.lastIndexOf("."),ze=Me>0?fe.name.slice(Me+1):"";E.push({path:At,hash:await ud(mt,ze),base64:mt,extension:ze,size:Lt.byteLength})}}return await P(u),E.sort((L,z)=>L.path.localeCompare(z.path)),E}function Qg(u){return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",mjs:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",map:"application/json; charset=utf-8",xml:"application/xml; charset=utf-8",txt:"text/plain; charset=utf-8",svg:"image/svg+xml",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",avif:"image/avif",ico:"image/x-icon",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",pdf:"application/pdf",webmanifest:"application/manifest+json"}[u.toLowerCase()]||"application/octet-stream"}async function _s(u,f,R,A){let T={Authorization:R},E;if(A instanceof FormData)E=A;else if(A!==void 0)T["Content-Type"]="application/json",E=JSON.stringify(A);let P=await fetch(`https://api.cloudflare.com/client/v4${f}`,{method:u,headers:T,body:E}),L=await P.text(),z;try{z=JSON.parse(L)}catch{throw Error(`Cloudflare Pages API returned ${P.status} with a non-JSON body: ${L.slice(0,200)}`)}if(!z.success){let fe=(z.errors??[]).map((me)=>`${me.code}: ${me.message}`).join(", ");throw Error(`Cloudflare Pages API error (${P.status}): ${fe||L.slice(0,200)}`)}return z.result}import{createHash as lh}from"node:crypto";var tp="https://api.cloudflare.com/client/v4",rp=10042,uh=10006,dh=10059;class _n extends Error{status;errors;constructor(u,f,R=[]){super(u);this.name="R2ApiError",this.status=f,this.errors=R}hasCode(u){return this.errors.some((f)=>f.code===u)}}class kn extends _n{accountId;constructor(u,f,R=[]){super(`R2 is not enabled on Cloudflare account ${u}. Enable it once in the Cloudflare dashboard (R2 Object Storage, then follow the prompt to activate it), then re-run the deploy.`,f,R);this.name="R2NotEnabledError",this.accountId=u}}class ci{name="cloudflare-r2";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare R2 needs an API token");if(!u.accountId)throw Error("Cloudflare R2 needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((f,R)=>fetch(f,R))}async requestEnvelope(u,f,R,A={}){let T={Authorization:`Bearer ${this.apiToken}`};if(R!==void 0)T["Content-Type"]="application/json";if(A.jurisdiction&&A.jurisdiction!=="default")T["cf-r2-jurisdiction"]=A.jurisdiction;let E=await this.fetchImpl(`${tp}/accounts/${this.accountId}/r2${f}`,{method:u,headers:T,body:R===void 0?void 0:JSON.stringify(R)}),P=await E.text(),L;try{L=JSON.parse(P)}catch{throw new _n(`Cloudflare R2 API returned ${E.status} with a non-JSON body: ${P.slice(0,200)}`,E.status)}if(!L.success){let z=L.errors??[];if(z.some((me)=>me.code===rp))throw new kn(this.accountId,E.status,z);let fe=z.map((me)=>`${me.code}: ${me.message}`).join(", ");throw new _n(`Cloudflare R2 API error (${E.status}) on ${u} ${f}: ${fe||P.slice(0,200)}`,E.status,z)}return L}async request(u,f,R,A){return(await this.requestEnvelope(u,f,R,A)).result}bucketPath(u){return`/buckets/${encodeURIComponent(u)}`}async listBuckets(u={}){let f=[],R;do{let A=new URLSearchParams({per_page:"1000"});if(R)A.set("cursor",R);let T=await this.requestEnvelope("GET",`/buckets?${A}`,void 0,u),E=T.result?.buckets??[];f.push(...E),R=E.length>0?T.result_info?.cursor||void 0:void 0}while(R);return f}async getBucket(u,f={}){try{return await this.request("GET",this.bucketPath(u),void 0,f)}catch(R){if(R instanceof kn)throw R;if(R instanceof _n&&(R.hasCode(uh)||R.status===404))return null;throw R}}async ensureBucket(u,f={}){let R={jurisdiction:f.jurisdiction},A=await this.getBucket(u,R);if(A)return{bucket:A,created:!1};let T={name:u};if(f.locationHint)T.locationHint=f.locationHint;let E=await this.request("POST","/buckets",T,R);return{bucket:{...E,name:E?.name||u},created:!0}}async getCors(u,f={}){try{return(await this.request("GET",`${this.bucketPath(u)}/cors`,void 0,f))?.rules??[]}catch(R){if(R instanceof _n&&!(R instanceof kn)&&(R.hasCode(dh)||R.status===404))return[];throw R}}async putCors(u,f,R={}){if(f.length===0){await this.request("DELETE",`${this.bucketPath(u)}/cors`,void 0,R);return}await this.request("PUT",`${this.bucketPath(u)}/cors`,{rules:f},R)}async ensureCors(u,f,R={}){let A=await this.getCors(u,R);if(Zs(A,f))return!1;return await this.putCors(u,f,R),!0}async getLifecycle(u,f={}){return(await this.request("GET",`${this.bucketPath(u)}/lifecycle`,void 0,f))?.rules??[]}async putLifecycle(u,f,R={}){await this.request("PUT",`${this.bucketPath(u)}/lifecycle`,{rules:f},R)}async ensureLifecycle(u,f,R={}){let A=await this.getLifecycle(u,R);if(Js(A,f))return!1;return await this.putLifecycle(u,f,R),!0}async listCustomDomains(u,f={}){return(await this.request("GET",`${this.bucketPath(u)}/domains/custom`,void 0,f))?.domains??[]}async attachCustomDomain(u,f,R={}){return this.request("POST",`${this.bucketPath(u)}/domains/custom`,{domain:f.domain,zoneId:f.zoneId,enabled:f.enabled??!0,minTLS:f.minTLS??"1.2"},R)}async updateCustomDomain(u,f,R,A={}){return this.request("PUT",`${this.bucketPath(u)}/domains/custom/${encodeURIComponent(f)}`,R,A)}async ensureCustomDomain(u,f,R={},A){let T=f.minTLS??"1.2",P=(A??await this.listCustomDomains(u,R)).find((fe)=>fe.domain.toLowerCase()===f.domain.toLowerCase());if(!P){let fe=await this.attachCustomDomain(u,{...f,minTLS:T,enabled:!0},R);return{action:"attached",domain:{...fe,domain:fe?.domain||f.domain}}}let L=P.minTLS??"1.0";if(P.enabled&&L===T)return{action:"unchanged",domain:P};let z=await this.updateCustomDomain(u,P.domain,{enabled:!0,minTLS:T},R);return{action:"updated",domain:{...P,...z}}}async getManagedDomain(u,f={}){return this.request("GET",`${this.bucketPath(u)}/domains/managed`,void 0,f)}async setManagedDomain(u,f,R={}){let A=await this.getManagedDomain(u,R);if(A?.enabled===f)return{changed:!1,domain:A};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(u)}/domains/managed`,{enabled:f},R)}}}function np(u){return`https://${u}.r2.cloudflarestorage.com`}async function ph(u){let{apiToken:f,accountId:R}=u;if(!f)throw Error("r2S3Credentials needs an API token");if(!R)throw Error("r2S3Credentials needs an account id");let A=u.fetch??((P,L)=>fetch(P,L)),T=[],E;for(let P of[`/accounts/${R}/tokens/verify`,"/user/tokens/verify"]){let L=await A(`${tp}${P}`,{method:"GET",headers:{Authorization:`Bearer ${f}`}}),z=await L.json().catch(()=>null);if(L.ok&&z?.success&&z.result?.id){E=z.result.id;break}let fe=z?.errors?.map((me)=>`${me.code}: ${me.message}`).join(", ");T.push(`${P} -> ${L.status}${fe?` (${fe})`:""}`)}if(!E)throw Error(`Could not verify the Cloudflare API token to derive R2 credentials: ${T.join("; ")}`);return{accessKeyId:E,secretAccessKey:lh("sha256").update(f).digest("hex"),endpoint:np(R),region:"auto"}}function co(u){if(Array.isArray(u))return`[${u.map(co).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,R])=>R!==void 0).sort(([R],[A])=>R.localeCompare(A)).map(([R,A])=>`${JSON.stringify(R)}:${co(A)}`).join(",")}}`;return JSON.stringify(u)}function ep(u,f){let R=(A)=>A&&A.length>0?[...A].map(String).sort():void 0;return{id:f?u.id:void 0,allowed:{origins:R(u.allowed?.origins),methods:R(u.allowed?.methods?.map((A)=>A.toUpperCase())),headers:R(u.allowed?.headers?.map((A)=>A.toLowerCase()))},exposeHeaders:R(u.exposeHeaders?.map((A)=>A.toLowerCase())),maxAgeSeconds:u.maxAgeSeconds}}function Zs(u,f){if(u.length!==f.length)return!1;return f.every((R,A)=>{let T=R.id!==void 0;return co(ep(u[A],T))===co(ep(R,T))})}function Js(u,f){if(u.length!==f.length)return!1;let R=(A)=>co([...A].map((T)=>({...T,storageClassTransitions:T.storageClassTransitions?.length?T.storageClassTransitions:void 0})).sort((T,E)=>T.id.localeCompare(E.id)));return R(u)===R(f)}var mh="r2 cache",gh=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function fh(u,f={}){let R=f.log??(()=>{}),A={buckets:[],warnings:[]},T=u.infrastructure?.r2??u.r2,E=Object.entries(T?.buckets??{});if(E.length===0)return R("R2: no buckets declared, skipping."),A;if(!f.apiToken||!f.accountId){let me=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),At=`R2: ${E.length} bucket(s) declared but ${me} is not set, skipping.`;return R(At),A.warnings.push(At),A}let P=f.dryRun===!0,L=new ci({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),z=new H(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),fe=new Map;for(let[me,At]of E){let Lt=At?.name;if(!Lt||!gh.test(Lt)){A.warnings.push(`R2: bucket '${me}' has an invalid name '${Lt??""}' (3-63 chars: lowercase letters, digits, hyphens), skipping.`);continue}R(`R2: ${P?"checking":"reconciling"} bucket ${Lt}...`);let mt={name:Lt,changes:[],domains:[]};if(A.buckets.push(mt),await Ch(At,{r2:L,cloudflare:z,dryRun:P,summary:mt,warnings:A.warnings,claimed:fe,log:R}),mt.changes.length===0)R(`R2: ${Lt} is in sync.`);else for(let Me of mt.changes)R(`R2: ${Lt}: ${Me}`)}return A}async function Ch(u,f){let{r2:R,dryRun:A,summary:T,warnings:E}=f,P=u.name,L={jurisdiction:u.jurisdiction},z=(mt,Me)=>{let ze=A?Me&&`would ${Me}`:mt;if(ze)T.changes.push(ze)},fe;if(A)fe=await R.getBucket(P,L)!==null;else{let{created:mt}=await R.ensureBucket(P,{locationHint:u.locationHint,jurisdiction:u.jurisdiction});if(fe=!0,mt)z("created","")}if(!fe)z("","create bucket");let me=Rh(u.customDomains);await go(f,`cors on ${P}`,async()=>{if(!u.cors)return;if(!fe){z("cors updated","set cors");return}let mt=await R.getCors(P,L);if(Zs(mt,u.cors))return;if(!A)await R.putCors(P,u.cors,L);z(u.cors.length===0?"cors removed":"cors updated",u.cors.length===0?"remove cors":"update cors")}),await go(f,`lifecycle on ${P}`,async()=>{if(!u.lifecycle)return;let mt=u.lifecycle.map(ap);if(fe){let Me=await R.getLifecycle(P,L);if(Js(Me,mt))return}if(!A)await R.putLifecycle(P,mt,L);z("lifecycle updated","update lifecycle")}),await go(f,`r2.dev URL on ${P}`,async()=>{let mt=u.publicDevUrl===!0;if(!fe){if(mt)z("r2.dev URL enabled","enable r2.dev URL");return}if((await R.getManagedDomain(P,L))?.enabled===mt)return;if(!A)await R.setManagedDomain(P,mt,L);z(mt?"r2.dev URL enabled":"r2.dev URL disabled",mt?"enable r2.dev URL":"disable r2.dev URL")});let At=[];if(me.length>0&&fe)try{At=await R.listCustomDomains(P,L)}catch(mt){if(mt instanceof kn)throw mt;E.push(`R2: could not list custom domains on ${P}: ${Kc(mt)}`)}let Lt=new Map;for(let{domain:mt,minTLS:Me}of me){let ze=f.claimed.get(mt);if(ze&&ze!==P){E.push(`R2: ${mt} is declared on both ${ze} and ${P}; leaving it on ${ze}.`);continue}f.claimed.set(mt,P);let j=At.find((G)=>G.domain.toLowerCase()===mt),yt=Me??"1.2";if(j&&j.enabled&&(j.minTLS??"1.0")===yt){if(T.domains.push({domain:mt,status:jc(j)}),j.zoneId)Lt.set(mt,j.zoneId);continue}await go(f,`custom domain ${mt} on ${P}`,async()=>{if(j){if(!A)await R.updateCustomDomain(P,j.domain,{enabled:!0,minTLS:yt},L);if(z(`custom domain ${mt} updated`,`update custom domain ${mt}`),T.domains.push({domain:mt,status:jc({...j,enabled:!0})}),j.zoneId)Lt.set(mt,j.zoneId);return}let G=await f.cloudflare.zoneIdFor(mt);if(Lt.set(mt,G),!A)await R.ensureCustomDomain(P,{domain:mt,zoneId:G,minTLS:yt},L,At);z(`custom domain ${mt} attached`,`attach custom domain ${mt}`),T.domains.push({domain:mt,status:A?"not attached":"pending"})},()=>T.domains.push({domain:mt,status:"error"}))}if(u.cache&&me.length>0)await Sh(u,me.map((mt)=>mt.domain).filter((mt)=>f.claimed.get(mt)===P),Lt,f,z)}async function Sh(u,f,R,A,T){let E=op(u.cache);if(!E||f.length===0)return;let P=new Map;for(let L of f){let z=R.get(L);if(!z)try{z=await A.cloudflare.zoneIdFor(L)}catch(fe){A.warnings.push(`R2: could not resolve the zone for ${L}, cache rule skipped: ${Kc(fe)}`);continue}P.set(z,[...P.get(z)??[],L])}for(let L of P.values()){let z={action:"set_cache_settings",description:`${Gt} ${mh}`,expression:`(${Ht(L)})`,enabled:!0,action_parameters:E};await go(A,`cache rule for ${L.join(", ")}`,async()=>{let fe=await A.cloudflare.getPhaseRules(L[0],"http_request_cache_settings");if(sp(fe,z))return;if(!A.dryRun){let me=await A.cloudflare.putManagedPhaseRules(L[0],"http_request_cache_settings",[z]);if(!me.success)throw Error(me.message||"cache rule write failed")}T(`cache rule updated for ${L.join(", ")}`,`update cache rule for ${L.join(", ")}`)})}}function op(u){if(u.edgeTtl===void 0&&u.browserTtl===void 0)return null;let f={cache:!0};if(u.edgeTtl!==void 0)f.edge_ttl={mode:"override_origin",default:u.edgeTtl};if(u.browserTtl!==void 0)f.browser_ttl={mode:"override_origin",default:u.browserTtl};return f}function sp(u,f){let R=Vt(f.expression),A=qn(f.expression),T=(L)=>(L.description||"").startsWith(Gt),E=(L)=>L.action===f.action&&L.description===f.description&&(L.enabled??!0)===(f.enabled??!0)&&qn(L.expression)===A&&Wa(L.action_parameters)===Wa(f.action_parameters),P=!1;for(let L of u){if(!T(L))continue;let z=Vt(L.expression);if(!R.some((me)=>z.includes(me)))continue;if(E(L)&&R.every((me)=>z.includes(me))&&!P){P=!0;continue}return!1}return P}function ap(u){let f={id:u.id,enabled:u.enabled??!0,conditions:{prefix:u.prefix??""}};if(u.expireAfterDays!==void 0)f.deleteObjectsTransition={condition:{type:"Age",maxAge:Gc(u.expireAfterDays)}};else if(u.expireOn!==void 0)f.deleteObjectsTransition={condition:{type:"Date",date:u.expireOn}};if(u.abortMultipartUploadsAfterDays!==void 0)f.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:Gc(u.abortMultipartUploadsAfterDays)}};if(u.infrequentAccessAfterDays!==void 0)f.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:Gc(u.infrequentAccessAfterDays)}}];return f}function Gc(u){return Math.round(u*86400)}function Rh(u){let f=new Set,R=[];for(let A of u??[]){let T=typeof A==="string"?{domain:A}:A,E=T.domain?.trim().replace(/\.$/,"").toLowerCase();if(!E||f.has(E))continue;f.add(E),R.push({domain:E,minTLS:T.minTLS})}return R}function jc(u){if(!u.enabled)return"disabled";let f=u.status?.ownership,R=u.status?.ssl;if(f==="active"&&R==="active")return"active";for(let A of[f,R])if(A==="error"||A==="blocked"||A==="deactivated")return A;return"pending"}async function go(u,f,R,A){try{await R()}catch(T){if(T instanceof kn)throw T;u.warnings.push(`R2: ${f} failed: ${Kc(T)}`),A?.()}}function Kc(u){return u instanceof Error?u.message:String(u)}function Wa(u){if(Array.isArray(u))return`[${u.map(Wa).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,R])=>R!==void 0).sort(([R],[A])=>R.localeCompare(A)).map(([R,A])=>`${JSON.stringify(R)}:${Wa(A)}`).join(",")}}`;return JSON.stringify(u)}import{basename as Dh,extname as kh}from"node:path";import{createHash as bh}from"node:crypto";var Th="https://api.cloudflare.com/client/v4",Fn="TS_CLOUD_CONTENT_HASH",Ss="2025-09-01",Zc="application/javascript+module",Ph=10007,$h=[1e4,9109];class ui extends Error{status;errors;constructor(u,f,R=[]){super(u);this.name="WorkersApiError",this.status=f,this.errors=R}hasCode(u){return this.errors.some((f)=>f.code===u)}}class za extends ui{permission;constructor(u,f,R,A=[]){super(`The Cloudflare API token is missing the "${u}" permission (${f}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,R,A);this.name="WorkersPermissionError",this.permission=u}}class Cc{name="cloudflare-workers";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare Workers needs an API token");if(!u.accountId)throw Error("Cloudflare Workers needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((f,R)=>fetch(f,R))}async request(u,f,R){let A={Authorization:`Bearer ${this.apiToken}`},T;if(R instanceof FormData)T=R;else if(R!==void 0)A["Content-Type"]="application/json",T=JSON.stringify(R);let E=await this.fetchImpl(`${Th}/accounts/${this.accountId}/workers${f}`,{method:u,headers:A,body:T}),P=await E.text(),L;try{L=JSON.parse(P)}catch{throw new ui(`Cloudflare Workers API returned ${E.status} with a non-JSON body: ${P.slice(0,200)}`,E.status)}if(!L.success){let z=L.errors??[],fe=z.map((me)=>`${me.code}: ${me.message}`).join(", ");if(wh(E.status,z))throw new za(Ih(f),`${u} ${f} -> ${E.status}${fe?`, ${fe}`:""}`,E.status,z);throw new ui(`Cloudflare Workers API error (${E.status}) on ${u} ${f}: ${fe||P.slice(0,200)}`,E.status,z)}return L.result}scriptPath(u){return`/scripts/${encodeURIComponent(u)}`}async getSettings(u){try{return await this.request("GET",`${this.scriptPath(u)}/settings`)}catch(f){if(f instanceof za)throw f;if(f instanceof ui&&(f.hasCode(Ph)||f.status===404))return null;throw f}}async getScript(u){return this.getSettings(u)}async uploadModuleScript(u,f){return this.request("PUT",this.scriptPath(u),lp(f))}async ensureModuleScript(u,f){let R=bs(f),A=await this.getSettings(u);if(A&&$c(A,f,R))return{action:"unchanged",hash:R};return await this.uploadModuleScript(u,up(f,R)),{action:A?"updated":"created",hash:R}}async listCustomDomains(u={}){let f=new URLSearchParams;if(u.service)f.set("service",u.service);if(u.hostname)f.set("hostname",u.hostname);if(u.zoneId)f.set("zone_id",u.zoneId);let R=f.toString(),A=R?`?${R}`:"";return await this.request("GET",`/domains${A}`)??[]}async attachCustomDomain(u,f){let R={hostname:u,service:f.service,environment:f.environment??"production"};if(f.zoneId)R.zone_id=f.zoneId;return this.request("PUT","/domains",R)}async detachCustomDomain(u){await this.request("DELETE",`/domains/${encodeURIComponent(u)}`)}async ensureCustomDomain(u,f,R){let T=(R??await this.listCustomDomains({hostname:u})).find((P)=>P.hostname.toLowerCase()===u.toLowerCase());if(T&&T.service===f.service)return{action:"unchanged",domain:T};if(T)throw Error(`${u} is attached to the Worker '${T.service}'. Detach it there first (Workers & Pages, ${T.service}, Settings, Domains & Routes); ts-cloud does not move it.`);let E=await this.attachCustomDomain(u,f);return{action:"attached",domain:{...E,hostname:E?.hostname||u}}}}function wh(u,f){if(f.some((R)=>$h.includes(R.code)))return!0;return(u===401||u===403)&&f.length===0}function Ih(u){if(u.startsWith("/domains"))return"Workers Routes: Edit (zone, for Workers custom domains) and Workers Scripts: Edit (account)";return"Workers Scripts: Edit (account)"}function lp(u){if(!u.modules.some((A)=>A.name===u.mainModule))throw Error(`Worker main module '${u.mainModule}' is not one of the uploaded modules`);let f={main_module:u.mainModule,bindings:u.bindings??[],compatibility_date:u.compatibilityDate??Ss,compatibility_flags:u.compatibilityFlags??[],keep_bindings:["secret_text"]},R=new FormData;R.append("metadata",JSON.stringify(f));for(let A of u.modules)R.append(A.name,new Blob([A.content],{type:A.type}),A.name);return R}function bs(u){let f={mainModule:u.mainModule,modules:[...u.modules].sort((R,A)=>R.name.localeCompare(A.name)).map((R)=>({name:R.name,type:R.type,sha256:cp(R.content)})),bindings:[...u.bindings??[]].filter((R)=>R.name!==Fn).sort((R,A)=>R.name.localeCompare(A.name)),compatibilityDate:u.compatibilityDate??Ss,compatibilityFlags:[...u.compatibilityFlags??[]].sort()};return cp(qc(f))}function up(u,f=bs(u)){return{...u,bindings:[...(u.bindings??[]).filter((R)=>R.name!==Fn),{type:"plain_text",name:Fn,text:f}]}}function $c(u,f,R){let A=u.bindings??[],T=A.find((E)=>E.name===Fn&&E.type==="plain_text");if(!T||T.text!==R)return!1;return(f.bindings??[]).every((E)=>{let P=A.find((z)=>z.name===E.name);if(!P||P.type!==E.type)return!1;let L=E.type==="r2_bucket"?"bucket_name":E.type==="plain_text"?"text":void 0;return!L||P[L]===E[L]})}function cp(u){return bh("sha256").update(u).digest("hex")}function qc(u){if(Array.isArray(u))return`[${u.map(qc).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,R])=>R!==void 0).sort(([R],[A])=>R.localeCompare(A)).map(([R,A])=>`${JSON.stringify(R)}:${qc(A)}`).join(",")}}`;return JSON.stringify(u)}async function Yc(u){if(!await Bun.file(u).exists())throw Error(`Worker entry not found: ${u}`);let f;try{f=await Bun.build({entrypoints:[u],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(T){throw Error(`Bundling Worker ${u} failed: ${vh(T)}`)}if(!f.success)throw Error(`Bundling Worker ${u} failed: ${f.logs.map((T)=>String(T.message??T)).join("; ")}`);if(f.outputs.length!==1)throw Error(`Bundling Worker ${u} produced ${f.outputs.length} files (${f.outputs.map((T)=>T.path).join(", ")}); a Worker is uploaded as a single module, so remove the dynamic imports or asset imports that split it.`);let R=f.outputs[0];if(R.kind!=="entry-point")throw Error(`Bundling Worker ${u} produced a ${R.kind} instead of an entry module`);let A=await R.text();return{name:`${Dh(u,kh(u))}.js`,content:A,type:Zc,size:new TextEncoder().encode(A).byteLength}}function vh(u){if(u instanceof AggregateError&&u.errors.length>0)return u.errors.map((f)=>f instanceof Error?f.message:String(f?.message??f)).join("; ");return u instanceof Error?u.message:String(u)}import{isAbsolute as Eh,resolve as Oh}from"node:path";var xh="https://api.cloudflare.com/client/v4",Lh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function Fh(u,f={}){let R=f.log??(()=>{}),A={workers:[],warnings:[]},T=Object.entries(u.infrastructure?.workers??u.workers??{});if(T.length===0)return R("Workers: none declared, skipping."),A;if(!f.apiToken||!f.accountId){let L=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),z=`Workers: ${T.length} Worker(s) declared but ${L} is not set, skipping.`;return R(z),A.warnings.push(z),A}let E=u.infrastructure?.r2??u.r2,P={workers:new Cc({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),r2:new ci({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),cloudflare:new H(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),apiToken:f.apiToken,fetch:f.fetch??((L,z)=>fetch(L,z)),projectRoot:f.projectRoot??process.cwd(),dryRun:f.dryRun===!0,warnings:A.warnings,log:R,r2ConfigDomains:Uh(E),r2Buckets:E,claimed:new Map};for(let[L,z]of T){let fe=z?.name;if(!fe||!Lh.test(fe)){A.warnings.push(`Workers: '${L}' has an invalid name '${fe??""}' (1-63 chars: lowercase letters, digits, '-' and '_'), skipping.`);continue}if(!z.entry){A.warnings.push(`Workers: ${fe} has no entry, skipping.`);continue}R(`Workers: ${P.dryRun?"checking":"reconciling"} ${fe}...`);let me={name:fe,changes:[],domains:[]};A.workers.push(me),await _h(z,me,P);for(let At of me.changes)R(`Workers: ${fe}: ${At}`)}return A}async function _h(u,f,R){let A=u.name,T=Eh(u.entry)?u.entry:Oh(R.projectRoot,u.entry),E;try{E=await Yc(T)}catch(L){throw Error(`Worker ${A}: ${Si(L)}`)}f.changes.push(`bundled ${jh(E.size)}`);let P={mainModule:E.name,modules:[{name:E.name,content:E.content,type:E.type}],bindings:dp(u,R),compatibilityDate:u.compatibilityDate??Ss,compatibilityFlags:u.compatibilityFlags??[]};if(R.dryRun){let L=await R.workers.getSettings(A);f.changes.push(L&&$c(L,P,bs(P))?"unchanged":"would upload")}else{let{action:L}=await R.workers.ensureModuleScript(A,P);f.changes.push(L==="unchanged"?"unchanged":"uploaded")}for(let L of Gh(u.customDomains))await Mh(A,L,f,R)}async function Mh(u,f,R,A){let T=(mt)=>{R.domains.push({domain:f,status:mt})},E=(mt)=>{A.warnings.push(`Workers: ${mt}`),T("conflict")},P=A.claimed.get(f);if(P&&P!==u){E(`${f} is declared on both ${P} and ${u}; leaving it on ${P}.`);return}A.claimed.set(f,u);let L=A.r2ConfigDomains.get(f);if(L){E(`${f} is also declared as a custom domain of the R2 bucket '${L}' (r2.buckets). A hostname serves either a bucket or a Worker. Remove it from the bucket's customDomains and detach it in the dashboard (R2, ${L}, Settings, Custom Domains) first; to serve the bucket through the Worker, bind it with bindings.r2Buckets instead.`);return}let z=await Bh(A);if(z===null){T("error");return}let fe=z.find((mt)=>mt.hostname.toLowerCase()===f);if(fe?.service===u){T("active");return}if(fe){E(`${f} is attached to the Worker '${fe.service}'. Detach it there first (Workers & Pages, ${fe.service}, Settings, Domains & Routes); it is not moved automatically.`);return}let me=(await Vh(A))?.get(f);if(me){E(`${f} is attached to the R2 bucket '${me}' as a custom domain. Detach it first (R2, ${me}, Settings, Custom Domains, then re-run the deploy); it is not detached automatically. To serve the bucket through the Worker, bind it with bindings.r2Buckets.`);return}let At;try{At=await A.cloudflare.zoneIdFor(f)}catch(mt){A.warnings.push(`Workers: could not resolve the zone for ${f}, not attached: ${Si(mt)}`),T("error");return}let Lt=await Hh(A,At,f);if(Lt.length>0){let mt=Lt.map((Me)=>`${Me.type} ${Me.content}`).join(", ");E(`${f} already has a DNS record (${mt}). A Worker custom domain creates its own record, so Cloudflare will not attach over it. Delete the record first (DNS, Records), then re-run the deploy; it is not deleted automatically.`);return}if(A.dryRun){R.changes.push(`would attach custom domain ${f}`),T("not attached");return}try{await A.workers.ensureCustomDomain(f,{service:u,zoneId:At},z),R.changes.push(`custom domain ${f} attached`),z.push({id:"",hostname:f,service:u,zone_id:At}),T("pending")}catch(mt){A.warnings.push(`Workers: custom domain ${f} on ${u} failed: ${Si(mt)}`),T("error")}}async function Bh(u){if(u.attached!==void 0)return u.attached;try{u.attached=await u.workers.listCustomDomains()}catch(f){u.warnings.push(`Workers: could not list Worker custom domains, none attached: ${Si(f)}`),u.attached=null}return u.attached}async function Vh(u){if(u.r2AccountDomains!==void 0)return u.r2AccountDomains;let f=new Map;try{let R=(await u.r2.listBuckets()).map((A)=>({name:A.name}));for(let A of Object.values(u.r2Buckets?.buckets??{}))if(A.jurisdiction&&A.jurisdiction!=="default")R.push({name:A.name,jurisdiction:A.jurisdiction});for(let A of R){let T=await u.r2.listCustomDomains(A.name,{jurisdiction:A.jurisdiction}).catch(()=>[]);for(let E of T)f.set(E.domain.toLowerCase(),A.name)}u.r2AccountDomains=f}catch(R){u.log(`Workers: could not check R2 custom domains (${Si(R)}); relying on the DNS check.`),u.r2AccountDomains=null}return u.r2AccountDomains}async function Hh(u,f,R){try{let A=await u.fetch(`${xh}/zones/${f}/dns_records?name=${encodeURIComponent(R)}&per_page=100`,{method:"GET",headers:{Authorization:`Bearer ${u.apiToken}`}}),T=await A.json();if(!T?.success)throw Error(`HTTP ${A.status}`);return(T.result??[]).filter((E)=>E.name?.toLowerCase()===R).map((E)=>({type:E.type??"?",content:E.content??""}))}catch(A){return u.log(`Workers: could not read DNS records for ${R} (${Si(A)}); attaching anyway.`),[]}}function dp(u,f){let R=[],A=new Set,T=(P)=>{if(P===Fn)return f.warnings.push(`Workers: ${u.name}: binding name ${Fn} is reserved for ts-cloud, ignored.`),!1;if(A.has(P))return f.warnings.push(`Workers: ${u.name}: binding ${P} is declared twice; the first one wins.`),!1;return A.add(P),!0},E=new Map;for(let P of Object.values(f.r2Buckets?.buckets??{}))if(P.jurisdiction&&P.jurisdiction!=="default")E.set(P.name,P.jurisdiction);for(let[P,L]of Object.entries(u.bindings?.r2Buckets??{})){if(!T(P))continue;let z=E.get(L);R.push(z?{type:"r2_bucket",name:P,bucket_name:L,jurisdiction:z}:{type:"r2_bucket",name:P,bucket_name:L})}for(let[P,L]of Object.entries(u.bindings?.vars??{}))if(T(P))R.push({type:"plain_text",name:P,text:String(L)});return R}function Uh(u){let f=new Map;for(let R of Object.values(u?.buckets??{}))for(let A of R?.customDomains??[]){let T=mp(typeof A==="string"?A:A.domain);if(T)f.set(T,R.name)}return f}function Gh(u){return[...new Set((u??[]).map(mp).filter(Boolean))]}function mp(u){return(u??"").trim().replace(/\.$/,"").toLowerCase()}function jh(u){if(u<1024)return`${u} B`;if(u<1048576)return`${(u/1024).toFixed(1)} KB`;return`${(u/1024/1024).toFixed(1)} MB`}function Si(u){return u instanceof Error?u.message:String(u)}export{Rl as ABTestManager,ye as ACMClient,Dr as ACMDnsValidator,ad as ACME_DIRECTORIES,Oe as AI,du as API_IDEMPOTENCY_TTL_MS,au as API_TOKEN_DEFAULT_TTL_MS,cu as API_TOKEN_MAX_TTL_MS,us as API_VERSION,Ie as AUTHORIZATION_CAPABILITIES,nu as AUTH_ACTION_TOKEN_TTL_MS,iu as AUTH_MFA_CHALLENGE_TTL_MS,su as AUTH_OIDC_TRANSACTION_TTL_MS,it as AUTH_SESSION_ABSOLUTE_TTL_MS,ru as AUTH_SESSION_IDLE_TTL_MS,fy as AWSAPIError,n as AWSClient,h as AWSCloudFormationClient,S as AWSCloudFrontClient,El as AWSConfigManager,HI as AWS_PSEUDO_PARAMETERS,_e as AWS_REGIONS,Ug as AcmeClient,tn as AlertEvaluator,Ui as AlertStore,Do as AnomalyConfigStore,gl as ApiGateway,i as ApiServiceError,bc as ApplicationAutoScalingClient,dn as Arn,_ as AssetHasher,Y as Auth,os as AuthenticationStore,qi as AutomationApiService,as as AutomationIdentityStore,Pa as AwsAuroraDataAdapter,Oa as AwsAuroraTransport,Ya as AwsDatabaseBackupSource,Br as AwsDriver,ka as AwsElastiCacheDataAdapter,_a as AwsElastiCacheTransport,jf as AwsIamCapabilityScanner,nc as AwsInfrastructureBackupSource,Da as AwsRdsDataAdapter,xa as AwsRdsTransport,sh as AwsRegionalDriver,sc as AwsSecretsManagerConfigurationBackend,cm as AwsSpendTransport,oc as AwsSsmConfigurationBackend,Cs as BackupCoordinator,bl as BackupManager,Ja as BackupStore,bf as BatchProcessingManager,Un as BedrockClient,Mn as BedrockRuntimeClient,hu as BitbucketSourceAdapter,wl as BlueGreenManager,uf as BounceComplaintHandler,tf as BuildOptimizationManager,Mu as BunDockerRuntime,mg as BunDockerVolumeRuntime,pg as BunFilesystemArchiveRuntime,Ce as CDN,zo as CHAIN_HEADER,Gt as CLOUDFLARE_MANAGED_RULE_PREFIX,al as CLOUDFRONT_FAILOVER_STATUS_CODES,DC as COMMON_CROSS_ACCOUNT_ROLES,Fn as CONTENT_HASH_BINDING,Ke as CONTROL_PLANE_SCHEMA_VERSION,Qo as Cache,Zi as CanaryManager,Ym as CertificateManager,wA as CloudBlockVolumeDriver,ro as CloudDriverFactory,tt as CloudError,Tm as CloudFormationBuilder,h as CloudFormationClient,S as CloudFrontClient,vl as CloudTrailManager,we as CloudWatchLogsClient,ld as CloudflarePagesProvider,H as CloudflareProvider,Ly as CommandHistory,ee as Communication,Jr as ComposeApplicationService,tr as ComposeApplicationStore,Mt as ComprehendClient,a as Compute,dm as ComputeSpendTransport,Vo as ConfigurationError,cc as ConfigurationService,ic as ConfigurationStore,Ln as ConnectClient,Ba as ContainerDataAdapter,Bl as ContainerRegistryManager,rc as ControlPlaneBackupSource,ja as ControlPlaneCleanupDriver,xi as ControlPlaneStore,To as CounterTracker,Pt as CredentialError,Um as CrossRegionReferenceManager,ty as DASHBOARD_ENTRY,ry as DASHBOARD_PORT_BASE,ny as DASHBOARD_PORT_SPAN,ey as DASHBOARD_STATE_DIR,ra as DEFAULT_ATTACK_MODE_HOURS,Ss as DEFAULT_COMPATIBILITY_DATE,Jd as DEFAULT_DDOS_THRESHOLDS,pm as DEFAULT_FAILOVER_STATUS_CODES,Nd as DEFAULT_METER_MAPPINGS,Pd as DEFAULT_PRICE_BOOK,gn as DEFAULT_RECURSION_LIMITS,ao as DEFAULT_RPX_CERTS_DIR,te as DEFAULT_SERVICE_LIMITS,el as DEFAULT_STATE_DIR,Rg as DEFAULT_STATIC_ASSET_EXTENSIONS,JA as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,FA as DEFAULT_TELEMETRY_POLICY,jp as DEFAULT_THRESHOLDS,bA as DEPLOYMENT_QUEUE_KINDS,jo as DEPTH_HEADER,Zr as DETECTABLE_SIGNALS,xu as DIAGNOSTIC_PRESETS,If as DLQMonitoringManager,W as DNS,df as DNSSECManager,fs as DataServiceLifecycle,Ra as DataServiceStore,or as Database,Jm as DatabaseUserManager,q as DebugLogger,WA as DependencyGraph,Z as Deployment,my as DeploymentError,Cl as DisasterRecoveryManager,Kn as DnsProviderFactory,fr as DockerDataTransport,ba as DockerDiscoveryAdapter,Wr as DockerNamedVolumeDriver,tc as DockerVolumeBackupSource,c as DurableOperationQueue,yo as DurableQueueWorker,Ue as DynamoDBClient,Qr as EC2Client,He as ECRClient,dt as ECSClient,vr as EFSClient,Ac as ELBv2Client,DA as ENFORCEMENT_ACTIONS,Mi as ENFORCEMENT_DESCRIPTIONS,O as ENFORCEMENT_SEVERITY,Ip as ENVIRONMENT_LABEL,Nu as EcsRuntimeAdapter,ta as EdgeRateLimiter,ut as ElastiCacheClient,m as Email,ff as EmailAdvanced,gf as EmailAnalyticsManager,Vn as EmailClient,hf as EmailHandlers,mf as EmailTemplateManager,La as EncryptedDataSecretStore,hy as ErrorCodes,Cr as EventBridgeClient,rh as EventBridgeJobAdapter,ac as ExternalConfigurationBackend,Uo as FAILOVER_REPLICA_POLICY_SID,Sf as FIFOQueueManager,qh as FLY_MACHINES_API,em as FOCUS_VERSION,fl as FileCache,Ze as FileSystem,Za as FilesystemBackupSource,Ma as FleetService,$a as FleetStore,Ls as FlyApiError,hp as FlyClient,e as Fn,Au as GiteaSourceAdapter,mu as GithubSourceAdapter,fu as GitlabSourceAdapter,Qm as GlobalResourceManager,Ge as GoDaddyProvider,Tl as GuardDutyManager,It as HOST_SITES_DIR,Iy as HashCache,xf as HealthCheckManager,Je as HealthCheckRunner,$r as HetznerClient,Pe as HetznerDriver,Re as IAMClient,Nc as IPV6_EXCLUDED_HOST_LABELS,ef as ImageScanningManager,yg as InfrastructureGenerator,yd as InvalidOperationTransitionError,Rt as JobLoader,nh as JobProviderReconciler,Ta as JobService,wa as JobStore,br as KendraClient,Nf as LARAVEL_SERVERLESS_BUILD_STEPS,v as LambdaClient,sf as LambdaConcurrencyManager,cf as LambdaDLQManager,of as LambdaDestinationsManager,rf as LambdaLayersManager,Bu as LambdaRuntimeAdapter,af as LambdaVPCManager,nf as LambdaVersionsManager,Nn as LocalEncryptedConfigurationBackend,ec as LogicalDatabaseBackupSource,Pl as LogsManager,nS as MANAGED_NODE_VERSIONS,rd as MANAGEMENT_DASHBOARD_SITE,wm as MANAGEMENT_DASHBOARD_SITE_PREFIX,is as MAX_CONTROL_HOURS,Sd as MAX_CONTROL_PLANE_ERROR_BYTES,Qp as MAX_CONTROL_PLANE_JSON_BYTES,Co as METERS,RA as METER_KEYS,PA as MICRO_CENTS,zp as MIN_PROJECTION_CONFIDENCE,Bg as MTA_STS_PORT,qa as MaintenanceService,Va as MaintenanceStore,le as Messaging,zm as MetricsManager,Km as MigrationManager,_m as MockCloudFormation,$m as MockDynamoDB,Lm as MockS3,Ho as Monitoring,Vm as MultiAccountManager,Fm as MultiRegionManager,ky as MultiStepProgress,y as Network,Of as NetworkSecurityManager,Qi as NotificationRouter,hm as ORIGIN_CONNECTION_ATTEMPTS,Am as ORIGIN_CONNECTION_TIMEOUT,mm as ORIGIN_GROUP_ALLOWED_METHODS,FI as ORIGIN_GROUP_ID_SUFFIX,fm as ORIGIN_GROUP_SELECTION_CRITERIA,yc as OpenSearchClient,bt as OptimisticConcurrencyError,qm as OrganizationManager,Jg as PAGES_MAX_FILE_BYTES,pS as PHP_DEFAULT_EXCLUDES,iS as PHP_LAYER_EXTENSIONS,Sp as PROJECT_LABEL,pt as PROXIABLE_RECORD_TYPES,D as ParameterStore,Wm as PerformanceManager,de as Permissions,Sc as PersonalizeClient,et as Phone,Af as PhoneAdvanced,Em as PhoneHandlers,Ua as PlacementService,Fa as PlacementStore,Qn as PollyClient,he as PorkbunProvider,In as PreDeployScanner,Sl as PreviewEnvironmentManager,Kr as PreviewEnvironmentService,We as PreviewEnvironmentStore,Il as PreviewNotificationService,Py as ProgressBar,Dl as ProgressiveDeploymentManager,na as ProtectionControlStore,KA as Pseudo,J as Queue,Oi as QueueCancellationError,Cf as QueueManagementManager,DI as QueuePresets,Ao as QueueTimeoutError,_n as R2ApiError,kn as R2NotEnabledError,ci as R2Provider,rp as R2_NOT_ENABLED_ERROR_CODE,Kl as RATE_LIMIT_KEY_SEPARATOR,ne as RDSClient,My as RECOMMENDED_ACCOUNT_STRUCTURES,RC as RECOMMENDED_SCPS,Hf as RELEASE_QUEUE_KINDS,xy as REPL,_y as REPLCommandBuilder,Oy as REPLContext,bp as ROLE_LABEL,by as RateLimiter,PI as RealtimePresets,tm as RecordingSpendTransport,ts as RecursionGuard,Dt as Redirects,Hm as RegionPairManager,Ha as RegionService,Qa as RegionStore,Ye as Registry,Ft as RekognitionClient,kt as ReleaseService,ga as ReleaseStore,ih as RemoteBuildService,kl as ReplicaManager,_f as ResourceManagementManager,ae as RetryableOperationError,I as Route53Client,hc as Route53DomainsClient,ie as Route53Provider,lf as Route53ResolverManager,Ol as Route53RoutingManager,ve as RuntimeOperationService,Ea as RuntimeStreamRegistry,Xa as S3BackupDestinationAdapter,o as S3Client,V as S3Error,Iu as SECRET_PATTERNS,Yp as SENSITIVITY_THRESHOLDS,gt as SESClient,X as SMS,lt as SNSClient,am as SPEND_CYCLE_SECONDS,Vd as SPEND_GATE_SETTING,GA as SPEND_LEASE_SETTING,pe as SQSClient,ke as SSH_BOOTSTRAP_VERSION,mi as SSH_PREFLIGHT_SCRIPT,Be as SSMClient,um as STATE_DIR_ENV_VAR,to as STATIC_SITE_ZONE_SETTINGS,dl as STORAGE_FAILOVER_METADATA_KEY,Te as STSClient,Hn as SchedulerClient,ar as Search,bn as SecretFindingScanner,Wi as Secrets,Nl as SecretsManager,re as SecretsManagerClient,Xm as SecretsRotationManager,C as Security,lr as SecurityHubManager,Sn as SecurityPostureStore,Nt as SecurityScannerRunner,Zm as SecurityScanningManager,pf as SenderReputationManager,th as ServerCronJobAdapter,Na as ServerDataAdapter,bo as ServerPathVolumeDriver,xl as ServiceMeshManager,ul as Sftp,ko as SignalSource,yf as SmsAdvanced,Qt as SmsClient,vm as SmsHandlers,vc as SmsVoiceClient,pa as SourceConnectionStore,pr as SourceProviderError,qd as SpendCapError,en as SpendGate,sm as SpendLoopLease,_o as SpendNotificationRouter,om as SpendRunner,nr as SpendService,Li as SpendStore,Ny as Spinner,Fr as SshDriver,vn as SshFleetDriver,Gm as StackDependencyManager,QI as StacksIntegration,Bf as StaticSiteManager,xe as Storage,ql as StorageAdvancedManager,Gn as SupportClient,ur as SyntheticsManager,Fu as SystemFleetSshTransport,Mr as SystemSshTransport,Ca as SystemdDiscoveryAdapter,Ko as TRACE_HEADER,By as TaskList,vt as TelemetryStore,sl as TemplateBuilder,hl as TemplateCache,Ut as TextractClient,$n as TranscribeClient,Ir as TranslateClient,ch as TransportDisasterRecoveryDriver,ah as TransportPlatformMaintenanceDriver,hs as TransportRemoteBuildDriver,Sa as TrivyImageScanner,ua as TsCloudApiError,lu as TsCloudClient,HA as URGENT_SPEND_EVENTS,Kp as USER_VISIBLE_ACTIONS,Ga as UnavailableRegionalDriver,Ae as UnifiedDnsValidator,mo as UnsupportedSchemaVersionError,km as ValidationError,Er as VoiceClient,Io as VolumeService,er as VolumeStore,Zc as WORKER_MODULE_TYPE,ui as WorkersApiError,za as WorkersPermissionError,Cc as WorkersProvider,ZA as Workflow,jm as XRayManager,zy as abTestManager,uu as activateImmutableRelease,Wg as addDns01ChallengeRecord,wn as addSiteToCloudConfig,xt as ageSeconds,xd as aggregateDeltas,Mp as allocateSitePorts,Cm as amazonLinuxImageId,YA as amazonLinuxImageParameter,$I as analyzeStackDiff,Fi as anomalyOptionsForSignal,ia as applyControlsToDdos,Zl as applyControlsToRateLimits,Qs as applyDeclaredZoneSettings,li as applyHetznerVolumes,sn as applyMitigationFactor,rA as applyPlan,qs as applyZoneMigration,_l as artifactKey,Tt as assertOriginGroupMethods,cs as assertReleaseStrategy,MA as assertSpendAllows,aA as attachConflicts,cA as attachIsViable,oA as attachPreconditions,Tu as attachProvenanceToRelease,Ia as attachSbomToRelease,Eu as attachVulnerabilitySummary,Uf as authEncryptionKeyFile,x as authorizeOrganization,Zf as authorizeRuntimePath,nC as autocomplete,Qy as awsConfigManager,ug as backupCredentialStatus,Fy as backupManager,Db as batch,yE as batchProcessingManager,da as beginOidcAuthorization,qy as blueGreenManager,gE as bounceComplaintHandler,Ct as budgetWindow,pc as buildAndPushServerlessImage,bE as buildBunRuntimeLayerZip,mA as buildCertificatePackScript,uA as buildCertificateStateScript,fA as buildCertificateUnpackScript,pl as buildCloudFormationTemplate,Jc as buildCloudInitFirstBoot,Ed as buildComposeLogsCommand,wI as buildComposeRuntimeCommand,RI as buildComposeScaleCommand,vd as buildComposeShellCommand,Zn as buildComputeStorageInstallScript,xr as buildComputeStorageSiteScript,_p as buildDrainSourceScript,zh as buildDrainedSiteScanScript,ll as buildFailoverReplicaPolicyStatement,Ar as buildFunctionEnv,Op as buildHealthGateScript,ti as buildHostCleanupDeployScript,Ys as buildHostCleanupInstallScript,ei as buildHostCleanupScript,Ni as buildHostSitePortsScript,zi as buildMailEnv,io as buildManagementDashboardArtifact,qS as buildMediaCdnPlan,Ng as buildMtaStsPolicy,Nh as buildMtaStsServer,IE as buildNodeRuntimeLayerZip,nE as buildOptimizationManager,cl as buildOriginGroup,cn as buildOriginGroups,Rc as buildOriginGuardRule,Rp as buildPauseWorkersScript,TE as buildPhpRuntimeLayerZip,bm as buildReplicationConfiguration,Im as buildReplicationRole,Np as buildRestoreScript,B as buildRpxConfig,Ne as buildRpxFragmentRefreshScript,iA as buildSetHostnameScript,ni as buildSiteDeployScript,kp as buildSnapshotScript,Lp as buildSourceStateScript,oi as buildSshArgs,gi as buildSshBootstrapScript,wc as buildStaticSiteCacheRules,ii as buildStaticSiteDeployScript,Bp as buildTargetStateScript,lp as buildUploadForm,Dp as buildWorkersStateScript,Yc as bundleWorker,Ru as bytes,op as cacheRuleParameters,jy as canaryManager,Tn as canonicalJson,Bt as capabilities,hr as capacity,$b as categorizeChanges,eE as certificateManager,pA as certificatesMatch,yb as checkIAMPermissions,Rf as checkInvocation,Ib as checkServiceQuotas,Cy as chunk,dR as cleanupDns01Challenge,IS as clearSigningKeyCache,fa as cloneSourceBinding,Ey as cloudConfigSchema,ip as cloudDrivers,Hy as cloudTrailManager,dd as collectAssets,Yo as collectPhpAppEntries,Dg as collectServerDnsDomains,Hp as completeComposeVolumeDeletion,la as completeOidcAuthorization,ob as composePresets,ho as composeProjectName,$l as composeServerlessAppTemplate,qA as compositeSpendTransport,$t as compressBackup,RS as config,Tc as configOrigins,Lu as connectionGuidance,Zy as containerRegistryManager,SA as controlPlaneDatabaseFile,hd as controlPlaneMigrations,KI as createApiBackendPreset,ya as createApiV1Handler,LS as createAsgBuildDriver,gg as createBackupQueueHandlers,gS as createCliHandler,F as createCloudDriver,Yu as createCloudFrontPolicy,mb as createCredentialProvider,ib as createDashboardSite,ZI as createDataPipelinePreset,$u as createDataServiceQueueHandlers,Td as createDeploymentQueueHandlers,N as createDnsProvider,_S as createEcsBuildDriver,jd as createEnforcementHandlers,Nm as createError,ml as createExistingStaticFullStackPreset,Uu as createFleetQueueHandlers,zI as createFullStackAppPreset,Ks as createGoDaddyValidator,vE as createHandlers,lS as createHttpHandler,JI as createJamstackPreset,_u as createJobQueueHandlers,rb as createLaravelPreset,eb as createMLApiPreset,zu as createMaintenanceQueueHandlers,GS as createMediaAccessToken,XI as createMicroservicesPreset,qb as createMockAWS,VI as createNodeJsServerPreset,qI as createNodeJsServerlessPreset,xs as createObjectStorageClient,zs as createPorkbunValidator,ab as createPreset,Zo as createPresignedUrl,fS as createPresignedUrlAsync,uS as createQueueHandler,YI as createRealtimeAppPreset,Hu as createRegionQueueHandlers,vu as createReleaseProvenance,pu as createReleaseQueueHandlers,xS as createRemoteBuildQueueHandlers,Ws as createRoute53Validator,Yf as createRuntimeAdapters,py as createS3Client,OS as createServerBuildDriver,nb as createServerlessLaravelPreset,jI as createServerlessNodePreset,wg as createSmsInfrastructure,ot as createSourceAdapter,GI as createStaticSitePreset,tb as createTraditionalWebAppPreset,wd as createVolumeQueueHandlers,WI as createWordPressPreset,rt as createZip,uC as crossRegionReferenceManager,Bn as dashboardActions,no as dashboardCredentialsFile,En as dataServiceCapabilities,YC as databaseUserManager,tu as decodeBase32,Fe as decompressBackup,yh as decryptBackup,sa as defaultConfig,Om as defaultLocalConfig,Jl as defaultRateLimitRules,Rr as delegateZone,Fs as delegateZoneFromConfig,ag as deleteFailoverReplicaBuckets,uc as deleteStaticSite,id as deployAllComputeSites,Ka as deployServerlessApp,cg as deploySite,so as deploySiteRelease,ws as deployStaticSite,gc as deployStaticSiteFull,xn as deployStaticSiteWithExternalDns,On as deployStaticSiteWithExternalDnsFull,wS as deployToFly,il as deploymentCoexistenceError,iy as deriveManagementDashboardPort,Us as describeDelegation,Yl as describePosture,Hs as describeZoneSettings,eh as desiredJobProviderState,Xp as detectAnomalies,gm as detectDeploymentTargets,Dc as detectDnsProvider,Qd as detectLatestAnomaly,hb as detectMisconfigurations,jl as detectServiceRegion,bd as diffCompose,Ob as diffTemplates,ma as discoverGitRefs,ca as discoverOidcProvider,Du as discoverRuntimeInventory,AE as dlqMonitoringManager,Pc as dnsProviders,lE as dnssecManager,Wf as dockerWorkloads,As as documentDigest,jc as domainStatus,Uy as drManager,qe as driverStatePath,Pu as ecsWorkloads,Zt as effectiveCapabilities,pE as emailAnalyticsManager,fE as emailTemplateManager,ss as encodeBase32,Ah as encryptBackup,wu as ensureDefaultSecurityPolicies,ig as ensureFailoverReplicaBuckets,bi as ensureFirewall,vi as ensureManagementDashboard,Ci as ensureServer,Ii as ensureSshKey,oe as escapeSecLang,_d as evaluateBudget,hi as evaluatePreflight,Oo as evaluateTelemetryAlertRules,Ou as eventBridgeScheduleInput,dS as eventToRequest,_A as ewma,Id as exportCompose,Gs as exportRoute53Zone,Dm as extendPreset,hE as fifoQueueManager,Rb as findChangedFiles,Vp as findMapping,Gp as findPriceEntry,$S as flyDeployOptions,Qc as flyIpType,Ap as flyMachineConfig,BC as formatAccountStructure,dA as formatAttachPlan,Wb as formatBytes,rn as formatCents,MI as formatDiff,Wh as formatDrainedSiteRefusal,Jb as formatDuration,sC as formatFlagSuggestions,cC as formatHistory,dC as formatHistoryStats,Zh as formatInventory,Yb as formatKeyValue,Xb as formatList,tA as formatPlan,yi as formatPreflightFindings,Kb as formatProgressBar,$y as formatRegion,EC as formatRegionList,qf as formatScanResults,Zb as formatSuggestion,jb as formatTable,Yr as formatTimeToExhaustion,zb as formatTree,dy as fromEC2Metadata,ly as fromECSMetadata,ay as fromEnvironment,cy as fromSharedCredentials,uy as fromWebIdentity,Ul as functionFingerprint,uo as gatewayHostnames,Fl as generateAppImageDockerfile,jC as generateApprovalConfig,Ef as generateBootstrap,wy as generateCleanupWorkflow,Ry as generateCostReportWorkflow,kC as generateCrossAccountRoleCF,bu as generateCycloneDxSbom,GC as generateDeploymentConfig,MC as generateDeploymentPipeline,xC as generateDeploymentWorkflow,lc as generateExternalDnsStaticSiteTemplate,lR as generateHttpsServerCode,Cu as generateImageSbom,cR as generateLetsEncryptUserData,t as generateLogicalId,HC as generateManualPipeline,$C as generateMatrixWorkflow,VC as generateMultiEnvConfig,FC as generateMultiEnvPipeline,OC as generateMultiEnvWorkflow,_C as generatePRPreviewWorkflow,zC as generateParallelConfig,kf as generatePhpFpmConfig,vf as generatePhpLayerDockerfile,UC as generatePreviewPipeline,Ty as generatePreviewWorkflow,r as generateResourceName,qC as generateScheduledConfig,QC as generateScheduledPipeline,LC as generateScheduledWorkflow,Ts as generateStaticSiteTemplate,M as generateUbuntuAppCloudInit,Pm as getAccountId,fC as getAllRegions,IC as getClosestRegion,oC as getCommandUsage,IA as getComposeTemplate,$f as getConfig,tC as getContextualHelp,Xi as getCredentials,Mb as getDeploymentStrategy,Fb as getDiffStats,_b as getDiffSummary,Ay as getErrorDetails,yl as getLocalConfig,Gb as getLocalCredentials,Hb as getLocalEndpoint,Vb as getLocalEnvVars,bb as getQuotaUsageSummary,PC as getRecommendedStructure,Yi as getRegion,vC as getRegionStats,AC as getRegionsByCompliance,hC as getRegionsByLocation,yC as getRegionsByPricingTier,yy as getRequiredPermissions,bS as getSigningKeyCacheSize,Tg as getSmsInfrastructureStatus,kI as getTimestamp,ea as globMatches,oo as globToRegex,gC as globalResourceManager,$i as governingLimitCents,sg as grantFailoverReplicaAccess,Gy as guardDutyManager,Lo as handleSpendRequest,lo as hasAutoWwwVariant,cr as hasManagementDashboardSite,fd as hasProxyUpstream,Eb as hashBuffer,vb as hashDirectory,Bm as hashFile,Tb as hashManifest,xm as hashString,RE as healthCheckManager,Wn as hostAcceptsIpv6,Ht as hostCondition,oa as hotp,Xr as hourBucket,OA as hourBucketsBetween,rE as imageScanningManager,Is as infraEnvFromOutputs,Hl as inspectInvocation,aS as installRecursionFetch,Ds as invalidateCache,wf as invocationContext,XA as isArmInstanceType,eC as isLikelyTypo,Xn as isLocalDatabase,Qb as isLocalDevelopment,dr as isManagementDashboardSiteName,Tr as isNameserverRegistrar,CS as isNodeCryptoAvailable,Ud as isOperationAllowed,xo as isQuietHours,Fo as isS3RestEndpoint,wi as isSafePattern,rl as isStateDirConfigured,nl as isStatePath,nn as isValidCidr,SC as isValidRegion,_i as isValidTimeZone,ES as isWebCryptoAvailable,wr as isZoneHost,Cn as jobProviderCapability,Bs as keyMatchesFilters,oE as lambdaConcurrencyManager,dE as lambdaDLQManager,aE as lambdaDestinationsManager,iE as lambdaLayersManager,cE as lambdaVPCManager,sE as lambdaVersionsManager,ku as lambdaWorkloads,Gl as laravelServerlessEnvDefaults,zr as listComposeTemplates,ls as listSourceReferences,eu as loadCloudConfig,ir as loadTelemetryPolicy,Wy as logsManager,Hd as lookbackHoursForSignal,zA as mailEnabled,Xe as mailFirewallPorts,an as mailWebmailSites,oh as maintenanceWindowOpen,Lf as makeAWSRequest,AS as makeAWSRequestAsync,hS as makeAWSRequestOnce,sp as managedRuleInSync,Rm as managementDashboardSiteName,Gu as manifestDigest,fn as matchTotpCounter,KS as mediaObjectHeaders,Ro as median,Wp as medianAbsoluteDeviation,Ld as mergeDecisions,ln as mergeInfrastructure,BA as mergePriceBooks,Bd as meterTelemetry,WC as metricsManager,Ig as migrateObjectStorage,JC as migrationManager,TC as multiAccountManager,lC as multiRegionManager,pR as needsRenewal,DE as networkSecurityManager,Ot as nextScheduleRuns,De as normalizePublicIpv6,Le as normalizeRuntimeStatus,at as normalizeScheduleExpression,Gf as normalizeSourceEvent,Ve as normalizeSshPublicKey,rm as normalizeTelemetryPolicy,ki as occupiedHostPorts,Aa as openApiDocument,No as optionsForSignal,wC as organizationManager,Vl as packagePhpApp,un as packageServerlessApp,ud as pagesAssetHash,Xg as pagesDnsRecord,Al as parallel,Pb as parallelMap,kb as parallelWithRetry,gA as parseCertificateState,Ql as parseChain,jr as parseCompose,vI as parseComposeCatalog,Kf as parseDockerInspect,fg as parseDotenv,Kh as parseDrainedSites,Bi as parseHostSiteFragments,SS as parseJSONResponse,fi as parsePreflightFacts,$p as parseSourceDrained,Jf as parseSystemdRecords,xp as parseTargetReady,md as parseUpstreamPort,Pp as parseWorkersPaused,yS as parseXMLResponse,Gi as pathTemplate,gd as pendingSteps,wo as percentOfLimit,XC as performanceManager,Ml as phpLayerBuildStage,sS as phpLayerPackages,pn as phpRuntimeLayerAssets,TI as planComposeTemplateUpgrade,$d as planEnforcement,di as planHetznerVolumes,Tp as planIsDestructive,lm as planMitigation,nA as planServerRename,hA as planSiteMove,Vs as planZoneMigration,qt as policyTag,Ai as preflightFailed,vy as previewManager,Dy as previewNotifications,_t as previewSchedule,xA as previousBudgetWindow,Eo as priceUsage,kA as priceUsageLines,Xh as probeHostRoutes,Uc as probeOriginTls,xb as processInChunks,yu as processSourceWebhook,ps as productionChangeReview,Ky as progressiveDeploymentManager,Od as projectSpend,Wo as propagationHeaders,mc as providerEndpoint,Vu as publicKeyFingerprint,jn as qualifyName,SE as queueManagementManager,wb as quickHash,np as r2Endpoint,ph as r2S3Credentials,Wl as rateLimitHeaders,ns as rateLimitKey,je as readDriverState,Yh as reconcile,kg as reconcileAddressRecords,Kg as reconcileCloudflareCdn,Fh as reconcileCloudflareWorkers,Ms as reconcileDeclaredRecords,BS as reconcileJobObservation,fh as reconcileR2Buckets,yn as reconcileSourceWebhook,gs as recordDashboardHostPosture,PS as recordPreDeploySecretScan,kS as recordSkippedSecretScan,Jo as recursionBlockedResponse,$e as redactRuntimeConfig,Wd as redactTelemetryText,Hi as redactTelemetryValue,Dn as redeployServerlessApp,pC as regionPairManager,An as releaseStrategyCapabilities,Qf as releaseTrafficPlan,Ti as reloadRpxGateway,Ns as remapKey,Pg as removeAddressRecords,Vg as removeDns01ChallengeRecord,Rn as removeSiteFromCloudConfig,Su as removeSourceWebhook,kc as removeStaleServerAddressRecords,Cd as renderComposeTemplate,ji as renderDdosInstallScript,Zd as renderNftablesRuleset,ms as renderServerCron,Yd as renderSysctlFile,od as renderWafConfig,Ri as renderWafInstallScript,sd as renewRpxCertificates,Xy as replicaManager,jA as requestHash,Lb as requiresReplacement,CE as resetRecursionRuntime,EE as resolveApp,g as resolveAppDatabase,sA as resolveAttachTarget,st as resolveAuthEncryptionKey,be as resolveCloudProvider,Zg as resolveCloudflareCdnPlan,Yn as resolveComputeVolumes,Go as resolveCredentials,vs as resolveDashboardAction,nd as resolveDashboardAuth,sy as resolveDashboardDomain,oy as resolveDashboardDomains,$s as resolveDeclaredRecords,LI as resolveDeployBucketName,K as resolveDeploymentMode,ri as resolveExecStart,Mo as resolveFailoverStatusCodes,Fc as resolveHetznerApiToken,_r as resolveHostCleanupConfig,w as resolveMailProxy,b as resolveMailService,sb as resolveManagementDashboardSite,Ji as resolveManagementDashboardSites,fc as resolveObjectStorage,ce as resolveOriginConnection,eA as resolvePlan,p as resolveProjectStackName,qr as resolveProxyUpstreams,Ll as resolveQueueNames,CA as resolveQueuedDeploymentCommand,gr as resolveQueues,oS as resolveRecursionConfig,gy as resolveRegion,ge as resolveRuntimeInventory,sr as resolveServerlessAppStackName,ol as resolveServerlessArtifactBucketName,Ki as resolveServerlessAssetBucketName,es as resolveServerlessRuntime,OI as resolveSiteBucketName,po as resolveSiteDeployTarget,d as resolveSiteKind,xI as resolveSiteResourceName,BI as resolveSiteStackName,pi as resolveSshSettings,l as resolveStatePath,_I as resolveStorageBucketName,ym as resolveStorageFailover,Jt as resolveUiSource,cd as resolveZoneApex,PE as resourceManagementManager,Pf as responseToResult,Jp as robustZScore,Yt as roleCapabilities,gu as rollbackImmutableRelease,Pn as rollbackServerlessApp,NA as roundCents,uE as route53ResolverManager,tS as route53RoutingManager,Zp as routeMatches,Cp as routesFromFragments,rs as ruleMatches,rS as runBuildHooks,Md as runEnforcement,Xo as runPhpBuildHooks,ct as runRemoteCommand,Ee as runtimeId,Qe as s3OriginBucket,Sm as s3RegionalDomain,Zs as sameCorsRules,Js as sameLifecycleRules,zn as sameNameservers,Es as sanitizeCloudConfig,s as sanitizeControlPlaneValue,NI as sanitizeName,ou as sanitizeOidcReturnPath,zd as saveTelemetryPolicy,Vf as scanForSecrets,Ad as scopeContains,Et as scopeKey,_c as scpUpload,rC as searchCommands,fo as searchControlPlane,Yy as secretsManager,ZC as secretsRotationManager,NS as secureContainerRelease,Vy as securityHubManager,tE as securityScanningManager,ue as securityScope,og as seedFailoverReplicas,hn as sendAuthenticationEmail,mE as senderReputationManager,Nb as sequence,hg as serializeDotenv,Ei as serverPublicIpv4,eS as serviceMeshManager,eg as setAttachToInCloudConfig,yr as setMaintenance,ys as setSitePropertyInCloudConfig,tl as setStateDir,uR as setupDns01Challenge,Ec as setupSmsInfrastructure,qo as sha256,cS as sharedRecursionGuard,Tf as sharedRuntimeLoop,Up as shipsARelease,US as signCloudFrontCookies,HS as signCloudFrontUrl,k as signRequest,zl as signRequestAsync,Po as signalDefinition,U as siteInstallBase,Pi as siteMoveArchivePath,lA as siteMoveCertArchivePath,pd as siteUnitGlob,im as spendNotificationText,$o as spendOpenApiPaths,Lr as sshExec,Se as sshExecOrThrow,mC as stackDependencyManager,dc as startLocalDashboardServer,VA as startSpendLoop,on as stateDir,Q as statePath,wE as staticSiteManager,mS as storageAdvancedManager,UI as storageFailoverReplicasFromTemplate,LA as streamFocusJsonl,Fd as strongestActiveAction,Mm as suggestCommand,iC as suggestFlags,Sb as suggestIAMPolicy,Cb as suggestQuotaIncrease,CC as suggestRegionPairs,bC as suggestRegions,ds as syncSourceRepositories,Rd as synchronizeComposeVolumes,Ag as synchronizeConfiguredConfiguration,va as synchronizeConfiguredJobs,Jy as syntheticsManager,Xd as sysctlHardening,Xf as systemdWorkloads,QA as telemetryBucketLabel,Vi as telemetryCursor,Kd as telemetryEstimatedMonthlyCost,UA as telemetryPercentile,nm as telemetryPolicyKey,Sy as templateCache,Ep as tenantsOf,ha as testSourceConnection,Dd as tieredMicroCents,ap as toApiLifecycleRule,Hc as toCloudflareZoneSettings,Bo as toFocusJsonl,Gd as toFocusRecords,Jh as toInventoryServer,Mf as totp,aa as totpUri,vp as unaccountedSites,zf as unsupportedCapabilities,EA as unsupportedVolumeCapabilities,ju as updateCompatibility,Ku as updateSiteInCloudConfig,Rs as uploadStaticFiles,qp as usageDeltaKey,rr as utcInstantOfLocal,NC as validateAccountStructure,Ub as validateAgainstSchema,TA as validateAttachment,hh as validateBackupDestination,aC as validateCommand,fb as validateConfiguration,Ab as validateCredentials,Fp as validateDeploymentConfig,vA as validateMountPath,wt as validateOriginGroups,Og as validateResourceLimits,wp as validateServerName,Cg as validateTemplate,Eg as validateTemplateSize,Bc as verifyAddressRecord,DS as verifyArtifactSignature,jS as verifyMediaAccessToken,Ff as verifyTotp,qu as verifyUpdateSignature,js as verifyZoneParity,So as volumeCapabilities,pp as wafEventTelemetry,Lc as waitForCloudInit,ai as waitForSsh,mr as webhookEndpoint,gb as withCDN,ub as withCache,up as withContentHash,lb as withDatabase,Df as withInvocation,cb as withMonitoring,pb as withQueue,db as withSecurity,Bb as withTimeout,dp as workerBindings,bs as workerContentHash,$c as workerInSync,se as wrapCloudInitUserData,ft as writeDriverState,KC as xrayManager,Qu as zeroCapacity,$A as zeroFill,kd as zoneOffsetMs,vo as zonedParts};