@stacksjs/ts-cloud 0.16.66 → 0.16.68

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 (190) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/{chunk-8bgfn8ek.js → chunk-17ewx21n.js} +11 -11
  3. package/dist/bin/chunk-19dhvnjh.js +1 -0
  4. package/dist/bin/{chunk-ya1413jw.js → chunk-1cb0r1j3.js} +2 -2
  5. package/dist/bin/chunk-1tk64amh.js +1 -0
  6. package/dist/bin/{chunk-tcn6qcc4.js → chunk-2247xk4n.js} +1 -1
  7. package/dist/bin/chunk-37xeqae4.js +1 -0
  8. package/dist/bin/{chunk-zesb85ra.js → chunk-43a60zkj.js} +1 -1
  9. package/dist/bin/chunk-4vz5erjz.js +1 -0
  10. package/dist/bin/{chunk-2avtspqd.js → chunk-55j0x82p.js} +5 -5
  11. package/dist/bin/{chunk-zs0q8sh5.js → chunk-5fde4d44.js} +1 -1
  12. package/dist/bin/{chunk-tw6z2mvh.js → chunk-5gf0je0v.js} +14 -14
  13. package/dist/bin/{chunk-0ejp168p.js → chunk-5t1ky9re.js} +1 -1
  14. package/dist/bin/chunk-6cyr6gcg.js +1 -0
  15. package/dist/bin/chunk-6rwewb7j.js +1 -0
  16. package/dist/bin/{chunk-d38cyam8.js → chunk-6tqzgm9z.js} +5 -5
  17. package/dist/bin/chunk-7d83f6sn.js +1 -0
  18. package/dist/bin/chunk-7v68hpgc.js +2 -0
  19. package/dist/bin/{chunk-nn8k84cd.js → chunk-7y56qyrj.js} +1 -1
  20. package/dist/bin/{chunk-e51cd46z.js → chunk-8escxm7h.js} +1 -1
  21. package/dist/bin/{chunk-6r04kx46.js → chunk-abk97qeq.js} +2 -2
  22. package/dist/bin/{chunk-qpvydcfm.js → chunk-b0r8a5h5.js} +5 -5
  23. package/dist/bin/chunk-bkvxzenb.js +1 -0
  24. package/dist/bin/{chunk-v6jm8dsa.js → chunk-d28q9ath.js} +1 -1
  25. package/dist/bin/chunk-dmm1p4bs.js +1 -0
  26. package/dist/bin/chunk-dycx66c7.js +1 -0
  27. package/dist/bin/{chunk-aekwpste.js → chunk-e4c7ba0g.js} +1 -1
  28. package/dist/bin/chunk-fjx816tt.js +1 -0
  29. package/dist/bin/{chunk-nbqja2ja.js → chunk-fx9zesgx.js} +113 -113
  30. package/dist/bin/{chunk-9pj5r0x0.js → chunk-gga18c4g.js} +1 -1
  31. package/dist/bin/chunk-gmy8p7nr.js +1 -0
  32. package/dist/bin/chunk-h5ccvped.js +1 -0
  33. package/dist/bin/chunk-h9h9dn0r.js +1 -0
  34. package/dist/bin/chunk-ht6s2cwm.js +1 -0
  35. package/dist/bin/{chunk-vbq4ten8.js → chunk-jrxb5sg4.js} +3 -3
  36. package/dist/bin/{chunk-cf2eyje1.js → chunk-krt80e8w.js} +7 -7
  37. package/dist/bin/{chunk-sbjzewvk.js → chunk-m60wwxz1.js} +6 -6
  38. package/dist/bin/{chunk-w4axqmyc.js → chunk-m92m9tx3.js} +84 -84
  39. package/dist/bin/{chunk-d0q93ecd.js → chunk-mjbd4pbz.js} +5 -5
  40. package/dist/bin/chunk-ncr1dwdt.js +1 -0
  41. package/dist/bin/{chunk-tpttr74v.js → chunk-nxsx69p4.js} +4 -4
  42. package/dist/bin/chunk-nzhpva7z.js +1 -0
  43. package/dist/bin/chunk-p40tvp17.js +1 -0
  44. package/dist/bin/{chunk-n667tnf3.js → chunk-pgbtdsj2.js} +3 -3
  45. package/dist/bin/{chunk-5ad4b744.js → chunk-pr96tp0s.js} +2 -2
  46. package/dist/bin/chunk-qe8zh9kn.js +1 -0
  47. package/dist/bin/{chunk-v5x06h8w.js → chunk-qjxd8f5m.js} +5 -5
  48. package/dist/bin/{chunk-favx96qj.js → chunk-qka0e661.js} +5 -5
  49. package/dist/bin/{chunk-pe18g092.js → chunk-rgnmxfvp.js} +3 -3
  50. package/dist/bin/chunk-sn1zde06.js +1 -0
  51. package/dist/bin/{chunk-71b4t3d8.js → chunk-sv7n9ape.js} +2 -2
  52. package/dist/bin/chunk-t6zpvaqr.js +1 -0
  53. package/dist/bin/{chunk-90ds3vw7.js → chunk-tdv5rwjv.js} +1 -1
  54. package/dist/bin/chunk-v4ncs6q2.js +1 -0
  55. package/dist/bin/{chunk-v3j9wgmn.js → chunk-v5js5pz6.js} +186 -186
  56. package/dist/bin/chunk-vrn0akcn.js +1 -0
  57. package/dist/bin/{chunk-mver6psb.js → chunk-w2eezm9z.js} +2 -2
  58. package/dist/bin/{chunk-6da5c33e.js → chunk-wjn2bpdb.js} +2 -2
  59. package/dist/bin/chunk-x00efaxm.js +1 -0
  60. package/dist/bin/{chunk-38qy0dj2.js → chunk-x40sd2m9.js} +3 -3
  61. package/dist/bin/chunk-zred4827.js +1 -0
  62. package/dist/bin/{chunk-tg3vzzc4.js → chunk-zs1cpqhv.js} +2 -2
  63. package/dist/bin/{chunk-kmxkwznm.js → chunk-zz9nj5kn.js} +5 -5
  64. package/dist/bin/cli.js +101 -101
  65. package/dist/bin/dashboard-server.js +1 -1
  66. package/dist/{chunk-y9589qef.js → chunk-040rbk7k.js} +35 -35
  67. package/dist/{chunk-f739f6d2.js → chunk-192rthtb.js} +70 -70
  68. package/dist/{chunk-9w5ncn9s.js → chunk-1wc2zfct.js} +3 -3
  69. package/dist/{chunk-axcxfz8p.js → chunk-1yj07hbw.js} +2 -2
  70. package/dist/{chunk-0kemzwpg.js → chunk-41fwhvp7.js} +1 -1
  71. package/dist/chunk-426k7fgf.js +1 -0
  72. package/dist/chunk-4b0ynr9y.js +1 -0
  73. package/dist/{chunk-a92gvctb.js → chunk-a07kew2q.js} +6 -6
  74. package/dist/chunk-emkp3dsp.js +1 -0
  75. package/dist/{chunk-pymc2aad.js → chunk-h360gwrf.js} +2 -2
  76. package/dist/{chunk-7mpbjr6c.js → chunk-h5yx54ks.js} +3 -3
  77. package/dist/{chunk-q4408fwg.js → chunk-hvttzk9q.js} +2 -2
  78. package/dist/{chunk-q8vvwmka.js → chunk-je8tky8z.js} +1 -1
  79. package/dist/{chunk-03eny26f.js → chunk-kbr9nc8y.js} +2 -2
  80. package/dist/{chunk-3ca6cb1s.js → chunk-p21vbrgk.js} +1 -1
  81. package/dist/chunk-pcagajw1.js +1 -0
  82. package/dist/{chunk-83fy36fn.js → chunk-qb25wesa.js} +2 -2
  83. package/dist/{chunk-hk1frmnn.js → chunk-qrpy0h2n.js} +1 -1
  84. package/dist/{chunk-xd67tr7p.js → chunk-s4wz0csj.js} +1 -1
  85. package/dist/{chunk-157bgr0x.js → chunk-spr6akra.js} +90 -90
  86. package/dist/chunk-sybwn2y6.js +1 -0
  87. package/dist/{chunk-r49ynkag.js → chunk-t8fbwcdk.js} +1 -1
  88. package/dist/{chunk-qgtydqpj.js → chunk-tb8azghz.js} +23 -23
  89. package/dist/{chunk-pah2r8a0.js → chunk-tq7nsdnd.js} +4 -4
  90. package/dist/{chunk-0860mm00.js → chunk-v0s8vpa3.js} +1 -1
  91. package/dist/{chunk-tngsyawj.js → chunk-xyem7g21.js} +1 -1
  92. package/dist/{chunk-zgfzc46r.js → chunk-yh9tmx00.js} +3 -3
  93. package/dist/{chunk-1t3rjvf9.js → chunk-z585dfjz.js} +12 -12
  94. package/dist/deploy/index.js +1 -1
  95. package/dist/dns/index.js +1 -1
  96. package/dist/drivers/index.js +1 -1
  97. package/dist/drivers/shared/releases.d.ts +12 -0
  98. package/dist/index.js +8 -8
  99. package/dist/mail/index.js +2 -2
  100. package/dist/object-storage/index.d.ts +6 -4
  101. package/dist/object-storage/migrate.d.ts +3 -1
  102. package/dist/operations/index.js +1 -1
  103. package/dist/protection/index.js +1 -1
  104. package/dist/spend/index.js +1 -1
  105. package/dist/ui/404.html +1 -1
  106. package/dist/ui/accept-invitation.html +1 -1
  107. package/dist/ui/access-denied.html +1 -1
  108. package/dist/ui/account/automation.html +5 -5
  109. package/dist/ui/account/security.html +2 -2
  110. package/dist/ui/applications/compose.html +6 -6
  111. package/dist/ui/applications/new.html +2 -2
  112. package/dist/ui/data/backups.html +6 -6
  113. package/dist/ui/data/services.html +6 -6
  114. package/dist/ui/data/volumes.html +6 -6
  115. package/dist/ui/index.html +6 -6
  116. package/dist/ui/infrastructure/topology.html +6 -6
  117. package/dist/ui/integrations.html +1 -1
  118. package/dist/ui/operations/alerts.html +6 -6
  119. package/dist/ui/operations/configuration.html +6 -6
  120. package/dist/ui/operations/jobs.html +6 -6
  121. package/dist/ui/operations/maintenance.html +6 -6
  122. package/dist/ui/operations/observability.html +6 -6
  123. package/dist/ui/operations/previews.html +6 -6
  124. package/dist/ui/operations/queue.html +6 -6
  125. package/dist/ui/operations/regions.html +6 -6
  126. package/dist/ui/operations/releases.html +6 -6
  127. package/dist/ui/operations/spend.html +6 -6
  128. package/dist/ui/operations/workloads.html +6 -6
  129. package/dist/ui/security.html +1 -1
  130. package/dist/ui/server/actions.html +6 -6
  131. package/dist/ui/server/activity.html +1 -1
  132. package/dist/ui/server/capacity.html +5 -5
  133. package/dist/ui/server/database.html +6 -6
  134. package/dist/ui/server/deployments.html +5 -5
  135. package/dist/ui/server/diagnostics.html +2 -2
  136. package/dist/ui/server/firewall.html +6 -6
  137. package/dist/ui/server/fleet.html +6 -6
  138. package/dist/ui/server/logs.html +6 -6
  139. package/dist/ui/server/metrics.html +5 -5
  140. package/dist/ui/server/security.html +2 -2
  141. package/dist/ui/server/services.html +1 -1
  142. package/dist/ui/server/sites.html +5 -5
  143. package/dist/ui/server/ssh-keys.html +5 -5
  144. package/dist/ui/server/team.html +5 -5
  145. package/dist/ui/server/terminal.html +1 -1
  146. package/dist/ui/serverless/alarms.html +5 -5
  147. package/dist/ui/serverless/assets.html +1 -1
  148. package/dist/ui/serverless/cost.html +2 -2
  149. package/dist/ui/serverless/data.html +6 -6
  150. package/dist/ui/serverless/deployments.html +2 -2
  151. package/dist/ui/serverless/firewall.html +1 -1
  152. package/dist/ui/serverless/functions.html +6 -6
  153. package/dist/ui/serverless/logs.html +6 -6
  154. package/dist/ui/serverless/metrics.html +2 -2
  155. package/dist/ui/serverless/queues.html +6 -6
  156. package/dist/ui/serverless/secrets.html +6 -6
  157. package/dist/ui/serverless/traces.html +6 -6
  158. package/dist/ui/serverless.html +5 -5
  159. package/package.json +3 -3
  160. package/dist/bin/chunk-0v5tsfx5.js +0 -1
  161. package/dist/bin/chunk-3954zb9r.js +0 -1
  162. package/dist/bin/chunk-3x52axr2.js +0 -1
  163. package/dist/bin/chunk-67mww6gq.js +0 -1
  164. package/dist/bin/chunk-7khzyn7k.js +0 -1
  165. package/dist/bin/chunk-97494wnx.js +0 -1
  166. package/dist/bin/chunk-agmznzms.js +0 -1
  167. package/dist/bin/chunk-ambf5hpg.js +0 -1
  168. package/dist/bin/chunk-b39h9as6.js +0 -1
  169. package/dist/bin/chunk-dfgzav9j.js +0 -1
  170. package/dist/bin/chunk-g0w0jec3.js +0 -1
  171. package/dist/bin/chunk-g514nb80.js +0 -1
  172. package/dist/bin/chunk-hknz7fsr.js +0 -1
  173. package/dist/bin/chunk-j9yq3b4d.js +0 -2
  174. package/dist/bin/chunk-k8qrjnyg.js +0 -1
  175. package/dist/bin/chunk-kqstefmv.js +0 -1
  176. package/dist/bin/chunk-mk2h37pm.js +0 -1
  177. package/dist/bin/chunk-nrtjmzzn.js +0 -1
  178. package/dist/bin/chunk-q3rch5hc.js +0 -1
  179. package/dist/bin/chunk-qqb6h33k.js +0 -1
  180. package/dist/bin/chunk-r1p3k2tn.js +0 -1
  181. package/dist/bin/chunk-t8xq3v3j.js +0 -1
  182. package/dist/bin/chunk-xb48vxmk.js +0 -1
  183. package/dist/bin/chunk-yehb738r.js +0 -1
  184. package/dist/bin/chunk-ythfx8pv.js +0 -1
  185. package/dist/bin/chunk-zynfzzjk.js +0 -1
  186. package/dist/chunk-0c48hvb8.js +0 -1
  187. package/dist/chunk-8crqfe8x.js +0 -1
  188. package/dist/chunk-949tycxj.js +0 -1
  189. package/dist/chunk-s3pe89wj.js +0 -1
  190. package/dist/chunk-wxjd9gyb.js +0 -1
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{LI,$I,rl,ym,nl,il,cn,Q,l,sl,Sm,K,ol,g,ty,C,Xe,Ji,dn,w,be,al,ry,r,t,MI,FI,m,UI,QI,HI,GI,VI,dr,cl,Xi,ny,qI,jI,xe,Ye,dl,Im,bm,zI,Cm,Em,vm,Qo,ll,ce,ln,Dt,Ho,Pt,Ce,iy,ul,Go,Tm,wm,Rm,Dm,gl,KI,W,E,sy,oy,Pm,a,S,Ze,f,km,et,J,kt,WI,Nm,X,pl,Oe,lr,Vo,de,ml,le,ay,qo,Y,Z,_,Yi,D,ur,Nt,ee,e,un,JI,Bm,fl,XI,YI,ZI,eb,hl,tb,rb,nb,ib,sb,ob,ab,cb,db,lb,ub,gb,cy,dy,ly,uy,gy,py,my,gr,xm,Om,pr,Zi,pb,_m,mb,fb,gn,hb,Ab,yb,Sb,Ib,bb,fy,hy,Ay,yy,Sy,es,Cb,jo,Iy,Lm,V,by,tt,zo,Bt,Cy,$m,Ey,vy,Ty,Mm,q,Eb,vb,Tb,wb,wy,Rb,te,Db,Pb,kb,Al,yl,Ry,Fm,Um,Nb,Bb,xb,Ob,_b,Dy,Sl,Lb,$b,Mb,Fb,Ub,Py,ky,Qb,Hb,Gb,Vb,qb,jb,zb,Ny,Kb,Qm,Il,Wb,Jb,Xb,Yb,Hm,Gm,Vm,Zb,bl,By,xy,Oy,_y,Cl,Ly,eC,tC,rC,nC,iC,sC,oC,$y,My,Fy,Uy,qm,aC,cC,dC,lC,uC,gC,pC,mC,fC,Qy,Hy,Gy,Vy,hC,AC,jm,yC,zm,Km,Wm,Jm,SC,IC,bC,CC,_e,ts,EC,vC,TC,wC,RC,DC,PC,kC,qy,NC,BC,Xm,Ym,xC,OC,jy,_C,LC,$C,MC,FC,UC,QC,HC,GC,VC,qC,jC,zC,KC,WC,JC,XC,YC,ZC,eE,tE,El,zy,vl,Ky,Tl,Wy,wl,Jy,Rl,Xy,mr,Yy,Dl,Zy,rs,eS,Pl,tS,kl,rS,Zm,rE,ef,nE,Nl,nS,fr,iS,tf,iE,Bl,sS,rf,sE,nf,oE,sf,aE,xl,oS,of,cE,af,dE,cf,lE,df,uE,Ol,aS,_l,cS,lf,gE,uf,pE,gf,mE,pf,fE,mf,hE,ff,AE,Ll,dS,hf,yE,Af,SE,yf,IE,Sf,bE,If,CE,bf,EE,Cf,Ef,vf,Tf,wf,vE,Rf,TE,Df,wE,Pf,RE,rt,kf,lS,Ko,$l,pn,uS,ns,hr,Ml,Fl,gS,pS,Ul,Nf,Ql,Bf,DE,PE,Wo,Jo,Xo,Hl,mn,Gl,Vl,is,Yo,Zo,xf,mS,fS,hS,kE,Of,_f,NE,AS,Lf,yS,SS,IS,BE,$f,fn,ql,Mf,xE,bS,ea,ta,jl,Ff,OE,zl,CS,Uf,_E,Qf,LE,Hf,$E}from"./chunk-y9589qef.js";import{Kl,k,Wl,ra,ES,Gf,vS,TS,wS,RS,DS,PS,kS,NS}from"./chunk-m2a60evh.js";import{ca,Vf,ru,_S,cs,nu,da,qf,jf,An,la,iu,it,su,ou,au,ds,yn,zf,st,cu,ua,ga,pa,du,lu,uu,ls,ma,gu,Sn,us,fa,xt,Kf,pu,mu,Wf,fu,ha,Ar,hu,Au,yu,Su,ot,Jf,Iu,yr,Aa,ya,Sa,gs,ps,In,bu,ms,Ia,ba,bn,Cu,Cn,Xf,Yf,Ot,En,Ca,Zf,Eu,vu,Ea,Tu,wu,Ru,LS,ue,Du,$S,MS,fs,hs,FS,Ee,eh,_t,Le,$e,Lt,Pu,ku,Nu,Bu,th,rh,va,nh,ih,Ta,xu,Ou,sh,ge,oh,_u,ve,wa,at,$t,Mt,vn,As,Lu,US,ah,ch,dh,lh,Ra,Da,$u,Pa,Tn,ka,Mu,ys,Fu,Na,Ba,xa,Oa,_a,La,$a,Ma,Uu,Sr,Fa,Qu,wn,Hu,Ua,Qa,Gu,Ir,Ha,Ga,uh,QS,Ss,HS,GS,VS,Va,qa,Vu,gh,ja,Rn,qu,Is,ju,zu,Ku,za,ph,Ka,Wu,mh,Wa,fh,Dn,Pn,Ju,bs,rg,og,ag,cg,dg,lg,Es,br,Xa,kn,Nn,Cr,ct,Eh,Za,vh,Th,pg,ec,Ts,mg,tc,Ut,Fe,fg,rc,nc,hg,ic,sc,oc,ac,Ag,yg,xn,cc,dc,lc,uc,Sg,ws,On,Rs,gc}from"./chunk-f739f6d2.js";import{U,zr,Ad,ho,d,jp,zp}from"./chunk-0860mm00.js";import{Et,hd,xi,Oi,_i,qp}from"./chunk-pymc2aad.js";import{tA,rA,nA,wp,Rp,Dp,iA,Pp,kp,sA,oA,Np,aA,cA,md,Bp,dA,lA,xp,uA,gA,pA,mA,fA,hA,AA,Bi,fd,Op,_p,Lp,$p,Mp,Fp,Up,Qp,Hp,Gp,Vp,yA,SA,IA,bA,CA,EA,vA}from"./chunk-zgfzc46r.js";import{Ke,yd,Ie,rr,Sd,x,nr,vt,Id,Ao,RA,Kp,bd,s,Li,yo,Kr,Cd,Ed,Wr,DA,vd,BI,xI,So,OI,_I,Td,wd,$i,Io,ae,c,bo,We,Jr,PA,kA,Rd,NA,Co,BA,xA,Eo,Dd,Xr,vo,OA,ir,Pd,Wp,sr,Yr,_A,To,LA,O,$A,kd,Jp,wo,MA,FA,UA,Nd,Mi,Ro,Bd,or,Tt,QA,Zr,HA,xd,Xp,Yp,Do,Od,_d,wt,Zp,Fi,Ld,Po,en,em,Ui,$d,Md,Qi,tm,Fd,Ud,Qd,Hd,ko,rm,nm,GA,im,Gd,Hi,sm,om,No,tn,Bo,xo,Oo,Vd,am,qd,_o,VA,ar,qA,jd,rn,zd,jA,Kd,cm,Gi,nn,Lo,Vi,Je,zA,dm,lm,cr,Wd,Jd,Xd,qi,ji,zi,KA,WA,Rt,$o,JA,sn,um,Mo,XA,gm,pm,mm,YA,fm,hm,ZA,i,ey,Ki,Fo,Uo}from"./chunk-qgtydqpj.js";import{n}from"./chunk-9w5ncn9s.js";import{Re,gt,jn}from"./chunk-03eny26f.js";import{o}from"./chunk-1t3rjvf9.js";import{Te,Os,_s,Cg,Ac,yc,Ls,Sc,dt,re,lt,pe,T,we,Mn,Ic,Ue,bc,Un,Qn,Hn,Qt,Ht,Gt,Gn,vr,Cc,Tr,wr,ut,Vn,vc,Vt,Rr,qn,wc,Rg,Dg,Rc,Dr}from"./chunk-a92gvctb.js";import{pt,he,Ge,Pg,qt,Pc,kc,jt,H,zn,zt,Kt,Kn,Us,Qs,Pr,kr,Wn,Nr,Hs,Gs,Vs,qs,ie,js,zs,Ks,Ws,Ae,Js,Xs,Ys,N,Nc,Jn,Bc,ye,Br}from"./chunk-q4408fwg.js";import{ne}from"./chunk-tngsyawj.js";import{kg,xc,Ng,De,Oc,Xn,Bg,_c,xg,Og,Mh,Zn,eo,M,_r,ei,ti,Lr,Mr,ri,to,ni,ii,si,oi,ci,Fr,Se,Mc,ft,Fc,Ur,Hc,Ve,se,qe,je,At,ui,gi,Pe,St,ke,mi,fi,hi,Ai,yi,Si,Ii,Qr,F,io,op,Yc,Ci,Ei,vi,Ti,id,oo,sd,er,Ri,ao,co,od,Di,ad}from"./chunk-157bgr0x.js";import{uo,po,mo,B,Ne}from"./chunk-pah2r8a0.js";import{Jl,na,ss,os,ia,Xl,Yl,as,sa,oa,eu,tu,aa}from"./chunk-eva9hz6q.js";import{pc,_n,Ln,Ds,Ps,ks,Ns,mc,fc}from"./chunk-7mpbjr6c.js";import{hc}from"./chunk-hk1frmnn.js";import{Dc,Qe,I}from"./chunk-r49ynkag.js";import{He}from"./chunk-3ca6cb1s.js";import{b}from"./chunk-q8vvwmka.js";import{oe,Pi,lo,cd,ki,Ip}from"./chunk-nkx9pn64.js";import{Gr,Be}from"./chunk-axcxfz8p.js";import{A}from"./chunk-0kemzwpg.js";import{Yd,on,Zd,el,tl,Wi,Am,an}from"./chunk-qqn369pf.js";import{BS,nt}from"./chunk-83fy36fn.js";var Gh="https://api.machines.dev/v1";class $s extends Error{status;path;constructor(u,p,h){super(u);this.status=p;this.path=h;this.name="FlyApiError"}}function Qc(u){let p=u.ip.includes(":");if(p&&u.ip.startsWith("fdaa:"))return"private_v6";if(u.shared)return"shared_v4";return p?"v6":"v4"}class fp{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,p,h={}){let y=new URL(`https://api.machines.dev/v1${p}`);for(let[L,z]of Object.entries(h.query??{}))y.searchParams.set(L,z);let R=await this.fetch(y,{method:u,headers:{Authorization:`Bearer ${this.token}`,...h.body!==void 0?{"Content-Type":"application/json"}:{},...h.headers},body:h.body===void 0?void 0:JSON.stringify(h.body)});if(R.status===404&&h.notFound==="null")return null;let v=await R.text(),P=v?hp(v):void 0;if(!R.ok){let L=typeof P==="object"&&P&&"error"in P?String(P.error):v||R.statusText;throw new $s(`Fly.io ${u} ${p} failed (${R.status}): ${L}`,R.status,p)}return P}getApp(u){return this.rest("GET",`/apps/${encodeURIComponent(u)}`,{notFound:"null"})}createApp(u,p){return this.rest("POST","/apps",{body:{app_name:u,org_slug:p}})}async listMachines(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines`)??[]}createMachine(u,p){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines`,{body:p})}updateMachine(u,p,h,y){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(p)}`,{body:h,headers:{"fly-machine-lease-nonce":y}})}async acquireLease(u,p,h=120){let R=(await this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(p)}/lease`,{body:{ttl:h}})).data?.nonce;if(!R)throw new $s(`Fly.io gave no lease nonce for Machine ${p}`,200,`/machines/${p}/lease`);return R}async releaseLease(u,p,h){await this.rest("DELETE",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(p)}/lease`,{headers:{"fly-machine-lease-nonce":h}})}async waitForState(u,p,h,y={}){await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(p)}/wait`,{query:{state:h,timeout:String(y.timeoutSeconds??60),...y.instanceId?{instance_id:y.instanceId}:{}}})}async listVolumes(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/volumes`)??[]}createVolume(u,p){return this.rest("POST",`/apps/${encodeURIComponent(u)}/volumes`,{body:{...p,encrypted:!0}})}async setSecrets(u,p){return(await this.rest("POST",`/apps/${encodeURIComponent(u)}/secrets`,{body:{values:p}})).version}async listIpAssignments(u){return(await this.rest("GET",`/apps/${encodeURIComponent(u)}/ip_assignments`)).ips??[]}async assignIp(u,p){let h=await this.rest("POST",`/apps/${encodeURIComponent(u)}/ip_assignments`,{body:{type:p}});if(!h.ip)throw new $s(`Fly.io assigned no ${p} address to ${u}`,200,`/apps/${u}/ip_assignments`);return{ip:h.ip,shared:h.shared??p==="shared_v4",region:h.region}}async requestCertificate(u,p){return this.rest("POST",`/apps/${encodeURIComponent(u)}/certificates/acme`,{body:{hostname:p}})}}function hp(u){try{return JSON.parse(u)}catch{return}}var Lc="ts-cloud-role";function qh(u,p){let h=u.fly??{},y=h.app??`${u.project.slug}-${p.environment}`;if(!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/.test(y))throw Error(`"${y}" is not a valid Fly app name: lowercase letters, digits and dashes, 3 to 63 characters.`);let R=h.internalPort??3000,v=h.count??1;if(!Number.isInteger(v)||v<1)throw Error(`fly.count must be a whole number of at least 1, got ${v}.`);return{app:y,org:h.org??"personal",image:p.image,regions:h.regions?.length?h.regions:["iad"],count:v,internalPort:R,healthPath:h.healthPath??"/",vm:{cpuKind:h.vm?.cpuKind??"shared",cpus:h.vm?.cpus??1,memoryMb:h.vm?.memoryMb??512},...h.volume?{volume:{name:h.volume.name??"data",sizeGb:h.volume.sizeGb,path:h.volume.path}}:{},autoStop:h.autoStop??!1,env:{...p.env,PORT:String(R)},secrets:p.secrets??{},hostnames:h.hostnames??[],release:p.release}}function yp(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 Zh(u,p,h=()=>{}){let y=!1;if(!await u.getApp(p.app))h(`Creating Fly app ${p.app} in ${p.org}`),await u.createApp(p.app,p.org),y=!0;let R;if(Object.keys(p.secrets).length>0)R=await u.setSecrets(p.app,p.secrets),h(`Set ${Object.keys(p.secrets).length} secret(s) (version ${R})`);let v=await u.listIpAssignments(p.app),P=new Set(v.map(Qc));if(!P.has("v6"))v.push(await u.assignIp(p.app,"v6")),h("Assigned a dedicated IPv6");if(!P.has("v4")&&!P.has("shared_v4"))v.push(await u.assignIp(p.app,"shared_v4")),h("Assigned a shared IPv4");let L=yp(p),z=(await u.listMachines(p.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=p.volume?await u.listVolumes(p.app):[],me=[],bt=[],It=new Set;for(let Me of p.regions){let ze=z.filter((j)=>j.region===Me).sort((j,yt)=>j.id.localeCompare(yt.id));for(let j=0;j<p.count;j++){let yt=ze[j];if(yt){It.add(yt.id),await Cp(u,p.app,yt,L,R),bt.push(yt.id),h(`Updated ${yt.id} (${Me}) to ${p.image}`);continue}let G=p.volume?[{volume:(await Sp(u,p,Me,fe)).id,path:p.volume.path}]:void 0,ht=await u.createMachine(p.app,{region:Me,name:`${p.app}-${Me}-${j+1}`,config:{...L,...G?{mounts:G}:{}},...R!==void 0?{min_secrets_version:R}:{}});await u.waitForState(p.app,ht.id,"started",{instanceId:ht.instance_id}),me.push(ht.id),h(`Created ${ht.id} in ${Me}`)}}let mt=[];for(let Me of p.hostnames)mt.push(await u.requestCertificate(p.app,Me));return{app:p.app,url:`https://${p.app}.fly.dev`,createdApp:y,created:me,updated:bt,untouched:z.filter((Me)=>!It.has(Me.id)).map((Me)=>Me.id),ips:v,certificates:mt}}async function Cp(u,p,h,y,R){let v=await u.acquireLease(p,h.id);try{let P=await u.updateMachine(p,h.id,{config:{...y,...h.config?.mounts?.length?{mounts:h.config.mounts}:{}},...R!==void 0?{min_secrets_version:R}:{}},v);await u.waitForState(p,h.id,"started",{instanceId:P.instance_id})}finally{await u.releaseLease(p,h.id,v)}}async function Sp(u,p,h,y){let R=y.find((P)=>P.region===h&&P.name===p.volume.name&&!P.attached_machine_id);if(R)return R.attached_machine_id="pending",R;let v=await u.createVolume(p.app,{name:p.volume.name,region:h,size_gb:p.volume.sizeGb});return y.push({...v,attached_machine_id:"pending"}),v}import{createHmac as Zl,createSign as bp,timingSafeEqual as Ap}from"node:crypto";function bi(u){let p=u instanceof Date?u.getTime():u;if(!Number.isFinite(p))throw TypeError("Media access timestamp must be finite");return Math.floor(p/1000)}function Zu(u){return Buffer.from(u).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function Tp(u){return Buffer.from(u).toString("base64url")}function Yu(u,p=!1){if(!u||/[\r\n]/.test(u))throw TypeError("Media resource is invalid");let h=p?u.replaceAll("*","wildcard"):u,y=new URL(h);if(!["http:","https:"].includes(y.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!p&&u.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function Xu(u,p){let h=bp("RSA-SHA1");return h.update(u),h.end(),Zu(h.sign(p))}function ed(u){Yu(u.resource,!0);let h={DateLessThan:{"AWS:EpochTime":bi(u.expiresAt)}};if(u.activeAt!==void 0)h.DateGreaterThan={"AWS:EpochTime":bi(u.activeAt)};if(u.ipAddress)h.IpAddress={"AWS:SourceIp":u.ipAddress};return JSON.stringify({Statement:[{Resource:u.resource,Condition:h}]})}function xS(u,p,h){Yu(u);let y=bi(p),R=u.includes("?")?"&":"?",v=ed({resource:u,expiresAt:p}),P=Xu(v,h.privateKey);return`${u}${R}Expires=${y}&Signature=${encodeURIComponent(P)}&Key-Pair-Id=${encodeURIComponent(h.keyPairId)}`}function WS(u,p){let h=ed(u);return{"CloudFront-Key-Pair-Id":p.keyPairId,"CloudFront-Policy":Zu(Buffer.from(h)),"CloudFront-Signature":Xu(h,p.privateKey)}}function zS(u){if(!u.resource||/[\r\n]/.test(u.resource))throw TypeError("Media resource is invalid");let p=Tp(Buffer.from(JSON.stringify({resource:u.resource,expiresAt:bi(u.expiresAt),...u.keyId?{keyId:u.keyId}:{},...u.audience?{audience:u.audience}:{}}))),h=Zl("sha256",u.secret).update(p).digest("base64url");return`${p}.${h}`}function jS(u,p){let[h,y,R]=u.split(".");if(!h||!y||R)return null;let v=Zl("sha256",p.secret).update(h).digest(),P;try{P=Buffer.from(y,"base64url")}catch{return null}if(v.length!==P.length||!Ap(v,P))return null;try{let L=JSON.parse(Buffer.from(h,"base64url").toString("utf8")),z=bi(p.now??Date.now());if(!L.resource||!Number.isSafeInteger(L.expiresAt)||L.expiresAt<=z)return null;if(p.resource&&L.resource!==p.resource)return null;if(p.audience&&L.audience!==p.audience)return null;return L}catch{return null}}function KS(u,p=!1){let h=new URL(u,"https://media.invalid").pathname.toLowerCase(),y=/\.(?:m3u8|mpd|vtt|json)$/.test(h),R=/\.(?:key|license)$/.test(h)||h.includes("/keys/")||h.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":p&&(y||R)?"private, no-store":y?"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 p=u.prefix?`/${u.prefix.replace(/^\/+|\/+$/g,"")}`:"",h=u.protected??!1,y="public, max-age=31536000, immutable",R=h?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${u.bucket}.s3.${u.region}.amazonaws.com`,originPath:p,domain:u.domain,trustedKeyGroupIds:[...new Set(u.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:R,compress:!0,signed:h},{pathPattern:"*.mpd",cacheControl:R,compress:!0,signed:h},{pathPattern:"*.vtt",cacheControl:R,compress:!0,signed:h},{pathPattern:"*",cacheControl:y,compress:!1,signed:h}],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 vp{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(u){this.config=u.config,this.environment=u.environment,this.builder=new al(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let p=this.config.environments[this.environment]?.infrastructure;if(!p)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...p,compute:{...this.config.infrastructure?.compute,...p.compute},storage:{...this.config.infrastructure?.storage,...p.storage},functions:{...this.config.infrastructure?.functions,...p.functions},servers:{...this.config.infrastructure?.servers,...p.servers},databases:{...this.config.infrastructure?.databases,...p.databases},cdn:{...this.config.infrastructure?.cdn,...p.cdn},sftp:p.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...p.queues},redirects:{...this.config.infrastructure?.redirects,...p.redirects},realtime:{...this.config.infrastructure?.realtime,...p.realtime},cache:{...this.config.infrastructure?.cache,...p.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...p.fileSystem},email:{...this.config.infrastructure?.email,...p.email},search:{...this.config.infrastructure?.search,...p.search},ai:{...this.config.infrastructure?.ai,...p.ai}}}}shouldDeploy(u){if(u.environments&&!u.environments.includes(this.environment))return!1;if(u.requiresFeatures){let p=this.config.features||{};if(!u.requiresFeatures.every((y)=>p[y]===!0))return!1}if(u.regions){let p=this.config.environments[this.environment]?.region||this.config.project.region;if(!u.regions.includes(p))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,p=Number(u||3008);return Number.isFinite(p)&&p>0?p: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,p){return u==="public"||p.routeCompute===!0}storageBucketName(u,p,h){return this.mergedConfig.infrastructure?.storage?.[h]?.bucket??`${u}-${p}-${h}`}fileSystemLogicalId(u,p,h){return t(r({slug:`${u}-${h}`,environment:p,resourceType:"efs"}))}resolveSftpStorage(u,p,h){let y=u.storage;if(y?.type==="efs"&&y.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[y.fileSystem])throw Error(`sftp: storage.fileSystem "${y.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(p,h,y.fileSystem)},posixProfile:y.posixProfile}}if(y?.type==="s3"&&y.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[y.storageBucket])throw Error(`sftp: storage.storageBucket "${y.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(p,h,y.storageBucket)}}return}resolveComputeCachePathPatterns(u){if(u&&u.length>0)return u;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(u,p){return{PathPattern:u,TargetOriginId:p,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,p,h,y,R,v){let P=this.serverEipLogicalIds.get("app"),L=this.serverEipLogicalIds.get("appInstance");if(!P)return;let z=`EC2-${y}-${R}-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`,bt={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:P}]}]},me]]},It=this.resolveApiOriginPort();if(u.push({Id:z,DomainName:bt,CustomOriginConfig:{HTTPPort:It,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),h.push(P),L)h.push(L);for(let mt of v)p.push(this.createComputeCacheBehavior(mt,z))}buildCaddyfile(u){let p=u.filter(([,R])=>typeof R.domain==="string"&&R.domain&&typeof R.port==="number");if(p.length===0)return;let h=new Map;for(let[,R]of p){let v=h.get(R.domain)??[];v.push({port:R.port,path:R.path}),h.set(R.domain,v)}let y=[];for(let[R,v]of h){let L=[...v].sort((z,fe)=>{let me=!z.path||z.path==="/",bt=!fe.path||fe.path==="/";if(me&&!bt)return 1;if(!me&&bt)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{LI,$I,rl,ym,nl,il,cn,Q,l,sl,Sm,K,ol,g,ty,C,Ye,Ji,dn,w,be,al,ry,r,t,MI,FI,m,UI,QI,HI,GI,VI,lr,cl,Xi,ny,qI,jI,xe,Ze,dl,Im,bm,zI,Cm,Em,vm,Qo,ll,ce,ln,Pt,Ho,kt,Ce,iy,ul,Go,Tm,wm,Rm,Dm,gl,KI,W,E,sy,oy,Pm,a,S,et,f,km,tt,J,Nt,WI,Nm,X,pl,Oe,ur,Vo,de,ml,le,ay,qo,Y,Z,_,Yi,D,gr,Bt,ee,e,un,JI,Bm,fl,XI,YI,ZI,eb,hl,tb,rb,nb,ib,sb,ob,ab,cb,db,lb,ub,gb,cy,dy,ly,uy,gy,py,my,pr,xm,Om,mr,Zi,pb,_m,mb,fb,gn,hb,Ab,yb,Sb,Ib,bb,fy,hy,Ay,yy,Sy,es,Cb,jo,Iy,Lm,V,by,rt,zo,xt,Cy,$m,Ey,vy,Ty,Mm,q,Eb,vb,Tb,wb,wy,Rb,te,Db,Pb,kb,Al,yl,Ry,Fm,Um,Nb,Bb,xb,Ob,_b,Dy,Sl,Lb,$b,Mb,Fb,Ub,Py,ky,Qb,Hb,Gb,Vb,qb,jb,zb,Ny,Kb,Qm,Il,Wb,Jb,Xb,Yb,Hm,Gm,Vm,Zb,bl,By,xy,Oy,_y,Cl,Ly,eC,tC,rC,nC,iC,sC,oC,$y,My,Fy,Uy,qm,aC,cC,dC,lC,uC,gC,pC,mC,fC,Qy,Hy,Gy,Vy,hC,AC,jm,yC,zm,Km,Wm,Jm,SC,IC,bC,CC,_e,ts,EC,vC,TC,wC,RC,DC,PC,kC,qy,NC,BC,Xm,Ym,xC,OC,jy,_C,LC,$C,MC,FC,UC,QC,HC,GC,VC,qC,jC,zC,KC,WC,JC,XC,YC,ZC,eE,tE,El,zy,vl,Ky,Tl,Wy,wl,Jy,Rl,Xy,fr,Yy,Dl,Zy,rs,eS,Pl,tS,kl,rS,Zm,rE,ef,nE,Nl,nS,hr,iS,tf,iE,Bl,sS,rf,sE,nf,oE,sf,aE,xl,oS,of,cE,af,dE,cf,lE,df,uE,Ol,aS,_l,cS,lf,gE,uf,pE,gf,mE,pf,fE,mf,hE,ff,AE,Ll,dS,hf,yE,Af,SE,yf,IE,Sf,bE,If,CE,bf,EE,Cf,Ef,vf,Tf,wf,vE,Rf,TE,Df,wE,Pf,RE,nt,kf,lS,Ko,$l,pn,uS,ns,Ar,Ml,Fl,gS,pS,Ul,Nf,Ql,Bf,DE,PE,Wo,Jo,Xo,Hl,mn,Gl,Vl,is,Yo,Zo,xf,mS,fS,hS,kE,Of,_f,NE,AS,Lf,yS,SS,IS,BE,$f,fn,ql,Mf,xE,bS,ea,ta,jl,Ff,OE,zl,CS,Uf,_E,Qf,LE,Hf,$E}from"./chunk-040rbk7k.js";import{Kl,k,Wl,ra,ES,Gf,vS,TS,wS,RS,DS,PS,kS,NS}from"./chunk-m2a60evh.js";import{ca,Vf,ru,_S,cs,nu,da,qf,jf,An,la,iu,st,su,ou,au,ds,yn,zf,ot,cu,ua,ga,pa,du,lu,uu,ls,ma,gu,Sn,us,fa,Ot,Kf,pu,mu,Wf,fu,ha,yr,hu,Au,yu,Su,at,Jf,Iu,Sr,Aa,ya,Sa,gs,ps,In,bu,ms,Ia,ba,bn,Cu,Cn,Xf,Yf,_t,En,Ca,Zf,Eu,vu,Ea,Tu,wu,Ru,LS,ue,Du,$S,MS,fs,hs,FS,Ee,eh,Lt,Le,$e,$t,Pu,ku,Nu,Bu,th,rh,va,nh,ih,Ta,xu,Ou,sh,ge,oh,_u,ve,wa,ct,Mt,Ft,vn,As,Lu,US,ah,ch,dh,lh,Ra,Da,$u,Pa,Tn,ka,Mu,ys,Fu,Na,Ba,xa,Oa,_a,La,$a,Ma,Uu,Ir,Fa,Qu,wn,Hu,Ua,Qa,Gu,br,Ha,Ga,uh,QS,Ss,HS,GS,VS,Va,qa,Vu,gh,ja,Rn,qu,Is,ju,zu,Ku,za,ph,Ka,Wu,mh,Wa,fh,Dn,Pn,Ju,bs,rg,og,ag,cg,dg,lg,Es,Cr,Xa,kn,Nn,Er,dt,Eh,Za,vh,Th,pg,ec,Ts,mg,tc,Qt,Fe,fg,rc,nc,hg,ic,sc,oc,ac,Ag,yg,xn,cc,dc,lc,uc,Sg,ws,On,Rs,gc}from"./chunk-192rthtb.js";import{U,zr,Ad,ho,d,jp,zp}from"./chunk-v0s8vpa3.js";import{vt,hd,xi,Oi,_i,qp}from"./chunk-h360gwrf.js";import{tA,rA,nA,wp,Rp,Dp,iA,Pp,kp,sA,oA,Np,aA,cA,md,Bp,dA,lA,xp,uA,gA,pA,mA,fA,hA,AA,Bi,fd,Op,_p,Lp,$p,Mp,Fp,Up,Qp,Hp,Gp,Vp,yA,SA,IA,bA,CA,EA,vA}from"./chunk-yh9tmx00.js";import{We,yd,Ie,nr,Sd,x,ir,Tt,Id,Ao,RA,Kp,bd,s,Li,yo,Kr,Cd,Ed,Wr,DA,vd,BI,xI,So,OI,_I,Td,wd,$i,Io,ae,c,bo,Je,Jr,PA,kA,Rd,NA,Co,BA,xA,Eo,Dd,Xr,vo,OA,sr,Pd,Wp,or,Yr,_A,To,LA,O,$A,kd,Jp,wo,MA,FA,UA,Nd,Mi,Ro,Bd,ar,wt,QA,Zr,HA,xd,Xp,Yp,Do,Od,_d,Rt,Zp,Fi,Ld,Po,en,em,Ui,$d,Md,Qi,tm,Fd,Ud,Qd,Hd,ko,rm,nm,GA,im,Gd,Hi,sm,om,No,tn,Bo,xo,Oo,Vd,am,qd,_o,VA,cr,qA,jd,rn,zd,jA,Kd,cm,Gi,nn,Lo,Vi,Xe,zA,dm,lm,dr,Wd,Jd,Xd,qi,ji,zi,KA,WA,Dt,$o,JA,sn,um,Mo,XA,gm,pm,mm,YA,fm,hm,ZA,i,ey,Ki,Fo,Uo}from"./chunk-tb8azghz.js";import{n}from"./chunk-1wc2zfct.js";import{Re,pt,jn}from"./chunk-kbr9nc8y.js";import{o}from"./chunk-z585dfjz.js";import{Te,Os,_s,Cg,Ac,yc,Ls,Sc,lt,re,ut,pe,T,we,Mn,Ic,Ue,bc,Un,Qn,Hn,Ht,Gt,Vt,Gn,Tr,Cc,wr,Rr,gt,Vn,vc,qt,Dr,qn,wc,Rg,Dg,Rc,Pr}from"./chunk-a07kew2q.js";import{mt,he,Ge,Pg,jt,Pc,kc,zt,H,zn,Kt,Wt,Kn,Us,Qs,kr,Nr,Wn,Br,Hs,Gs,Vs,qs,ie,js,zs,Ks,Ws,Ae,Js,Xs,Ys,N,Nc,Jn,Bc,ye,xr}from"./chunk-hvttzk9q.js";import{ne}from"./chunk-xyem7g21.js";import{kg,xc,Ng,De,Oc,Xn,Bg,_c,xg,Og,Mh,Zn,eo,M,Lr,ei,ti,$r,Fr,ri,to,ni,ii,si,oi,ci,Ur,Se,Mc,ht,Fc,Qr,Hc,Ve,se,qe,je,yt,ui,gi,Pe,It,ke,mi,fi,hi,Ai,yi,Si,Ii,Hr,F,io,op,Yc,Ci,Ei,vi,Ti,id,oo,sd,tr,Ri,ao,co,od,Di,ad}from"./chunk-spr6akra.js";import{uo,po,mo,B,Ne}from"./chunk-tq7nsdnd.js";import{Jl,na,ss,os,ia,Xl,Yl,as,sa,oa,eu,tu,aa}from"./chunk-eva9hz6q.js";import{pc,_n,Ln,Ds,Ps,ks,Ns,mc,fc}from"./chunk-h5yx54ks.js";import{hc}from"./chunk-qrpy0h2n.js";import{Dc,Qe,I}from"./chunk-t8fbwcdk.js";import{He}from"./chunk-p21vbrgk.js";import{b}from"./chunk-je8tky8z.js";import{oe,Pi,lo,cd,ki,Ip}from"./chunk-nkx9pn64.js";import{Vr,Be}from"./chunk-1yj07hbw.js";import{A}from"./chunk-41fwhvp7.js";import{Yd,on,Zd,el,tl,Wi,Am,an}from"./chunk-qqn369pf.js";import{BS,it}from"./chunk-qb25wesa.js";var Gh="https://api.machines.dev/v1";class $s extends Error{status;path;constructor(u,p,h){super(u);this.status=p;this.path=h;this.name="FlyApiError"}}function Qc(u){let p=u.ip.includes(":");if(p&&u.ip.startsWith("fdaa:"))return"private_v6";if(u.shared)return"shared_v4";return p?"v6":"v4"}class fp{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,p,h={}){let y=new URL(`https://api.machines.dev/v1${p}`);for(let[L,z]of Object.entries(h.query??{}))y.searchParams.set(L,z);let R=await this.fetch(y,{method:u,headers:{Authorization:`Bearer ${this.token}`,...h.body!==void 0?{"Content-Type":"application/json"}:{},...h.headers},body:h.body===void 0?void 0:JSON.stringify(h.body)});if(R.status===404&&h.notFound==="null")return null;let v=await R.text(),P=v?hp(v):void 0;if(!R.ok){let L=typeof P==="object"&&P&&"error"in P?String(P.error):v||R.statusText;throw new $s(`Fly.io ${u} ${p} failed (${R.status}): ${L}`,R.status,p)}return P}getApp(u){return this.rest("GET",`/apps/${encodeURIComponent(u)}`,{notFound:"null"})}createApp(u,p){return this.rest("POST","/apps",{body:{app_name:u,org_slug:p}})}async listMachines(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines`)??[]}createMachine(u,p){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines`,{body:p})}updateMachine(u,p,h,y){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(p)}`,{body:h,headers:{"fly-machine-lease-nonce":y}})}async acquireLease(u,p,h=120){let R=(await this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(p)}/lease`,{body:{ttl:h}})).data?.nonce;if(!R)throw new $s(`Fly.io gave no lease nonce for Machine ${p}`,200,`/machines/${p}/lease`);return R}async releaseLease(u,p,h){await this.rest("DELETE",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(p)}/lease`,{headers:{"fly-machine-lease-nonce":h}})}async waitForState(u,p,h,y={}){await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(p)}/wait`,{query:{state:h,timeout:String(y.timeoutSeconds??60),...y.instanceId?{instance_id:y.instanceId}:{}}})}async listVolumes(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/volumes`)??[]}createVolume(u,p){return this.rest("POST",`/apps/${encodeURIComponent(u)}/volumes`,{body:{...p,encrypted:!0}})}async setSecrets(u,p){return(await this.rest("POST",`/apps/${encodeURIComponent(u)}/secrets`,{body:{values:p}})).version}async listIpAssignments(u){return(await this.rest("GET",`/apps/${encodeURIComponent(u)}/ip_assignments`)).ips??[]}async assignIp(u,p){let h=await this.rest("POST",`/apps/${encodeURIComponent(u)}/ip_assignments`,{body:{type:p}});if(!h.ip)throw new $s(`Fly.io assigned no ${p} address to ${u}`,200,`/apps/${u}/ip_assignments`);return{ip:h.ip,shared:h.shared??p==="shared_v4",region:h.region}}async requestCertificate(u,p){return this.rest("POST",`/apps/${encodeURIComponent(u)}/certificates/acme`,{body:{hostname:p}})}}function hp(u){try{return JSON.parse(u)}catch{return}}var Lc="ts-cloud-role";function qh(u,p){let h=u.fly??{},y=h.app??`${u.project.slug}-${p.environment}`;if(!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/.test(y))throw Error(`"${y}" is not a valid Fly app name: lowercase letters, digits and dashes, 3 to 63 characters.`);let R=h.internalPort??3000,v=h.count??1;if(!Number.isInteger(v)||v<1)throw Error(`fly.count must be a whole number of at least 1, got ${v}.`);return{app:y,org:h.org??"personal",image:p.image,regions:h.regions?.length?h.regions:["iad"],count:v,internalPort:R,healthPath:h.healthPath??"/",vm:{cpuKind:h.vm?.cpuKind??"shared",cpus:h.vm?.cpus??1,memoryMb:h.vm?.memoryMb??512},...h.volume?{volume:{name:h.volume.name??"data",sizeGb:h.volume.sizeGb,path:h.volume.path}}:{},autoStop:h.autoStop??!1,env:{...p.env,PORT:String(R)},secrets:p.secrets??{},hostnames:h.hostnames??[],release:p.release}}function yp(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 Zh(u,p,h=()=>{}){let y=!1;if(!await u.getApp(p.app))h(`Creating Fly app ${p.app} in ${p.org}`),await u.createApp(p.app,p.org),y=!0;let R;if(Object.keys(p.secrets).length>0)R=await u.setSecrets(p.app,p.secrets),h(`Set ${Object.keys(p.secrets).length} secret(s) (version ${R})`);let v=await u.listIpAssignments(p.app),P=new Set(v.map(Qc));if(!P.has("v6"))v.push(await u.assignIp(p.app,"v6")),h("Assigned a dedicated IPv6");if(!P.has("v4")&&!P.has("shared_v4"))v.push(await u.assignIp(p.app,"shared_v4")),h("Assigned a shared IPv4");let L=yp(p),z=(await u.listMachines(p.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=p.volume?await u.listVolumes(p.app):[],me=[],bt=[],At=new Set;for(let Me of p.regions){let ze=z.filter((j)=>j.region===Me).sort((j,Ct)=>j.id.localeCompare(Ct.id));for(let j=0;j<p.count;j++){let Ct=ze[j];if(Ct){At.add(Ct.id),await Cp(u,p.app,Ct,L,R),bt.push(Ct.id),h(`Updated ${Ct.id} (${Me}) to ${p.image}`);continue}let G=p.volume?[{volume:(await Sp(u,p,Me,fe)).id,path:p.volume.path}]:void 0,ft=await u.createMachine(p.app,{region:Me,name:`${p.app}-${Me}-${j+1}`,config:{...L,...G?{mounts:G}:{}},...R!==void 0?{min_secrets_version:R}:{}});await u.waitForState(p.app,ft.id,"started",{instanceId:ft.instance_id}),me.push(ft.id),h(`Created ${ft.id} in ${Me}`)}}let Ke=[];for(let Me of p.hostnames)Ke.push(await u.requestCertificate(p.app,Me));return{app:p.app,url:`https://${p.app}.fly.dev`,createdApp:y,created:me,updated:bt,untouched:z.filter((Me)=>!At.has(Me.id)).map((Me)=>Me.id),ips:v,certificates:Ke}}async function Cp(u,p,h,y,R){let v=await u.acquireLease(p,h.id);try{let P=await u.updateMachine(p,h.id,{config:{...y,...h.config?.mounts?.length?{mounts:h.config.mounts}:{}},...R!==void 0?{min_secrets_version:R}:{}},v);await u.waitForState(p,h.id,"started",{instanceId:P.instance_id})}finally{await u.releaseLease(p,h.id,v)}}async function Sp(u,p,h,y){let R=y.find((P)=>P.region===h&&P.name===p.volume.name&&!P.attached_machine_id);if(R)return R.attached_machine_id="pending",R;let v=await u.createVolume(p.app,{name:p.volume.name,region:h,size_gb:p.volume.sizeGb});return y.push({...v,attached_machine_id:"pending"}),v}import{createHmac as Zl,createSign as bp,timingSafeEqual as Ap}from"node:crypto";function bi(u){let p=u instanceof Date?u.getTime():u;if(!Number.isFinite(p))throw TypeError("Media access timestamp must be finite");return Math.floor(p/1000)}function Zu(u){return Buffer.from(u).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function Tp(u){return Buffer.from(u).toString("base64url")}function Yu(u,p=!1){if(!u||/[\r\n]/.test(u))throw TypeError("Media resource is invalid");let h=p?u.replaceAll("*","wildcard"):u,y=new URL(h);if(!["http:","https:"].includes(y.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!p&&u.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function Xu(u,p){let h=bp("RSA-SHA1");return h.update(u),h.end(),Zu(h.sign(p))}function ed(u){Yu(u.resource,!0);let h={DateLessThan:{"AWS:EpochTime":bi(u.expiresAt)}};if(u.activeAt!==void 0)h.DateGreaterThan={"AWS:EpochTime":bi(u.activeAt)};if(u.ipAddress)h.IpAddress={"AWS:SourceIp":u.ipAddress};return JSON.stringify({Statement:[{Resource:u.resource,Condition:h}]})}function xS(u,p,h){Yu(u);let y=bi(p),R=u.includes("?")?"&":"?",v=ed({resource:u,expiresAt:p}),P=Xu(v,h.privateKey);return`${u}${R}Expires=${y}&Signature=${encodeURIComponent(P)}&Key-Pair-Id=${encodeURIComponent(h.keyPairId)}`}function WS(u,p){let h=ed(u);return{"CloudFront-Key-Pair-Id":p.keyPairId,"CloudFront-Policy":Zu(Buffer.from(h)),"CloudFront-Signature":Xu(h,p.privateKey)}}function zS(u){if(!u.resource||/[\r\n]/.test(u.resource))throw TypeError("Media resource is invalid");let p=Tp(Buffer.from(JSON.stringify({resource:u.resource,expiresAt:bi(u.expiresAt),...u.keyId?{keyId:u.keyId}:{},...u.audience?{audience:u.audience}:{}}))),h=Zl("sha256",u.secret).update(p).digest("base64url");return`${p}.${h}`}function jS(u,p){let[h,y,R]=u.split(".");if(!h||!y||R)return null;let v=Zl("sha256",p.secret).update(h).digest(),P;try{P=Buffer.from(y,"base64url")}catch{return null}if(v.length!==P.length||!Ap(v,P))return null;try{let L=JSON.parse(Buffer.from(h,"base64url").toString("utf8")),z=bi(p.now??Date.now());if(!L.resource||!Number.isSafeInteger(L.expiresAt)||L.expiresAt<=z)return null;if(p.resource&&L.resource!==p.resource)return null;if(p.audience&&L.audience!==p.audience)return null;return L}catch{return null}}function KS(u,p=!1){let h=new URL(u,"https://media.invalid").pathname.toLowerCase(),y=/\.(?:m3u8|mpd|vtt|json)$/.test(h),R=/\.(?:key|license)$/.test(h)||h.includes("/keys/")||h.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":p&&(y||R)?"private, no-store":y?"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 p=u.prefix?`/${u.prefix.replace(/^\/+|\/+$/g,"")}`:"",h=u.protected??!1,y="public, max-age=31536000, immutable",R=h?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${u.bucket}.s3.${u.region}.amazonaws.com`,originPath:p,domain:u.domain,trustedKeyGroupIds:[...new Set(u.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:R,compress:!0,signed:h},{pathPattern:"*.mpd",cacheControl:R,compress:!0,signed:h},{pathPattern:"*.vtt",cacheControl:R,compress:!0,signed:h},{pathPattern:"*",cacheControl:y,compress:!1,signed:h}],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 vp{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(u){this.config=u.config,this.environment=u.environment,this.builder=new al(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let p=this.config.environments[this.environment]?.infrastructure;if(!p)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...p,compute:{...this.config.infrastructure?.compute,...p.compute},storage:{...this.config.infrastructure?.storage,...p.storage},functions:{...this.config.infrastructure?.functions,...p.functions},servers:{...this.config.infrastructure?.servers,...p.servers},databases:{...this.config.infrastructure?.databases,...p.databases},cdn:{...this.config.infrastructure?.cdn,...p.cdn},sftp:p.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...p.queues},redirects:{...this.config.infrastructure?.redirects,...p.redirects},realtime:{...this.config.infrastructure?.realtime,...p.realtime},cache:{...this.config.infrastructure?.cache,...p.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...p.fileSystem},email:{...this.config.infrastructure?.email,...p.email},search:{...this.config.infrastructure?.search,...p.search},ai:{...this.config.infrastructure?.ai,...p.ai}}}}shouldDeploy(u){if(u.environments&&!u.environments.includes(this.environment))return!1;if(u.requiresFeatures){let p=this.config.features||{};if(!u.requiresFeatures.every((y)=>p[y]===!0))return!1}if(u.regions){let p=this.config.environments[this.environment]?.region||this.config.project.region;if(!u.regions.includes(p))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,p=Number(u||3008);return Number.isFinite(p)&&p>0?p: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,p){return u==="public"||p.routeCompute===!0}storageBucketName(u,p,h){return this.mergedConfig.infrastructure?.storage?.[h]?.bucket??`${u}-${p}-${h}`}fileSystemLogicalId(u,p,h){return t(r({slug:`${u}-${h}`,environment:p,resourceType:"efs"}))}resolveSftpStorage(u,p,h){let y=u.storage;if(y?.type==="efs"&&y.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[y.fileSystem])throw Error(`sftp: storage.fileSystem "${y.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(p,h,y.fileSystem)},posixProfile:y.posixProfile}}if(y?.type==="s3"&&y.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[y.storageBucket])throw Error(`sftp: storage.storageBucket "${y.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(p,h,y.storageBucket)}}return}resolveComputeCachePathPatterns(u){if(u&&u.length>0)return u;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(u,p){return{PathPattern:u,TargetOriginId:p,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,p,h,y,R,v){let P=this.serverEipLogicalIds.get("app"),L=this.serverEipLogicalIds.get("appInstance");if(!P)return;let z=`EC2-${y}-${R}-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`,bt={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:P}]}]},me]]},At=this.resolveApiOriginPort();if(u.push({Id:z,DomainName:bt,CustomOriginConfig:{HTTPPort:At,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),h.push(P),L)h.push(L);for(let Ke of v)p.push(this.createComputeCacheBehavior(Ke,z))}buildCaddyfile(u){let p=u.filter(([,R])=>typeof R.domain==="string"&&R.domain&&typeof R.port==="number");if(p.length===0)return;let h=new Map;for(let[,R]of p){let v=h.get(R.domain)??[];v.push({port:R.port,path:R.path}),h.set(R.domain,v)}let y=[];for(let[R,v]of h){let L=[...v].sort((z,fe)=>{let me=!z.path||z.path==="/",bt=!fe.path||fe.path==="/";if(me&&!bt)return 1;if(!me&&bt)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 y.join(`
9
9
 
10
- `)}normalizeMountPath(u){let p=u?.mountPath||u?.path;if(!p||p==="/")return;let h=`/${p}`.replace(/\/+/g,"/").replace(/\/$/,"");return h==="/"?void 0:h}storageBucketLogicalId(u,p,h){return`${u}-${p}-s3-${h}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((y)=>y.charAt(0).toUpperCase()+y.slice(1)).join("")}pathMountRewriteFunctionCode(u,p="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(u)}; var rewriteStyle = ${JSON.stringify(p)}; 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,p=this.environment,h=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),y=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),R=!!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,p),this.generateContainerInfrastructure(u,p);if(h)this.generateServerless(u,p);if(y)this.generateServer(u,p);if(R)this.generateComputeApp(u,p);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(u,p);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(u,p),this.storageFailoverReplicas.length>0)this.builder.addMetadata(ul,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(u){}generateNetworkInfrastructure(u,p){if(this.builder.hasResource("VPC"))return;let y=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:R,logicalId:v}=S.createVpc({slug:u,environment:p,cidr:y,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",R);let P=`${u}${p}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${u}-${p}-igw`},{Key:"Environment",Value:p}]}});let L=`${u}${p}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}${p}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${u}-${p}-public-rt`},{Key:"Environment",Value:p}]}}),this.builder.addResource(`${u}${p}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[p]?.region||this.mergedConfig.project.region||"us-east-1",me=["a","b"];for(let bt=0;bt<2;bt++){let It=`PublicSubnet${bt+1}`;this.builder.addResource(It,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${bt}.0/24`,AvailabilityZone:`${fe}${me[bt]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${u}-${p}-public-${me[bt]}`},{Key:"Environment",Value:p}]}}),this.builder.addResource(`${It}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:It},RouteTableId:{Ref:z}}})}}generateContainerInfrastructure(u,p){let h=this.mergedConfig.infrastructure?.containers;if(!h)return;let y=this.mergedConfig.infrastructure?.loadBalancer,R=this.mergedConfig.infrastructure?.ssl,v=this.mergedConfig.infrastructure?.dns,P;if(R?.enabled&&R.domains?.length)if(R.certificateArn);else{let me=R.domains[0],bt=R.domains.slice(1).map((Me)=>{if(Me.includes(".")&&Me.endsWith(me))return Me.replace(`.${me}`,"");return Me}),{certificate:It,logicalId:mt}=E.createCertificate({domain:me,subdomains:bt,slug:u,environment:p,validationMethod:"DNS",hostedZoneId:v?.hostedZoneId});P=mt,this.builder.addResource(mt,It)}let L="ECSCluster";this.builder.addResource(L,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${u}-${p}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${u}-${p}`},{Key:"Environment",Value:p}]}});let z=`${u}${p}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${u}-${p}`,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}-${p}-alb-sg`},{Key:"Environment",Value:p}]}});let fe=`${u}${p}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[me,bt]of Object.entries(h)){let It=bt.port||3000;this.builder.addResource(fe,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${u}-${p}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:It,ToPort:It,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}-${p}-ecs-sg`},{Key:"Environment",Value:p}]}});let mt=`${u}${p}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(mt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-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}${p}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-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}${p}${me}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),j=`/ecs/${u}-${p}-${me}`;this.builder.addResource(ze,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:j,RetentionInDays:30}});let yt=`${u}${p}${me}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),G=String(bt.cpu||512),ht=String(bt.memory||1024);this.builder.addResource(yt,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${p}-${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:It,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:${It}${bt.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${p}-${me}`},{Key:"Environment",Value:p}]},DependsOn:[mt,Me,ze]});let Ct=`${u}${p}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(y?.enabled!==!1){this.builder.addResource(Ct,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${u}-${p}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:z}],Tags:[{Key:"Name",Value:`${u}-${p}-alb`},{Key:"Environment",Value:p}]}});let Ft=`${u}${p}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),Wt=y?.healthCheck?.path||bt.healthCheck||"/health";this.builder.addResource(Ft,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${u}-${p}-tg`,Port:It,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:Wt,HealthCheckIntervalSeconds:y?.healthCheck?.interval||30,HealthyThresholdCount:y?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:y?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${u}-${p}-tg`},{Key:"Environment",Value:p}]}});let Zt=`${u}${p}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(R?.enabled&&R?.redirectHttp)this.builder.addResource(Zt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ct},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(Zt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ct},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Ft}}]}});if(R?.enabled){let Yt=R.certificateArn||(P?{Ref:P}:void 0);if(Yt){let tr=`${u}${p}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(tr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:Ct},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Yt}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Ft}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Jt=`${u}${p}${me}Service`.replace(/[^a-zA-Z0-9]/g,""),Xt=bt.desiredCount||1;this.builder.addResource(Jt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${p}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:yt},DesiredCount:Xt,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:me,ContainerPort:It,TargetGroupArn:{Ref:Ft}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${u}-${p}-${me}`},{Key:"Environment",Value:p}]},DependsOn:[yt,Zt,Ft]});let Er=bt.autoScaling;if(Er){let Yt=`${u}${p}${me}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Yt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:Er.max||10,MinCapacity:Er.min||1,ResourceId:{"Fn::Sub":`service/\${${L}}/${u}-${p}-${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:Jt}),Er.targetCpuUtilization)this.builder.addResource(`${u}${p}${me}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${p}-${me}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Yt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:Er.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(Er.targetMemoryUtilization)this.builder.addResource(`${u}${p}${me}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${p}-${me}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Yt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:Er.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(v?.domain&&v?.hostedZoneId)this.builder.addResource(`${u}${p}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:v.hostedZoneId,Name:`api.${v.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[Ct,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[Ct,"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}-${p}-${me}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[Ct,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let Ft=`${u}${p}${me}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ft,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${p}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:yt},DesiredCount:bt.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${u}-${p}-${me}`},{Key:"Environment",Value:p}]},DependsOn:[yt]})}break}}generateServerless(u,p){if(this.mergedConfig.infrastructure?.functions)for(let[h,y]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(y))continue;let{role:R,logicalId:v}=de.createRole({slug:u,environment:p,roleName:`${u}-${p}-${h}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(v,R);let{lambdaFunction:P,logicalId:L}=a.createLambdaFunction({slug:u,environment:p,functionName:`${u}-${p}-${h}`,handler:y.handler||"index.handler",runtime:y.runtime||"nodejs20.x",code:{zipFile:y.code||"export const handler = async () => ({ statusCode: 200 });"},role:v,timeout:y.timeout,memorySize:y.memorySize});this.builder.addResource(L,P)}if(this.mergedConfig.infrastructure?.api){let{restApi:h,logicalId:y}=ml.createRestApi({slug:u,environment:p,apiName:`${u}-${p}-api`});this.builder.addResource(y,h)}}generateServer(u,p){if(!this.mergedConfig.infrastructure?.servers)return;let h=this.mergedConfig.infrastructure.servers,y=this.mergedConfig.infrastructure?.compute,R=this.mergedConfig.infrastructure?.ssl;if(Object.values(h).some((P)=>!P.privateNetwork||P.privateNetwork==="create"))this.generateNetworkInfrastructure(u,p);for(let[P,L]of Object.entries(h)){let z=L.instanceType||L.size||y?.size,me=(z?a.InstanceSize.specs[z]:void 0)?.instanceType||z||"t3.micro",bt=L.type||"app",It=L.userData||L.startupScript;if(!It)It=a.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:L.bunVersion||"latest",webServer:"none",domain:L.domain,enableSsl:!!R?.enabled,sslEmail:R?.letsEncrypt?.email,installRedis:bt==="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:p,vpcId:mt,subnetId:Me,instanceType:me,keyName:L.keyName||`${u}-${p}`,domain:L.domain,userData:It,volumeSize:L.diskSize||20,imageId:L.image,allowedPorts:yt});for(let[ht,Ct]of Object.entries(G.resources))this.builder.addResource(ht,Ct);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,p){let h=this.mergedConfig.infrastructure?.compute;if(!h)return;let y=this.mergedConfig.sites||{},R=Object.entries(y),P=this.mergedConfig.infrastructure?.dns?.domain,L=this.mergedConfig.infrastructure?.database,z=h.size,me=(z?a.InstanceSize.specs[z]:void 0)?.instanceType||z||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(u,p);let bt=this.buildCaddyfile(R),It=a.UserData.generateBunAppScript({runtime:h.runtime||"bun",runtimeVersion:h.runtimeVersion||"latest",systemPackages:h.systemPackages,database:L,caddyfile:bt}),mt=eo(h.appUpdates),Me=mt.length>0?`${It}
11
- ${mt.join(`
10
+ `)}normalizeMountPath(u){let p=u?.mountPath||u?.path;if(!p||p==="/")return;let h=`/${p}`.replace(/\/+/g,"/").replace(/\/$/,"");return h==="/"?void 0:h}storageBucketLogicalId(u,p,h){return`${u}-${p}-s3-${h}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((y)=>y.charAt(0).toUpperCase()+y.slice(1)).join("")}pathMountRewriteFunctionCode(u,p="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(u)}; var rewriteStyle = ${JSON.stringify(p)}; 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,p=this.environment,h=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),y=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),R=!!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,p),this.generateContainerInfrastructure(u,p);if(h)this.generateServerless(u,p);if(y)this.generateServer(u,p);if(R)this.generateComputeApp(u,p);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(u,p);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(u,p),this.storageFailoverReplicas.length>0)this.builder.addMetadata(ul,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(u){}generateNetworkInfrastructure(u,p){if(this.builder.hasResource("VPC"))return;let y=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:R,logicalId:v}=S.createVpc({slug:u,environment:p,cidr:y,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",R);let P=`${u}${p}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${u}-${p}-igw`},{Key:"Environment",Value:p}]}});let L=`${u}${p}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}${p}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${u}-${p}-public-rt`},{Key:"Environment",Value:p}]}}),this.builder.addResource(`${u}${p}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[p]?.region||this.mergedConfig.project.region||"us-east-1",me=["a","b"];for(let bt=0;bt<2;bt++){let At=`PublicSubnet${bt+1}`;this.builder.addResource(At,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${bt}.0/24`,AvailabilityZone:`${fe}${me[bt]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${u}-${p}-public-${me[bt]}`},{Key:"Environment",Value:p}]}}),this.builder.addResource(`${At}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:At},RouteTableId:{Ref:z}}})}}generateContainerInfrastructure(u,p){let h=this.mergedConfig.infrastructure?.containers;if(!h)return;let y=this.mergedConfig.infrastructure?.loadBalancer,R=this.mergedConfig.infrastructure?.ssl,v=this.mergedConfig.infrastructure?.dns,P;if(R?.enabled&&R.domains?.length)if(R.certificateArn);else{let me=R.domains[0],bt=R.domains.slice(1).map((Me)=>{if(Me.includes(".")&&Me.endsWith(me))return Me.replace(`.${me}`,"");return Me}),{certificate:At,logicalId:Ke}=E.createCertificate({domain:me,subdomains:bt,slug:u,environment:p,validationMethod:"DNS",hostedZoneId:v?.hostedZoneId});P=Ke,this.builder.addResource(Ke,At)}let L="ECSCluster";this.builder.addResource(L,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${u}-${p}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${u}-${p}`},{Key:"Environment",Value:p}]}});let z=`${u}${p}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${u}-${p}`,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}-${p}-alb-sg`},{Key:"Environment",Value:p}]}});let fe=`${u}${p}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[me,bt]of Object.entries(h)){let At=bt.port||3000;this.builder.addResource(fe,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${u}-${p}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:At,ToPort:At,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}-${p}-ecs-sg`},{Key:"Environment",Value:p}]}});let Ke=`${u}${p}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ke,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-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}${p}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-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}${p}${me}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),j=`/ecs/${u}-${p}-${me}`;this.builder.addResource(ze,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:j,RetentionInDays:30}});let Ct=`${u}${p}${me}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),G=String(bt.cpu||512),ft=String(bt.memory||1024);this.builder.addResource(Ct,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${p}-${me}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:G,Memory:ft,ExecutionRoleArn:{"Fn::GetAtt":[Ke,"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:At,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:${At}${bt.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${p}-${me}`},{Key:"Environment",Value:p}]},DependsOn:[Ke,Me,ze]});let St=`${u}${p}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(y?.enabled!==!1){this.builder.addResource(St,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${u}-${p}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:z}],Tags:[{Key:"Name",Value:`${u}-${p}-alb`},{Key:"Environment",Value:p}]}});let Et=`${u}${p}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),Ut=y?.healthCheck?.path||bt.healthCheck||"/health";this.builder.addResource(Et,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${u}-${p}-tg`,Port:At,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:Ut,HealthCheckIntervalSeconds:y?.healthCheck?.interval||30,HealthyThresholdCount:y?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:y?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${u}-${p}-tg`},{Key:"Environment",Value:p}]}});let Zt=`${u}${p}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(R?.enabled&&R?.redirectHttp)this.builder.addResource(Zt,{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(Zt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:St},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Et}}]}});if(R?.enabled){let Yt=R.certificateArn||(P?{Ref:P}:void 0);if(Yt){let er=`${u}${p}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(er,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:St},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Yt}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Et}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Jt=`${u}${p}${me}Service`.replace(/[^a-zA-Z0-9]/g,""),Xt=bt.desiredCount||1;this.builder.addResource(Jt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${p}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:Ct},DesiredCount:Xt,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:me,ContainerPort:At,TargetGroupArn:{Ref:Et}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${u}-${p}-${me}`},{Key:"Environment",Value:p}]},DependsOn:[Ct,Zt,Et]});let vr=bt.autoScaling;if(vr){let Yt=`${u}${p}${me}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Yt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:vr.max||10,MinCapacity:vr.min||1,ResourceId:{"Fn::Sub":`service/\${${L}}/${u}-${p}-${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:Jt}),vr.targetCpuUtilization)this.builder.addResource(`${u}${p}${me}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${p}-${me}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Yt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:vr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(vr.targetMemoryUtilization)this.builder.addResource(`${u}${p}${me}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${p}-${me}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Yt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:vr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(v?.domain&&v?.hostedZoneId)this.builder.addResource(`${u}${p}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:v.hostedZoneId,Name:`api.${v.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}-${p}-${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 Et=`${u}${p}${me}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Et,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${p}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:Ct},DesiredCount:bt.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${u}-${p}-${me}`},{Key:"Environment",Value:p}]},DependsOn:[Ct]})}break}}generateServerless(u,p){if(this.mergedConfig.infrastructure?.functions)for(let[h,y]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(y))continue;let{role:R,logicalId:v}=de.createRole({slug:u,environment:p,roleName:`${u}-${p}-${h}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(v,R);let{lambdaFunction:P,logicalId:L}=a.createLambdaFunction({slug:u,environment:p,functionName:`${u}-${p}-${h}`,handler:y.handler||"index.handler",runtime:y.runtime||"nodejs20.x",code:{zipFile:y.code||"export const handler = async () => ({ statusCode: 200 });"},role:v,timeout:y.timeout,memorySize:y.memorySize});this.builder.addResource(L,P)}if(this.mergedConfig.infrastructure?.api){let{restApi:h,logicalId:y}=ml.createRestApi({slug:u,environment:p,apiName:`${u}-${p}-api`});this.builder.addResource(y,h)}}generateServer(u,p){if(!this.mergedConfig.infrastructure?.servers)return;let h=this.mergedConfig.infrastructure.servers,y=this.mergedConfig.infrastructure?.compute,R=this.mergedConfig.infrastructure?.ssl;if(Object.values(h).some((P)=>!P.privateNetwork||P.privateNetwork==="create"))this.generateNetworkInfrastructure(u,p);for(let[P,L]of Object.entries(h)){let z=L.instanceType||L.size||y?.size,me=(z?a.InstanceSize.specs[z]:void 0)?.instanceType||z||"t3.micro",bt=L.type||"app",At=L.userData||L.startupScript;if(!At)At=a.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:L.bunVersion||"latest",webServer:"none",domain:L.domain,enableSsl:!!R?.enabled,sslEmail:R?.letsEncrypt?.email,installRedis:bt==="cache",installDatabaseClients:!!L.database});let Ke=L.privateNetwork&&L.privateNetwork!=="create"?L.privateNetwork:{Ref:"VPC"},Me=L.subnet||{Ref:"PublicSubnet1"},j=!!this.mergedConfig.infrastructure?.email?.server?.enabled,Ct=[22,80,443,this.resolveApiOriginPort()];if(j)Ct.push(25,465,587,143,993);let G=a.createServerModeStack({slug:`${u}-${P}`,environment:p,vpcId:Ke,subnetId:Me,instanceType:me,keyName:L.keyName||`${u}-${p}`,domain:L.domain,userData:At,volumeSize:L.diskSize||20,imageId:L.image,allowedPorts:Ct});for(let[ft,St]of Object.entries(G.resources))this.builder.addResource(ft,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,p){let h=this.mergedConfig.infrastructure?.compute;if(!h)return;let y=this.mergedConfig.sites||{},R=Object.entries(y),P=this.mergedConfig.infrastructure?.dns?.domain,L=this.mergedConfig.infrastructure?.database,z=h.size,me=(z?a.InstanceSize.specs[z]:void 0)?.instanceType||z||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(u,p);let bt=this.buildCaddyfile(R),At=a.UserData.generateBunAppScript({runtime:h.runtime||"bun",runtimeVersion:h.runtimeVersion||"latest",systemPackages:h.systemPackages,database:L,caddyfile:bt}),Ke=eo(h.appUpdates),Me=Ke.length>0?`${At}
11
+ ${Ke.join(`
12
12
  `)}
13
- `:It,ze=R.map(([,Wt])=>Wt.port).filter((Wt)=>typeof Wt==="number"&&![80,443].includes(Wt)),j=this.resolveApiOriginPort(),yt=`${u}${p}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),G=`${u}-${p}-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:p},{Key:"ManagedBy",Value:"ts-cloud"}]}});let ht=a.createServerModeStack({slug:`${u}-app`,environment:p,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:me,keyName:h.allowSsh?`${u}-${p}`:void 0,domain:P,userData:Me,volumeSize:h.disk?.size||20,imageId:h.image,allowedPorts:[...h.allowSsh?[22]:[],80,443,j,...ze]}),Ct=ht.resources[ht.outputs.instanceLogicalId];if(Ct?.Properties){let Wt=Ct.Properties.Tags||[];Ct.Properties.Tags=[...Wt,{Key:"Project",Value:u},{Key:"Environment",Value:p},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let Ft=ht.resources[ht.outputs.roleLogicalId];if(Ft?.Properties)Ft.Properties.Policies=Ft.Properties.Policies||[],Ft.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[Wt,Zt]of Object.entries(ht.resources))this.builder.addResource(Wt,Zt);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,p,h){let y=Object.keys(this.mergedConfig.infrastructure?.fileSystem??{});if(typeof h==="string")return y.includes(h)?{Ref:this.fileSystemLogicalId(u,p,h)}:h;if(y.length===1)return{Ref:this.fileSystemLogicalId(u,p,y[0])};throw Error(y.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 ${y.length} (${y.join(", ")}). Set mountEfs to the name of the one to mount.`)}generateJumpBox(u,p){let h=this.mergedConfig.infrastructure?.jumpBox;if(!h)return;let y=h===!0?{}:h;if(y.enabled===!1)return;this.generateNetworkInfrastructure(u,p);let R=y.size||"micro",P=a.InstanceSize.specs[R]?.instanceType||R||"t3.micro",L=a.createJumpBox({slug:u,environment:p,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:y.keyName,instanceType:P,allowedCidrs:y.allowedCidrs,mountEfs:y.mountEfs?{fileSystemId:this.jumpBoxFileSystemId(u,p,y.mountEfs),mountPath:y.mountPath||"/mnt/efs"}:void 0,databaseTools:y.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,p){let h=this.mergedConfig.infrastructure?.ssl,y=this.mergedConfig.infrastructure?.dns,R=y?.domain,v=y?.hostedZoneId,P=[],L,z;if(h?.certificateArn)z=h.certificateArn;else if(h?.enabled&&R&&v){let ze=h.domains||[R],j=ze[0],yt=ze.slice(1).map((Ct)=>{if(Ct.includes(".")&&Ct.endsWith(j))return Ct.replace(`.${j}`,"");return Ct}),{certificate:G,logicalId:ht}=E.createCertificate({domain:j,subdomains:yt,slug:u,environment:p,validationMethod:"DNS",hostedZoneId:v});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}${p}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(j,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${u}-${p}-s3-oac`,Description:`OAC for ${u} ${p} 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,p,G)})).filter((G)=>G.name!=="public"&&G.config.website&&G.mountPath);for(let[G,ht]of Object.entries(this.mergedConfig.infrastructure.storage)){let Ct=!!(ht.website&&j),Ft=this.storageBucketName(u,p,G),{bucket:Wt,logicalId:Zt}=xe.createBucket({slug:u,name:G,environment:p,bucketName:Ft,versioning:ht.versioning,encryption:ht.encryption,public:Ct?!1:ht.public}),Jt=this.normalizeMountPath(ht),Xt;if(ht.failover){let Yt=`infrastructure.storage.${G}`;if(!Ct||!R||Jt&&G!=="public")throw Error(`${Yt}.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(Xt=Tm({failover:ht.failover,primaryBucket:Ft,primaryRegion:this.mergedConfig.project.region||"us-east-1",where:Yt}),Xt.replicate&&Wt.Properties){let tr=`${Zt}FailoverReplicationRole`;this.builder.addResource(tr,Rm({primaryBucket:Ft,replicaBucket:Xt.replicaBucket}));let xr=Wt.Properties;xr.VersioningConfiguration={Status:"Enabled"},xr.ReplicationConfiguration=Dm({replicaBucket:Xt.replicaBucket,roleArn:{"Fn::GetAtt":[tr,"Arn"]}})}}if(Ct&&Wt.Properties)Wt.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(Zt,Wt),ht.website){let Yt=typeof ht.website==="object"?ht.website:{},tr=xe.enableWebsiteHosting(Wt,Yt.indexDocument||"index.html",Yt.errorDocument);this.builder.addResource(Zt,tr)}let Er=this.normalizeMountPath(ht);if(Ct&&j&&R&&!(Er&&G!=="public")){let Yt=`${u}${p}${G}CDN`.replace(/[^a-zA-Z0-9]/g,""),tr=[];if(ht.aliases&&ht.aliases.length>0)tr.push(...ht.aliases);else if(G==="public"){if(tr.push(R),h?.domains?.includes(`www.${R}`))tr.push(`www.${R}`)}else if(G==="docs")tr.push(`docs.${R}`);else if(G==="blog")tr.push(`blog.${R}`);let xr=typeof ht.website==="object"?ht.website:{},jr=ht.spa===!0,Vr=xr.errorDocument||(jr?"index.html":"404.html"),Or=[];if(jr)Or.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else Or.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${Vr}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${Vr}`,ErrorCachingMinTTL:300});let qr=z&&tr.length>0?{AcmCertificateArn:z,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:L&&tr.length>0?{AcmCertificateArn:{Ref:L},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Bn=`S3-${u}-${p}-${G}`,Ya=this.mergedConfig.project.region||"us-east-1",Yn;if(!jr)Yn=`${u}${p}${G}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(Yn,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${p}-${G}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${u} ${p} ${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 pi=[{Id:Bn,DomainName:{"Fn::Sub":`\${${Zt}}.s3.${Ya}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}],go=[],Tc=[];if(this.shouldRouteStorageBucketToCompute(G,ht)){this.appendComputeAppOrigin(pi,go,Tc,u,p,this.resolveComputeCachePathPatterns(ht.computeRoutes));for(let $r of yt){let Cs=`S3-${u}-${p}-${$r.name}`,Ec=`${u}${p}${$r.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ec,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${p}-${$r.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${u} ${p} ${$r.name} at ${$r.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode($r.mountPath,$r.rewriteStyle)}}),pi.push({Id:Cs,DomainName:{"Fn::Sub":`\${${$r.logicalId}}.s3.${Ya}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),Tc.push($r.logicalId,Ec);for(let gp of[$r.mountPath,`${$r.mountPath}/*`])go.push({PathPattern:gp,TargetOriginId:Cs,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Ec,"FunctionARN"]}}]})}}let fo,Xc=Bn;if(Xt){let $r=`${Bn}-failover`;Object.assign(pi[0],Xt.primaryConnection),pi.push({Id:$r,DomainName:wm(Xt.replicaBucket,Xt.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),fo=ln({primaryOriginId:Bn,secondaryOriginId:$r,statusCodes:Xt.statusCodes}),Xc=fo.Items[0].Id}let $c={Type:"AWS::CloudFront::Distribution",DependsOn:[Zt,j,...Yn?[Yn]:[],...Tc],Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${p} ${G} site`,DefaultRootObject:"index.html",Origins:pi,...fo?{OriginGroups:fo}:{},DefaultCacheBehavior:{TargetOriginId:Xc,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...Yn?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Yn,"FunctionARN"]}}]}:{}},...go.length>0?{CacheBehaviors:go}:{},...tr.length>0?{Aliases:tr}:{},ViewerCertificate:qr,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:Or}}};if(L)$c.DependsOn.push(L);if(Xt)Pt($c.Properties.DistributionConfig,`infrastructure.storage.${G}`),this.storageFailoverReplicas.push({name:G,primaryBucket:Ft,primaryRegion:Ya,replicaBucket:Xt.replicaBucket,replicaRegion:Xt.replicaRegion,replicate:Xt.replicate,distributionArnOutput:`${G}CloudFrontDistributionArn`}),this.builder.addOutput(`${G}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`},Description:`CloudFront distribution ARN for ${G} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${G}FailoverBucketName`,{Value:Xt.replicaBucket,Description:`Failover replica bucket for ${G} (${Xt.replicaRegion}), outside this stack`});this.builder.addResource(Yt,$c);let mp=`${Zt}CloudFrontPolicy`;if(this.builder.addResource(mp,{Type:"AWS::S3::BucketPolicy",DependsOn:[Zt,Yt],Properties:{Bucket:{Ref:Zt},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${Zt}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(G,ht))for(let $r of yt){let Cs=`${$r.logicalId}CloudFrontPolicy`;this.builder.addResource(Cs,{Type:"AWS::S3::BucketPolicy",DependsOn:[$r.logicalId,Yt],Properties:{Bucket:{Ref:$r.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:::\${${$r.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`}}}}]}}})}if(tr.length>0)P.push({name:G,bucketLogicalId:Zt,distLogicalId:Yt,oacLogicalId:j,aliases:tr});this.builder.addOutput(`${G}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Yt,"DomainName"]},Description:`CloudFront domain for ${G}`}),this.builder.addOutput(`${G}CloudFrontDistributionId`,{Value:{Ref:Yt},Description:`CloudFront distribution ID for ${G}`})}if(this.builder.addOutput(`${G}BucketName`,{Value:{Ref:Zt},Description:`S3 bucket name for ${G}`}),G==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:Zt},Description:"Frontend S3 bucket name"});if(G==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:Zt},Description:"Documentation S3 bucket name"});if(G==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:Zt},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let ze=this.mergedConfig.infrastructure.sftp,j=pl.create({...ze,storage:this.resolveSftpStorage(ze,u,p)??ze.storage,slug:u,environment:p});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(v&&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:v,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:v,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}=lr.createTable({slug:u,environment:p,tableName:`${u}-${p}-${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}=lr.createPostgres({slug:u,environment:p,dbInstanceIdentifier:`${u}-${p}-${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}=lr.createMysql({slug:u,environment:p,dbInstanceIdentifier:`${u}-${p}-${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,Ct=`${u}${p}${ze}CDN`.replace(/[^a-zA-Z0-9]/g,""),Ft=`S3-${u}-${p}-${ze}-cdn`,Wt=[{Id:Ft,DomainName:j.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:j.originShield?{Enabled:!0,OriginShieldRegion:j.originShieldRegion||this.mergedConfig.environments[p]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...ce(j,`infrastructure.cdn.${ze}`)}],Zt=[],Jt=[],Xt=["GET","HEAD","OPTIONS"],Er=Ft,Yt;if(j.failoverOrigin){Dt(Xt,`the default cache behavior of infrastructure.cdn.${ze}`);let Vr=`${Ft}-failover`,Or=typeof j.failoverOrigin==="string"?{domain:j.failoverOrigin}:j.failoverOrigin;if(!Or.domain)throw Error(`infrastructure.cdn.${ze}.failoverOrigin.domain is required`);if(Or.domain===j.origin)throw Error(`infrastructure.cdn.${ze}: failoverOrigin must differ from origin (both are ${j.origin})`);Wt.push({Id:Vr,DomainName:Or.domain,OriginPath:Or.originPath||"",...Ho(Or.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...ce(Or,`infrastructure.cdn.${ze}.failoverOrigin`)}),Yt=ln({primaryOriginId:Ft,secondaryOriginId:Vr,statusCodes:j.failoverStatusCodes}),Er=Yt.Items[0].Id}else if(j.failoverStatusCodes)throw Error(`infrastructure.cdn.${ze}: failoverStatusCodes needs failoverOrigin to fail over to`);if(j.routeCompute)this.appendComputeAppOrigin(Wt,Zt,Jt,u,p,this.resolveComputeCachePathPatterns(j.computeRoutes));let tr=ht&&yt?{AcmCertificateArn:L&&!G?{Ref:L}:ht,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},xr=[...Jt];if(L&&!G&&yt)xr.push(L);let jr={Type:"AWS::CloudFront::Distribution",...xr.length>0?{DependsOn:xr}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${p} ${ze} CDN`,DefaultRootObject:"index.html",Origins:Wt,...Yt?{OriginGroups:Yt}:{},DefaultCacheBehavior:{TargetOriginId:Er,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:Xt,CachedMethods:["GET","HEAD","OPTIONS"],Compress:j.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...Zt.length>0?{CacheBehaviors:Zt}:{},...yt&&ht?{Aliases:[yt]}:{},ViewerCertificate:tr,PriceClass:"PriceClass_100",HttpVersion:j.http3?"http2and3":"http2"}}};if(Pt(jr.Properties.DistributionConfig,`infrastructure.cdn.${ze}`),this.builder.addResource(Ct,jr),v&&yt&&ht){let Vr=yt.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Vr}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Ct,...L&&!G?[L]:[]],Properties:{HostedZoneId:v,Name:yt,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[Ct,"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:p,name:`${u}-${p}-${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:Ct,updatedSourceQueue:Ft,deadLetterLogicalId:Wt}=J.createDeadLetterQueue(G,{slug:u,environment:p,maxReceiveCount:j.maxReceiveCount});ht=Wt,this.builder.addResource(Wt,Ct);let Jt=this.builder.getResources()[G];if(Jt?.Properties)Jt.Properties.RedrivePolicy=Ft.Properties?.RedrivePolicy}if(j.trigger){let Ct=j.trigger,Ft=`${u}${p}${Ct.functionName}`.replace(/[^a-zA-Z0-9]/g,""),Wt={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[G,"Arn"]},FunctionName:{Ref:Ft},BatchSize:Ct.batchSize||10,MaximumBatchingWindowInSeconds:Ct.batchWindow||0,Enabled:!0,...Ct.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...Ct.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:Ct.maxConcurrency}},...Ct.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(Ct.filterPattern)}]}}},DependsOn:[G,Ft]};this.builder.addResource(`${G}Trigger`,Wt)}if(j.alarms?.enabled){let Ct=j.alarms,Ft=Ct.notificationTopicArn;if(!Ft&&Ct.notificationEmails?.length){let Jt=`${G}AlarmTopic`;this.builder.addResource(Jt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${p}-${ze}-alarms`,DisplayName:`${ze} Queue Alarms`}}),Ct.notificationEmails.forEach((Xt,Er)=>{this.builder.addResource(`${Jt}Sub${Er}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Jt},Protocol:"email",Endpoint:Xt}})}),Ft={Ref:Jt}}let Wt=Ct.queueDepthThreshold||1000;this.builder.addResource(`${G}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-${ze}-queue-depth`,AlarmDescription:`Queue ${ze} depth exceeds ${Wt} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:Wt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Ft&&{AlarmActions:[Ft],OKActions:[Ft]}}});let Zt=Ct.messageAgeThreshold||3600;if(this.builder.addResource(`${G}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-${ze}-message-age`,AlarmDescription:`Queue ${ze} oldest message exceeds ${Zt} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:Zt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Ft&&{AlarmActions:[Ft],OKActions:[Ft]}}}),ht&&Ct.dlqAlarm!==!1)this.builder.addResource(`${ht}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-${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"]}}],...Ft&&{AlarmActions:[Ft]}}})}if(j.subscribe){let Ct=j.subscribe,Ft=Ct.topicArn;if(!Ft&&Ct.topicName)Ft={Ref:Ct.topicName};if(Ft){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":Ft}}}]}}});let Wt={TopicArn:Ft,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[G,"Arn"]},RawMessageDelivery:Ct.rawMessageDelivery||!1};if(Ct.filterPolicy)Wt.FilterPolicy=Ct.filterPolicy,Wt.FilterPolicyScope=Ct.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${G}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:Wt,DependsOn:`${G}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(u,p);else this.generateRealtimeResources(u,p);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:Ct,policyLogicalId:Ft}=Nt.createDomainRedirectBucket({slug:u,environment:p,sourceDomain:yt,targetDomain:ze,protocol:j});this.builder.addResource(Ct,G),this.builder.addResource(Ft,ht)}if(fe.paths&&Object.keys(fe.paths).length>0){let yt=Nt.fromMapping(fe.paths,{statusCode:fe.statusCode||301}),{function:G,logicalId:ht}=Nt.createPathRedirectFunction({slug:u,environment:p,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}=qo.createAlarm({slug:u,environment:p,alarmName:`${u}-${p}-${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,p);let j=me.redis||{},{replicationGroup:yt,subnetGroup:G,logicalId:ht,subnetGroupId:Ct}=Vo.createRedis({slug:u,environment:p,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&&Ct)this.builder.addResource(Ct,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,p);let j=me.elasticache||{},{cluster:yt,subnetGroup:G,logicalId:ht,subnetGroupId:Ct}=Vo.createMemcached({slug:u,environment:p,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&&Ct)this.builder.addResource(Ct,G);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[ht,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let bt=this.mergedConfig.infrastructure?.email;if(bt){let ze=bt.domain||this.mergedConfig.infrastructure?.dns?.domain;if(ze){let{emailIdentity:j,logicalId:yt}=f.verifyDomain({domain:ze,slug:u,environment:p,enableDkim:bt.enableDkim!==!1,dkimKeyLength:bt.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(yt,j),bt.configurationSet!==!1){let{configurationSet:Ct,logicalId:Ft}=f.createConfigurationSet({slug:u,environment:p});this.builder.addResource(Ft,Ct)}let G=bt.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(G){if(bt.enableDkim!==!1)for(let Jt=1;Jt<=3;Jt++){let Xt=`DkimRecord${Jt}${ze.replace(/\./g,"")}`;this.builder.addResource(Xt,{Type:"AWS::Route53::RecordSet",DependsOn:[yt],Properties:{HostedZoneId:G,Name:{"Fn::GetAtt":[yt,`DkimDNSTokenName${Jt}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[yt,`DkimDNSTokenValue${Jt}`]}]}})}let{record:Ct,logicalId:Ft}=f.createSpfRecord(ze,G);this.builder.addResource(Ft,Ct);let{record:Wt,logicalId:Zt}=f.createDmarcRecord(ze,G,{policy:"none",reportingEmail:bt.dmarcReportingEmail||`dmarc-reports@${ze}`});this.builder.addResource(Zt,Wt)}this.builder.addOutput("EmailDomain",{Value:ze,Description:"SES verified email domain"});let ht=bt.server;if(ht?.enabled&&G){let Ct=this.mergedConfig.environments[p]?.region||this.mergedConfig.project.region||"us-east-1",Ft=`${u}-${p}-email`,{role:Wt,policy:Zt,roleLogicalId:Jt,policyLogicalId:Xt}=f.createEmailLambdaRole({slug:u,environment:p,s3BucketArn:`arn:aws:s3:::${Ft}`,sesIdentityArn:`arn:aws:ses:${Ct}:*:identity/${ze}`});this.builder.addResource(Jt,Wt),this.builder.addResource(Xt,Zt);let{function:Er,permission:Yt,logicalId:tr,permissionLogicalId:xr}=f.createInboundEmailLambda({slug:u,environment:p,roleArn:{"Fn::GetAtt":[Jt,"Arn"]},s3BucketName:Ft,organizedPrefix:"mailboxes/"});this.builder.addResource(tr,Er),this.builder.addResource(xr,Yt);let jr=f.createInboundEmailSetup({slug:u,environment:p,domain:ze,s3BucketName:Ft,s3KeyPrefix:"inbox/",region:Ct,hostedZoneId:G,lambdaFunctionArn:{"Fn::GetAtt":[tr,"Arn"]}});for(let[Or,qr]of Object.entries(jr.resources)){if(qr.Type==="AWS::SES::ReceiptRule")qr.DependsOn=[xr,tr];this.builder.addResource(Or,qr)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:tr},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:Ft,Description:"S3 bucket for email storage"});let Vr=this.serverEipLogicalIds.get("app");if(Vr&&G){let qr=`${ht?.subdomain||"mail"}.${ze}`,Bn=qr.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Bn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:G,Name:qr,Type:"A",TTL:"300",ResourceRecords:[{Ref:Vr}]}})}this.builder.addOutput("MailHost",{Value:`mail.${ze}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let It=this.mergedConfig.infrastructure?.search;if(It){let ze=It.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(ze)this.generateNetworkInfrastructure(u,p);let{domain:j,logicalId:yt}=ur.createDomain({slug:u,environment:p,engineVersion:It.engineVersion||"OpenSearch_2.11",instanceType:It.instanceType||"t3.small.search",instanceCount:It.instanceCount||1,volumeSize:It.volumeSize||10,volumeType:It.volumeType||"gp3",dedicatedMaster:It.dedicatedMaster||!1,dedicatedMasterType:It.dedicatedMasterType,dedicatedMasterCount:It.dedicatedMasterCount||3,multiAz:It.multiAz||!1,encryption:It.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:It.advancedSecurity,autoTune:It.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,p);for(let[ze,j]of Object.entries(mt)){let{fileSystem:yt,logicalId:G}=Ze.createFileSystem({slug:`${u}-${ze}`,environment:p,encrypted:j.encrypted!==!1,performanceMode:j.performanceMode||"generalPurpose",throughputMode:j.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(G,yt);let{securityGroup:ht,logicalId:Ct}=Ze.createEfsSecurityGroup({slug:`${u}-${ze}`,environment:p,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(Ct,ht);let{mountTargets:Ft,logicalIds:Wt}=Ze.createMultiAzMountTargets(G,{slug:`${u}-${ze}`,environment:p,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:Ct}});for(let Zt=0;Zt<Ft.length;Zt++)this.builder.addResource(Wt[Zt],Ft[Zt]);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:p,models:j,allowStreaming:yt});else if(ze==="ec2")G=Oe.enableBedrockForEc2({slug:u,environment:p,models:j,allowStreaming:yt});else if(ze==="lambda")G=Oe.enableBedrockForLambda({slug:u,environment:p,models:j,allowStreaming:yt});else G=Oe.createBedrockRole(ze,{slug:u,environment:p,models:j,allowStreaming:yt});if(this.builder.addResource(G.logicalId,G.role),Me.allowAsync){let{policy:ht,logicalId:Ct}=Oe.createBedrockPolicy({slug:u,environment:p,models:j,allowStreaming:yt,allowAsync:!0});this.builder.addResource(Ct,ht)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[G.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(u,p){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let y=h.name||`${u}-${p}-realtime`,R=h.scaling||{},v=h.storage||{type:"dynamodb"},P=R.handlerMemory||256,L=R.handlerTimeout||30,z=`${u}${p}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),fe=`${u}${p}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(v.type==="dynamodb"){let Wt=v.dynamodb||{},Zt=Wt.billingMode||"PAY_PER_REQUEST";this.builder.addResource(z,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${p}-realtime-connections`,BillingMode:Zt,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"},...Zt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Wt.readCapacity||5,WriteCapacityUnits:Wt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Zt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Wt.readCapacity||5,WriteCapacityUnits:Wt.writeCapacity||5}},...Wt.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${u}-${p}-realtime-connections`},{Key:"Environment",Value:p}]}}),this.builder.addResource(fe,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${p}-realtime-channels`,BillingMode:Zt,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"},...Zt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Wt.readCapacity||5,WriteCapacityUnits:Wt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Zt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Wt.readCapacity||5,WriteCapacityUnits:Wt.writeCapacity||5}},Tags:[{Key:"Name",Value:`${u}-${p}-realtime-channels`},{Key:"Environment",Value:p}]}})}let me=`${u}${p}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-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 bt=`${u}${p}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),It=`${u}${p}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),mt=`${u}${p}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(bt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${p}-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:p}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[me,z]}),this.builder.addResource(It,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${p}-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:p}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[me,z,fe]}),this.builder.addResource(mt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${p}-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:p}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[me,z,fe]});let Me=`${u}${p}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:y,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:y,Environment:p}}});let ze=`${bt}Permission`,j=`${It}Permission`,yt=`${mt}Permission`;this.builder.addResource(ze,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:bt},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:It},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`,Ct=`${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/\${${bt}.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/\${${It}.Arn}/invocations`}}}),this.builder.addResource(Ct,{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/\${${Ct}}`}}});let Ft=`${Me}Stage`;if(this.builder.addResource(Ft,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Me},StageName:p,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:R.messagesPerSecond||1000,ThrottlingRateLimit:R.messagesPerSecond||1000}}}),h.monitoring?.enabled){let Wt=h.monitoring,Zt=Wt.notificationTopicArn;if(!Zt&&Wt.notificationEmails?.length){let Jt=`${Me}AlarmTopic`;this.builder.addResource(Jt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${p}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),Wt.notificationEmails.forEach((Xt,Er)=>{this.builder.addResource(`${Jt}Sub${Er}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Jt},Protocol:"email",Endpoint:Xt}})}),Zt={Ref:Jt}}if(Wt.connectionThreshold)this.builder.addResource(`${Me}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${Wt.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:Wt.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Me}}],...Zt&&{AlarmActions:[Zt]}}});if(Wt.errorThreshold)this.builder.addResource(`${Me}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${Wt.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:Wt.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Me}}],...Zt&&{AlarmActions:[Zt]}}})}this.builder.addOutput(`${Me}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${Me}}.execute-api.\${AWS::Region}.amazonaws.com/${p}`},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
+ `:At,ze=R.map(([,Ut])=>Ut.port).filter((Ut)=>typeof Ut==="number"&&![80,443].includes(Ut)),j=this.resolveApiOriginPort(),Ct=`${u}${p}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),G=`${u}-${p}-deploy`;this.builder.addResource(Ct,{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:p},{Key:"ManagedBy",Value:"ts-cloud"}]}});let ft=a.createServerModeStack({slug:`${u}-app`,environment:p,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:me,keyName:h.allowSsh?`${u}-${p}`:void 0,domain:P,userData:Me,volumeSize:h.disk?.size||20,imageId:h.image,allowedPorts:[...h.allowSsh?[22]:[],80,443,j,...ze]}),St=ft.resources[ft.outputs.instanceLogicalId];if(St?.Properties){let Ut=St.Properties.Tags||[];St.Properties.Tags=[...Ut,{Key:"Project",Value:u},{Key:"Environment",Value:p},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let Et=ft.resources[ft.outputs.roleLogicalId];if(Et?.Properties)Et.Properties.Policies=Et.Properties.Policies||[],Et.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[Ut,Zt]of Object.entries(ft.resources))this.builder.addResource(Ut,Zt);this.builder.addOutput("deployBucketName",{Value:{Ref:Ct},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:ft.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:ft.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",ft.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",ft.outputs.instanceLogicalId)}jumpBoxFileSystemId(u,p,h){let y=Object.keys(this.mergedConfig.infrastructure?.fileSystem??{});if(typeof h==="string")return y.includes(h)?{Ref:this.fileSystemLogicalId(u,p,h)}:h;if(y.length===1)return{Ref:this.fileSystemLogicalId(u,p,y[0])};throw Error(y.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 ${y.length} (${y.join(", ")}). Set mountEfs to the name of the one to mount.`)}generateJumpBox(u,p){let h=this.mergedConfig.infrastructure?.jumpBox;if(!h)return;let y=h===!0?{}:h;if(y.enabled===!1)return;this.generateNetworkInfrastructure(u,p);let R=y.size||"micro",P=a.InstanceSize.specs[R]?.instanceType||R||"t3.micro",L=a.createJumpBox({slug:u,environment:p,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:y.keyName,instanceType:P,allowedCidrs:y.allowedCidrs,mountEfs:y.mountEfs?{fileSystemId:this.jumpBoxFileSystemId(u,p,y.mountEfs),mountPath:y.mountPath||"/mnt/efs"}:void 0,databaseTools:y.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,p){let h=this.mergedConfig.infrastructure?.ssl,y=this.mergedConfig.infrastructure?.dns,R=y?.domain,v=y?.hostedZoneId,P=[],L,z;if(h?.certificateArn)z=h.certificateArn;else if(h?.enabled&&R&&v){let ze=h.domains||[R],j=ze[0],Ct=ze.slice(1).map((St)=>{if(St.includes(".")&&St.endsWith(j))return St.replace(`.${j}`,"");return St}),{certificate:G,logicalId:ft}=E.createCertificate({domain:j,subdomains:Ct,slug:u,environment:p,validationMethod:"DNS",hostedZoneId:v});L=ft,this.builder.addResource(ft,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}${p}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(j,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${u}-${p}-s3-oac`,Description:`OAC for ${u} ${p} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let Ct=Object.entries(this.mergedConfig.infrastructure.storage).map(([G,ft])=>({name:G,config:ft,mountPath:this.normalizeMountPath(ft),rewriteStyle:ft.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(u,p,G)})).filter((G)=>G.name!=="public"&&G.config.website&&G.mountPath);for(let[G,ft]of Object.entries(this.mergedConfig.infrastructure.storage)){let St=!!(ft.website&&j),Et=this.storageBucketName(u,p,G),{bucket:Ut,logicalId:Zt}=xe.createBucket({slug:u,name:G,environment:p,bucketName:Et,versioning:ft.versioning,encryption:ft.encryption,public:St?!1:ft.public}),Jt=this.normalizeMountPath(ft),Xt;if(ft.failover){let Yt=`infrastructure.storage.${G}`;if(!St||!R||Jt&&G!=="public")throw Error(`${Yt}.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(Xt=Tm({failover:ft.failover,primaryBucket:Et,primaryRegion:this.mergedConfig.project.region||"us-east-1",where:Yt}),Xt.replicate&&Ut.Properties){let er=`${Zt}FailoverReplicationRole`;this.builder.addResource(er,Rm({primaryBucket:Et,replicaBucket:Xt.replicaBucket}));let _r=Ut.Properties;_r.VersioningConfiguration={Status:"Enabled"},_r.ReplicationConfiguration=Dm({replicaBucket:Xt.replicaBucket,roleArn:{"Fn::GetAtt":[er,"Arn"]}})}}if(St&&Ut.Properties)Ut.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(Zt,Ut),ft.website){let Yt=typeof ft.website==="object"?ft.website:{},er=xe.enableWebsiteHosting(Ut,Yt.indexDocument||"index.html",Yt.errorDocument);this.builder.addResource(Zt,er)}let vr=this.normalizeMountPath(ft);if(St&&j&&R&&!(vr&&G!=="public")){let Yt=`${u}${p}${G}CDN`.replace(/[^a-zA-Z0-9]/g,""),er=[];if(ft.aliases&&ft.aliases.length>0)er.push(...ft.aliases);else if(G==="public"){if(er.push(R),h?.domains?.includes(`www.${R}`))er.push(`www.${R}`)}else if(G==="docs")er.push(`docs.${R}`);else if(G==="blog")er.push(`blog.${R}`);let _r=typeof ft.website==="object"?ft.website:{},jr=ft.spa===!0,Mr=_r.errorDocument||(jr?"index.html":"404.html"),Or=[];if(jr)Or.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else Or.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${Mr}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${Mr}`,ErrorCachingMinTTL:300});let qr=z&&er.length>0?{AcmCertificateArn:z,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:L&&er.length>0?{AcmCertificateArn:{Ref:L},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Bn=`S3-${u}-${p}-${G}`,Ya=this.mergedConfig.project.region||"us-east-1",Yn;if(!jr)Yn=`${u}${p}${G}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(Yn,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${p}-${G}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${u} ${p} ${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 pi=[{Id:Bn,DomainName:{"Fn::Sub":`\${${Zt}}.s3.${Ya}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}],go=[],Tc=[];if(this.shouldRouteStorageBucketToCompute(G,ft)){this.appendComputeAppOrigin(pi,go,Tc,u,p,this.resolveComputeCachePathPatterns(ft.computeRoutes));for(let rr of Ct){let Cs=`S3-${u}-${p}-${rr.name}`,Ec=`${u}${p}${rr.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ec,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${p}-${rr.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${u} ${p} ${rr.name} at ${rr.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(rr.mountPath,rr.rewriteStyle)}}),pi.push({Id:Cs,DomainName:{"Fn::Sub":`\${${rr.logicalId}}.s3.${Ya}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),Tc.push(rr.logicalId,Ec);for(let gp of[rr.mountPath,`${rr.mountPath}/*`])go.push({PathPattern:gp,TargetOriginId:Cs,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Ec,"FunctionARN"]}}]})}}let fo,Xc=Bn;if(Xt){let rr=`${Bn}-failover`;Object.assign(pi[0],Xt.primaryConnection),pi.push({Id:rr,DomainName:wm(Xt.replicaBucket,Xt.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),fo=ln({primaryOriginId:Bn,secondaryOriginId:rr,statusCodes:Xt.statusCodes}),Xc=fo.Items[0].Id}let $c={Type:"AWS::CloudFront::Distribution",DependsOn:[Zt,j,...Yn?[Yn]:[],...Tc],Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${p} ${G} site`,DefaultRootObject:"index.html",Origins:pi,...fo?{OriginGroups:fo}:{},DefaultCacheBehavior:{TargetOriginId:Xc,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...Yn?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[Yn,"FunctionARN"]}}]}:{}},...go.length>0?{CacheBehaviors:go}:{},...er.length>0?{Aliases:er}:{},ViewerCertificate:qr,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:Or}}};if(L)$c.DependsOn.push(L);if(Xt)kt($c.Properties.DistributionConfig,`infrastructure.storage.${G}`),this.storageFailoverReplicas.push({name:G,primaryBucket:Et,primaryRegion:Ya,replicaBucket:Xt.replicaBucket,replicaRegion:Xt.replicaRegion,replicate:Xt.replicate,distributionArnOutput:`${G}CloudFrontDistributionArn`}),this.builder.addOutput(`${G}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`},Description:`CloudFront distribution ARN for ${G} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${G}FailoverBucketName`,{Value:Xt.replicaBucket,Description:`Failover replica bucket for ${G} (${Xt.replicaRegion}), outside this stack`});this.builder.addResource(Yt,$c);let mp=`${Zt}CloudFrontPolicy`;if(this.builder.addResource(mp,{Type:"AWS::S3::BucketPolicy",DependsOn:[Zt,Yt],Properties:{Bucket:{Ref:Zt},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${Zt}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(G,ft))for(let rr of Ct){let Cs=`${rr.logicalId}CloudFrontPolicy`;this.builder.addResource(Cs,{Type:"AWS::S3::BucketPolicy",DependsOn:[rr.logicalId,Yt],Properties:{Bucket:{Ref:rr.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:::\${${rr.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`}}}}]}}})}if(er.length>0)P.push({name:G,bucketLogicalId:Zt,distLogicalId:Yt,oacLogicalId:j,aliases:er});this.builder.addOutput(`${G}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Yt,"DomainName"]},Description:`CloudFront domain for ${G}`}),this.builder.addOutput(`${G}CloudFrontDistributionId`,{Value:{Ref:Yt},Description:`CloudFront distribution ID for ${G}`})}if(this.builder.addOutput(`${G}BucketName`,{Value:{Ref:Zt},Description:`S3 bucket name for ${G}`}),G==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:Zt},Description:"Frontend S3 bucket name"});if(G==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:Zt},Description:"Documentation S3 bucket name"});if(G==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:Zt},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let ze=this.mergedConfig.infrastructure.sftp,j=pl.create({...ze,storage:this.resolveSftpStorage(ze,u,p)??ze.storage,slug:u,environment:p});for(let[Ct,G]of Object.entries(j.resources))this.builder.addResource(Ct,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(v&&P.length>0)for(let{name:ze,distLogicalId:j,aliases:Ct}of P)for(let G of Ct){let ft=G.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${ft}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[j],Properties:{HostedZoneId:v,Name:G,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[j,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${ft}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[j],Properties:{HostedZoneId:v,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:Ct,logicalId:G}=ur.createTable({slug:u,environment:p,tableName:`${u}-${p}-${ze}`,partitionKey:j.partitionKey||{name:"id",type:"S"},sortKey:j.sortKey});this.builder.addResource(G,Ct)}else if(j.engine==="postgres"){let{dbInstance:Ct,logicalId:G}=ur.createPostgres({slug:u,environment:p,dbInstanceIdentifier:`${u}-${p}-${ze}`,masterUsername:j.username||"admin",masterUserPassword:j.password||"changeme123",allocatedStorage:j.storage||20,dbInstanceClass:j.instanceClass||"db.t3.micro"});this.builder.addResource(G,Ct)}else if(j.engine==="mysql"){let{dbInstance:Ct,logicalId:G}=ur.createMysql({slug:u,environment:p,dbInstanceIdentifier:`${u}-${p}-${ze}`,masterUsername:j.username||"admin",masterUserPassword:j.password||"changeme123",allocatedStorage:j.storage||20,dbInstanceClass:j.instanceClass||"db.t3.micro"});this.builder.addResource(G,Ct)}}if(this.mergedConfig.infrastructure?.cdn)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!j.origin)continue;let Ct=typeof j.customDomain==="string"?j.customDomain:j.customDomain?.domain||j.domain,G=typeof j.customDomain==="object"?j.customDomain?.certificateArn:j.certificateArn,ft=G||z,St=`${u}${p}${ze}CDN`.replace(/[^a-zA-Z0-9]/g,""),Et=`S3-${u}-${p}-${ze}-cdn`,Ut=[{Id:Et,DomainName:j.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:j.originShield?{Enabled:!0,OriginShieldRegion:j.originShieldRegion||this.mergedConfig.environments[p]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...ce(j,`infrastructure.cdn.${ze}`)}],Zt=[],Jt=[],Xt=["GET","HEAD","OPTIONS"],vr=Et,Yt;if(j.failoverOrigin){Pt(Xt,`the default cache behavior of infrastructure.cdn.${ze}`);let Mr=`${Et}-failover`,Or=typeof j.failoverOrigin==="string"?{domain:j.failoverOrigin}:j.failoverOrigin;if(!Or.domain)throw Error(`infrastructure.cdn.${ze}.failoverOrigin.domain is required`);if(Or.domain===j.origin)throw Error(`infrastructure.cdn.${ze}: failoverOrigin must differ from origin (both are ${j.origin})`);Ut.push({Id:Mr,DomainName:Or.domain,OriginPath:Or.originPath||"",...Ho(Or.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...ce(Or,`infrastructure.cdn.${ze}.failoverOrigin`)}),Yt=ln({primaryOriginId:Et,secondaryOriginId:Mr,statusCodes:j.failoverStatusCodes}),vr=Yt.Items[0].Id}else if(j.failoverStatusCodes)throw Error(`infrastructure.cdn.${ze}: failoverStatusCodes needs failoverOrigin to fail over to`);if(j.routeCompute)this.appendComputeAppOrigin(Ut,Zt,Jt,u,p,this.resolveComputeCachePathPatterns(j.computeRoutes));let er=ft&&Ct?{AcmCertificateArn:L&&!G?{Ref:L}:ft,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},_r=[...Jt];if(L&&!G&&Ct)_r.push(L);let jr={Type:"AWS::CloudFront::Distribution",..._r.length>0?{DependsOn:_r}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${p} ${ze} CDN`,DefaultRootObject:"index.html",Origins:Ut,...Yt?{OriginGroups:Yt}:{},DefaultCacheBehavior:{TargetOriginId:vr,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:Xt,CachedMethods:["GET","HEAD","OPTIONS"],Compress:j.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...Zt.length>0?{CacheBehaviors:Zt}:{},...Ct&&ft?{Aliases:[Ct]}:{},ViewerCertificate:er,PriceClass:"PriceClass_100",HttpVersion:j.http3?"http2and3":"http2"}}};if(kt(jr.Properties.DistributionConfig,`infrastructure.cdn.${ze}`),this.builder.addResource(St,jr),v&&Ct&&ft){let Mr=Ct.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Mr}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[St,...L&&!G?[L]:[]],Properties:{HostedZoneId:v,Name:Ct,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:Ct,logicalId:G}=J.createQueue({slug:u,environment:p,name:`${u}-${p}-${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,Ct);let ft;if(j.deadLetterQueue){let{deadLetterQueue:St,updatedSourceQueue:Et,deadLetterLogicalId:Ut}=J.createDeadLetterQueue(G,{slug:u,environment:p,maxReceiveCount:j.maxReceiveCount});ft=Ut,this.builder.addResource(Ut,St);let Jt=this.builder.getResources()[G];if(Jt?.Properties)Jt.Properties.RedrivePolicy=Et.Properties?.RedrivePolicy}if(j.trigger){let St=j.trigger,Et=`${u}${p}${St.functionName}`.replace(/[^a-zA-Z0-9]/g,""),Ut={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[G,"Arn"]},FunctionName:{Ref:Et},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,Et]};this.builder.addResource(`${G}Trigger`,Ut)}if(j.alarms?.enabled){let St=j.alarms,Et=St.notificationTopicArn;if(!Et&&St.notificationEmails?.length){let Jt=`${G}AlarmTopic`;this.builder.addResource(Jt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${p}-${ze}-alarms`,DisplayName:`${ze} Queue Alarms`}}),St.notificationEmails.forEach((Xt,vr)=>{this.builder.addResource(`${Jt}Sub${vr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Jt},Protocol:"email",Endpoint:Xt}})}),Et={Ref:Jt}}let Ut=St.queueDepthThreshold||1000;this.builder.addResource(`${G}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-${ze}-queue-depth`,AlarmDescription:`Queue ${ze} depth exceeds ${Ut} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:Ut,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Et&&{AlarmActions:[Et],OKActions:[Et]}}});let Zt=St.messageAgeThreshold||3600;if(this.builder.addResource(`${G}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-${ze}-message-age`,AlarmDescription:`Queue ${ze} oldest message exceeds ${Zt} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:Zt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Et&&{AlarmActions:[Et],OKActions:[Et]}}}),ft&&St.dlqAlarm!==!1)this.builder.addResource(`${ft}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-${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":[ft,"QueueName"]}}],...Et&&{AlarmActions:[Et]}}})}if(j.subscribe){let St=j.subscribe,Et=St.topicArn;if(!Et&&St.topicName)Et={Ref:St.topicName};if(Et){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":Et}}}]}}});let Ut={TopicArn:Et,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[G,"Arn"]},RawMessageDelivery:St.rawMessageDelivery||!1};if(St.filterPolicy)Ut.FilterPolicy=St.filterPolicy,Ut.FilterPolicyScope=St.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${G}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:Ut,DependsOn:`${G}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(u,p);else this.generateRealtimeResources(u,p);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 Ct of fe.domains){let{bucket:G,bucketPolicy:ft,logicalId:St,policyLogicalId:Et}=Bt.createDomainRedirectBucket({slug:u,environment:p,sourceDomain:Ct,targetDomain:ze,protocol:j});this.builder.addResource(St,G),this.builder.addResource(Et,ft)}if(fe.paths&&Object.keys(fe.paths).length>0){let Ct=Bt.fromMapping(fe.paths,{statusCode:fe.statusCode||301}),{function:G,logicalId:ft}=Bt.createPathRedirectFunction({slug:u,environment:p,rules:Ct});this.builder.addResource(ft,G)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:Ct,logicalId:G}=qo.createAlarm({slug:u,environment:p,alarmName:`${u}-${p}-${ze}`,metricName:j.metricName||"Errors",namespace:j.namespace||"AWS/Lambda",threshold:j.threshold||1,comparisonOperator:j.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(G,Ct)}let me=this.mergedConfig.infrastructure?.cache;if(me){let ze=me.type||"redis";if(ze==="redis"){this.generateNetworkInfrastructure(u,p);let j=me.redis||{},{replicationGroup:Ct,subnetGroup:G,logicalId:ft,subnetGroupId:St}=Vo.createRedis({slug:u,environment:p,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(ft,Ct),G&&St)this.builder.addResource(St,G);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[ft,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[ft,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(ze==="memcached"){this.generateNetworkInfrastructure(u,p);let j=me.elasticache||{},{cluster:Ct,subnetGroup:G,logicalId:ft,subnetGroupId:St}=Vo.createMemcached({slug:u,environment:p,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(ft,Ct),G&&St)this.builder.addResource(St,G);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[ft,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let bt=this.mergedConfig.infrastructure?.email;if(bt){let ze=bt.domain||this.mergedConfig.infrastructure?.dns?.domain;if(ze){let{emailIdentity:j,logicalId:Ct}=f.verifyDomain({domain:ze,slug:u,environment:p,enableDkim:bt.enableDkim!==!1,dkimKeyLength:bt.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(Ct,j),bt.configurationSet!==!1){let{configurationSet:St,logicalId:Et}=f.createConfigurationSet({slug:u,environment:p});this.builder.addResource(Et,St)}let G=bt.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(G){if(bt.enableDkim!==!1)for(let Jt=1;Jt<=3;Jt++){let Xt=`DkimRecord${Jt}${ze.replace(/\./g,"")}`;this.builder.addResource(Xt,{Type:"AWS::Route53::RecordSet",DependsOn:[Ct],Properties:{HostedZoneId:G,Name:{"Fn::GetAtt":[Ct,`DkimDNSTokenName${Jt}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[Ct,`DkimDNSTokenValue${Jt}`]}]}})}let{record:St,logicalId:Et}=f.createSpfRecord(ze,G);this.builder.addResource(Et,St);let{record:Ut,logicalId:Zt}=f.createDmarcRecord(ze,G,{policy:"none",reportingEmail:bt.dmarcReportingEmail||`dmarc-reports@${ze}`});this.builder.addResource(Zt,Ut)}this.builder.addOutput("EmailDomain",{Value:ze,Description:"SES verified email domain"});let ft=bt.server;if(ft?.enabled&&G){let St=this.mergedConfig.environments[p]?.region||this.mergedConfig.project.region||"us-east-1",Et=`${u}-${p}-email`,{role:Ut,policy:Zt,roleLogicalId:Jt,policyLogicalId:Xt}=f.createEmailLambdaRole({slug:u,environment:p,s3BucketArn:`arn:aws:s3:::${Et}`,sesIdentityArn:`arn:aws:ses:${St}:*:identity/${ze}`});this.builder.addResource(Jt,Ut),this.builder.addResource(Xt,Zt);let{function:vr,permission:Yt,logicalId:er,permissionLogicalId:_r}=f.createInboundEmailLambda({slug:u,environment:p,roleArn:{"Fn::GetAtt":[Jt,"Arn"]},s3BucketName:Et,organizedPrefix:"mailboxes/"});this.builder.addResource(er,vr),this.builder.addResource(_r,Yt);let jr=f.createInboundEmailSetup({slug:u,environment:p,domain:ze,s3BucketName:Et,s3KeyPrefix:"inbox/",region:St,hostedZoneId:G,lambdaFunctionArn:{"Fn::GetAtt":[er,"Arn"]}});for(let[Or,qr]of Object.entries(jr.resources)){if(qr.Type==="AWS::SES::ReceiptRule")qr.DependsOn=[_r,er];this.builder.addResource(Or,qr)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:er},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:Et,Description:"S3 bucket for email storage"});let Mr=this.serverEipLogicalIds.get("app");if(Mr&&G){let qr=`${ft?.subdomain||"mail"}.${ze}`,Bn=qr.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Bn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:G,Name:qr,Type:"A",TTL:"300",ResourceRecords:[{Ref:Mr}]}})}this.builder.addOutput("MailHost",{Value:`mail.${ze}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let At=this.mergedConfig.infrastructure?.search;if(At){let ze=At.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(ze)this.generateNetworkInfrastructure(u,p);let{domain:j,logicalId:Ct}=gr.createDomain({slug:u,environment:p,engineVersion:At.engineVersion||"OpenSearch_2.11",instanceType:At.instanceType||"t3.small.search",instanceCount:At.instanceCount||1,volumeSize:At.volumeSize||10,volumeType:At.volumeType||"gp3",dedicatedMaster:At.dedicatedMaster||!1,dedicatedMasterType:At.dedicatedMasterType,dedicatedMasterCount:At.dedicatedMasterCount||3,multiAz:At.multiAz||!1,encryption:At.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:At.advancedSecurity,autoTune:At.autoTune!==!1,vpc:ze});this.builder.addResource(Ct,j),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[Ct,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[Ct,"Arn"]},Description:"OpenSearch domain ARN"})}let Ke=this.mergedConfig.infrastructure?.fileSystem;if(Ke&&Object.keys(Ke).length>0){this.generateNetworkInfrastructure(u,p);for(let[ze,j]of Object.entries(Ke)){let{fileSystem:Ct,logicalId:G}=et.createFileSystem({slug:`${u}-${ze}`,environment:p,encrypted:j.encrypted!==!1,performanceMode:j.performanceMode||"generalPurpose",throughputMode:j.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(G,Ct);let{securityGroup:ft,logicalId:St}=et.createEfsSecurityGroup({slug:`${u}-${ze}`,environment:p,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(St,ft);let{mountTargets:Et,logicalIds:Ut}=et.createMultiAzMountTargets(G,{slug:`${u}-${ze}`,environment:p,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:St}});for(let Zt=0;Zt<Et.length;Zt++)this.builder.addResource(Ut[Zt],Et[Zt]);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||["*"],Ct=Me.allowStreaming!==!1,G;if(ze==="ecs")G=Oe.enableBedrockForEcs({slug:u,environment:p,models:j,allowStreaming:Ct});else if(ze==="ec2")G=Oe.enableBedrockForEc2({slug:u,environment:p,models:j,allowStreaming:Ct});else if(ze==="lambda")G=Oe.enableBedrockForLambda({slug:u,environment:p,models:j,allowStreaming:Ct});else G=Oe.createBedrockRole(ze,{slug:u,environment:p,models:j,allowStreaming:Ct});if(this.builder.addResource(G.logicalId,G.role),Me.allowAsync){let{policy:ft,logicalId:St}=Oe.createBedrockPolicy({slug:u,environment:p,models:j,allowStreaming:Ct,allowAsync:!0});this.builder.addResource(St,ft)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[G.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(u,p){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let y=h.name||`${u}-${p}-realtime`,R=h.scaling||{},v=h.storage||{type:"dynamodb"},P=R.handlerMemory||256,L=R.handlerTimeout||30,z=`${u}${p}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),fe=`${u}${p}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(v.type==="dynamodb"){let Ut=v.dynamodb||{},Zt=Ut.billingMode||"PAY_PER_REQUEST";this.builder.addResource(z,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${p}-realtime-connections`,BillingMode:Zt,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"},...Zt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Ut.readCapacity||5,WriteCapacityUnits:Ut.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Zt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Ut.readCapacity||5,WriteCapacityUnits:Ut.writeCapacity||5}},...Ut.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${u}-${p}-realtime-connections`},{Key:"Environment",Value:p}]}}),this.builder.addResource(fe,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${p}-realtime-channels`,BillingMode:Zt,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"},...Zt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Ut.readCapacity||5,WriteCapacityUnits:Ut.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Zt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Ut.readCapacity||5,WriteCapacityUnits:Ut.writeCapacity||5}},Tags:[{Key:"Name",Value:`${u}-${p}-realtime-channels`},{Key:"Environment",Value:p}]}})}let me=`${u}${p}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-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 bt=`${u}${p}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),At=`${u}${p}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),Ke=`${u}${p}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(bt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${p}-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:p}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[me,z]}),this.builder.addResource(At,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${p}-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:p}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[me,z,fe]}),this.builder.addResource(Ke,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${p}-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:p}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[me,z,fe]});let Me=`${u}${p}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:y,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:y,Environment:p}}});let ze=`${bt}Permission`,j=`${At}Permission`,Ct=`${Ke}Permission`;this.builder.addResource(ze,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:bt},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:At},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$disconnect`}}}),this.builder.addResource(Ct,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Ke},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$default`}}});let G=`${Me}ConnectInteg`,ft=`${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/\${${bt}.Arn}/invocations`}}}),this.builder.addResource(ft,{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(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/\${${Ke}.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/\${${ft}}`}}}),this.builder.addResource(`${Me}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Me},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${St}}`}}});let Et=`${Me}Stage`;if(this.builder.addResource(Et,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Me},StageName:p,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:R.messagesPerSecond||1000,ThrottlingRateLimit:R.messagesPerSecond||1000}}}),h.monitoring?.enabled){let Ut=h.monitoring,Zt=Ut.notificationTopicArn;if(!Zt&&Ut.notificationEmails?.length){let Jt=`${Me}AlarmTopic`;this.builder.addResource(Jt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${p}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),Ut.notificationEmails.forEach((Xt,vr)=>{this.builder.addResource(`${Jt}Sub${vr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Jt},Protocol:"email",Endpoint:Xt}})}),Zt={Ref:Jt}}if(Ut.connectionThreshold)this.builder.addResource(`${Me}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${Ut.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:Ut.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Me}}],...Zt&&{AlarmActions:[Zt]}}});if(Ut.errorThreshold)this.builder.addResource(`${Me}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${Ut.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:Ut.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Me}}],...Zt&&{AlarmActions:[Zt]}}})}this.builder.addOutput(`${Me}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${Me}}.execute-api.\${AWS::Region}.amazonaws.com/${p}`},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
 
@@ -170,7 +170,7 @@ catch (error) {
170
170
  return { statusCode: 500, body: JSON.stringify({ error: 'Internal error' }) };
171
171
  }
172
172
  };
173
- `.trim()}generateRealtimeServerResources(u,p){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let y=h.server||{},R=y.port||6001,v=y.instances||1,P=`${u}${p}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${u} realtime WebSocket server`,GroupName:`${u}-${p}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:R,ToPort:R,CidrIp:"0.0.0.0/0",Description:"WebSocket connections"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS/WSS connections"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${p}-realtime-sg`},{Key:"Environment",Value:p}]}});let L=`${u}${p}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),z=`${u}${p}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),fe=`${u}${p}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(fe,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-realtime-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}}),this.builder.addResource(z,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-realtime-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RealtimeTaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},...y.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let me=[{Name:"BROADCAST_HOST",Value:y.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(R)},{Name:"NODE_ENV",Value:p==="production"?"production":"development"}];if(y.redis?.enabled){if(y.redis.useElastiCache)me.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),me.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else me.push({Name:"REDIS_HOST",Value:y.redis.host||"localhost"}),me.push({Name:"REDIS_PORT",Value:String(y.redis.port||6379)});if(y.redis.keyPrefix)me.push({Name:"REDIS_KEY_PREFIX",Value:y.redis.keyPrefix})}this.builder.addResource(L,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${p}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[fe,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[z,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${u}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:R,Protocol:"tcp"}],Environment:me,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${u}-${p}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${R}${y.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${p}-realtime`},{Key:"Environment",Value:p}]},DependsOn:[fe,z]});let bt=`${u}${p}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(bt,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${u}-${p}-realtime`,RetentionInDays:30}});let It=`${u}${p}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(It,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${p}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:L},DesiredCount:v,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:P}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${u}-${p}-realtime`},{Key:"Environment",Value:p}]},DependsOn:[L,P,bt]}),y.autoScaling){let mt=y.autoScaling,Me=`${u}${p}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Me,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:mt.max||10,MinCapacity:mt.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${u}-${p}-realtime`},RoleARN:{"Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"},ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},DependsOn:It}),mt.targetCPU)this.builder.addResource(`${u}${p}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${p}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Me},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:mt.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(h.monitoring?.enabled){let mt=h.monitoring,Me=mt.notificationTopicArn;if(!Me&&mt.notificationEmails?.length){let ze=`${u}${p}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(ze,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${p}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),mt.notificationEmails.forEach((j,yt)=>{this.builder.addResource(`${ze}Sub${yt}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:ze},Protocol:"email",Endpoint:j}})}),Me={Ref:ze}}this.builder.addResource(`${u}${p}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-realtime-high-cpu`,AlarmDescription:"Realtime server CPU utilization is high",MetricName:"CPUUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${u}-${p}-realtime`}],...Me&&{AlarmActions:[Me]}},DependsOn:It}),this.builder.addResource(`${u}${p}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-realtime-high-memory`,AlarmDescription:"Realtime server memory utilization is high",MetricName:"MemoryUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${u}-${p}-realtime`}],...Me&&{AlarmActions:[Me]}},DependsOn:It})}this.builder.addOutput(`${u}${p}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${u}-${p}-realtime.\${AWS::Region}.elb.amazonaws.com:${R}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let u=this.mergedConfig.infrastructure?.realtime;if(!u||u.mode!=="server")return"";let p=u.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
173
+ `.trim()}generateRealtimeServerResources(u,p){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let y=h.server||{},R=y.port||6001,v=y.instances||1,P=`${u}${p}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${u} realtime WebSocket server`,GroupName:`${u}-${p}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:R,ToPort:R,CidrIp:"0.0.0.0/0",Description:"WebSocket connections"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS/WSS connections"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${p}-realtime-sg`},{Key:"Environment",Value:p}]}});let L=`${u}${p}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),z=`${u}${p}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),fe=`${u}${p}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(fe,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-realtime-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}}),this.builder.addResource(z,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${p}-realtime-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RealtimeTaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},...y.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let me=[{Name:"BROADCAST_HOST",Value:y.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(R)},{Name:"NODE_ENV",Value:p==="production"?"production":"development"}];if(y.redis?.enabled){if(y.redis.useElastiCache)me.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),me.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else me.push({Name:"REDIS_HOST",Value:y.redis.host||"localhost"}),me.push({Name:"REDIS_PORT",Value:String(y.redis.port||6379)});if(y.redis.keyPrefix)me.push({Name:"REDIS_KEY_PREFIX",Value:y.redis.keyPrefix})}this.builder.addResource(L,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${p}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[fe,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[z,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${u}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:R,Protocol:"tcp"}],Environment:me,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${u}-${p}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${R}${y.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${p}-realtime`},{Key:"Environment",Value:p}]},DependsOn:[fe,z]});let bt=`${u}${p}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(bt,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${u}-${p}-realtime`,RetentionInDays:30}});let At=`${u}${p}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(At,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${p}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:L},DesiredCount:v,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:P}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${u}-${p}-realtime`},{Key:"Environment",Value:p}]},DependsOn:[L,P,bt]}),y.autoScaling){let Ke=y.autoScaling,Me=`${u}${p}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Me,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:Ke.max||10,MinCapacity:Ke.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${u}-${p}-realtime`},RoleARN:{"Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"},ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},DependsOn:At}),Ke.targetCPU)this.builder.addResource(`${u}${p}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${p}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Me},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:Ke.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(h.monitoring?.enabled){let Ke=h.monitoring,Me=Ke.notificationTopicArn;if(!Me&&Ke.notificationEmails?.length){let ze=`${u}${p}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(ze,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${p}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),Ke.notificationEmails.forEach((j,Ct)=>{this.builder.addResource(`${ze}Sub${Ct}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:ze},Protocol:"email",Endpoint:j}})}),Me={Ref:ze}}this.builder.addResource(`${u}${p}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-realtime-high-cpu`,AlarmDescription:"Realtime server CPU utilization is high",MetricName:"CPUUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${u}-${p}-realtime`}],...Me&&{AlarmActions:[Me]}},DependsOn:At}),this.builder.addResource(`${u}${p}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${p}-realtime-high-memory`,AlarmDescription:"Realtime server memory utilization is high",MetricName:"MemoryUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${u}-${p}-realtime`}],...Me&&{AlarmActions:[Me]}},DependsOn:At})}this.builder.addOutput(`${u}${p}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${u}-${p}-realtime.\${AWS::Region}.elb.amazonaws.com:${R}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let u=this.mergedConfig.infrastructure?.realtime;if(!u||u.mode!=="server")return"";let p=u.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
174
174
 
175
175
  export default {
176
176
  verbose: ${this.environment!=="production"},
@@ -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 Ig(u,p,h){let y=`_acme-challenge.${p}`;if(await Eg(u,p,y,h))return;let R=await u.createRecord(p,{name:y,type:"TXT",content:h,ttl:60});if(!R.success)throw Error(`Failed to create DNS challenge record: ${R.message}`)}async function vg(u,p,h){let y=await u.deleteRecord(p,{name:`_acme-challenge.${p}`,type:"TXT",content:h});if(!y.success)console.warn(`Failed to delete DNS challenge record: ${y.message}`)}async function Eg(u,p,h,y){try{let R=await u.listRecords(p,"TXT"),v=h.replace(/\.$/,"").toLowerCase();return(R.records??[]).some((P)=>P.name.replace(/\.$/,"").toLowerCase()===v&&P.content.replace(/^"|"$/g,"")===y)}catch{return!1}}function td(u){let{hostedZoneId:p,dnsProvider:h,region:y="us-east-1"}=u;if(h)return N(h);if(p)return new ie(y,p);throw Error("Either dnsProvider or hostedZoneId must be provided")}async function dR(u){await Ig(td(u),u.domain,u.challengeValue)}async function pR(u){await vg(td(u),u.domain,u.challengeValue)}function mR(u){try{let{execSync:p}=nt("node:child_process"),h=p(`openssl x509 -checkend 2592000 -noout -in ${u}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as rd,createSign as Lg,generateKeyPairSync as nd}from"node:crypto";var ld={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class Fg{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(u){this.directoryUrl=u.staging?ld.staging:ld.production,this.email=u.email,this.accountKey=u.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:u}=nd("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 y=this.nonce;return this.nonce=null,y}let u=await this.getDirectory(),h=(await fetch(u.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!h)throw Error("Failed to get nonce from ACME server");return h}getJwk(){let u=this.accountKey.split(`
605
- `).filter((v)=>!v.startsWith("-----")).join(""),p=Buffer.from(u,"base64"),h=p.length-65,y=p.subarray(h+1,h+33),R=p.subarray(h+33,h+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(y),y:this.base64UrlEncode(R)}}getJwkThumbprint(){let u=this.getJwk(),p=JSON.stringify({crv:u.crv,kty:u.kty,x:u.x,y:u.y}),h=rd("sha256").update(p).digest();return this.base64UrlEncode(h)}base64UrlEncode(u){return(typeof u==="string"?Buffer.from(u):u).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(u,p){let h=await this.getNonce(),y=this.getJwk(),R={alg:"ES256",nonce:h,url:u};if(this.accountUrl)R.kid=this.accountUrl;else R.jwk=y;let v=this.base64UrlEncode(JSON.stringify(R)),P=p===""?"":this.base64UrlEncode(JSON.stringify(p)),L=`${v}.${P}`,z=Lg("SHA256");z.update(L);let fe=z.sign(this.accountKey),me=fe.subarray(4,4+fe[3]),bt=4+fe[3]+2,It=fe.subarray(bt,bt+fe[bt-1]),mt=Buffer.alloc(32),Me=Buffer.alloc(32);me.copy(mt,32-me.length),It.copy(Me,32-It.length);let ze=Buffer.concat([mt,Me]);return JSON.stringify({protected:v,payload:P,signature:this.base64UrlEncode(ze)})}async acmeRequest(u,p){let h=await this.signPayload(u,p),y=await fetch(u,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:h}),R=y.headers.get("replay-nonce");if(R)this.nonce=R;let v,P=y.headers.get("content-type");if(P?.includes("application/json")||P?.includes("application/problem+json"))v=await y.json();else v=await y.text();if(!y.ok)throw Error(`ACME request failed: ${JSON.stringify(v)}`);return{body:v,headers:y.headers}}async registerAccount(){let u=await this.getDirectory(),{body:p,headers:h}=await this.acmeRequest(u.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),y=h.get("location");if(!y)throw Error("No account URL returned");return this.accountUrl=y,y}async createOrder(u){if(!this.accountUrl)await this.registerAccount();let p=await this.getDirectory(),{body:h,headers:y}=await this.acmeRequest(p.newOrder,{identifiers:u.map((v)=>({type:"dns",value:v}))}),R=y.get("location");if(!R)throw Error("No order URL returned");return{orderUrl:R,authorizations:h.authorizations,finalize:h.finalize}}async getAuthorization(u){let{body:p}=await this.acmeRequest(u,""),h=p.identifier.value,y=this.getJwkThumbprint(),R=p.challenges.filter((v)=>v.type==="http-01"||v.type==="dns-01").map((v)=>{let P=`${v.token}.${y}`;if(v.type==="http-01")return{type:"http-01",token:v.token,keyAuthorization:P,identifier:`/.well-known/acme-challenge/${v.token}`};else{let L=this.base64UrlEncode(rd("sha256").update(P).digest());return{type:"dns-01",token:v.token,keyAuthorization:P,identifier:`_acme-challenge.${h}`,dnsValue:L}}});return{domain:h,challenges:R}}async respondToChallenge(u){await this.acmeRequest(u,{})}async waitForAuthorization(u,p=30){for(let h=0;h<p;h++){let{body:y}=await this.acmeRequest(u,"");if(y.status==="valid")return;if(y.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(y)}`);await new Promise((R)=>setTimeout(R,2000))}throw Error("Authorization timed out")}generateCsr(u){let{privateKey:p}=nd("rsa",{modulusLength:2048}),h=p.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(u,p),privateKey:h}}createSimpleCsr(u,p){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(u,p){let{csr:h,privateKey:y}=this.generateCsr(p),{body:R}=await this.acmeRequest(u,{csr:this.base64UrlEncode(Buffer.from(h,"base64"))}),v=R.certificate;if(!v)throw Error("Certificate not immediately available - polling not implemented");let L=await(await fetch(v)).text(),z=L.split(/(?=-----BEGIN CERTIFICATE-----)/g),fe=z[0],me=z.slice(1).join("");return{certificate:fe,privateKey:y,chain:me,fullchain:L,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var Hr=(u)=>u===void 0?void 0:u?"on":"off";function zc(u){let p={ssl:u.ssl,always_use_https:Hr(u.alwaysUseHttps),automatic_https_rewrites:Hr(u.automaticHttpsRewrites),min_tls_version:u.minTlsVersion,tls_1_3:Hr(u.tls13),brotli:Hr(u.brotli),http3:Hr(u.http3),"0rtt":Hr(u.zeroRtt),early_hints:Hr(u.earlyHints),browser_cache_ttl:u.browserCacheTtl,always_online:Hr(u.alwaysOnline),websockets:Hr(u.websockets),email_obfuscation:Hr(u.emailObfuscation)};if(u.hsts)p.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 h of Object.keys(p))if(p[h]===void 0)delete p[h];return{...p,...u.raw??{}}}var wi={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 _g}from"node:tls";async function Uc(u){let{address:p,serverName:h,port:y=443,timeoutMs:R=5000}=u;return new Promise((v)=>{let P=!1,L=(fe)=>{if(P)return;P=!0;try{z.destroy()}catch{}v(fe)},z=_g({host:p,port:y,servername:h,rejectUnauthorized:!1,timeout:R});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 ${R}ms`})}),z.once("error",(fe)=>{L({reachable:!1,trusted:!1,reason:fe.message})})})}function Mg(u,p){let h=p.replace(/\.$/,"").toLowerCase();return u.some((y)=>{let R=y.replace(/\.$/,"").toLowerCase();if(R===h)return!0;if(!R.startsWith("*."))return!1;let v=R.slice(2);if(!h.endsWith(`.${v}`))return!1;return!h.slice(0,h.length-v.length-1).includes(".")})}async function Wg(u){let{provider:p,zone:h,hosts:y,ipv4:R,ipv6:v,proxied:P=!0,settings:L=wi,cache:z,originGuard:fe,purge:me=!0,ttl:bt=300,skipOriginProbe:It=!1,skipEdgeCertificateCheck:mt=!1}=u,Me={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(y.length===0)return Me;let ze=[],j=P&&!mt?await p.listEdgeCertificateHosts(h):null;for(let G of y){let ht=P;if(ht&&j&&!Mg(j,G)){ht=!1;let Ft=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:Ft}),Me.warnings.push(`${G}: publishing DNS-only — ${Ft}. 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&&!It){let Ft=await Uc({address:R,serverName:G});if(!Ft.trusted){ht=!1;let Wt=Ft.reason||"origin is not serving a trusted certificate";Me.deferredProxy.push({host:G,reason:Wt}),Me.warnings.push(`${G}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${Wt}). 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 Ct=[{type:"A",content:R}];if(v&&Xn(G))Ct.push({type:"AAAA",content:v});for(let{type:Ft,content:Wt}of Ct){let Zt=await p.upsertRecord(h,{name:G,type:Ft,content:Wt,ttl:bt,proxied:ht});if(Zt.success)Me.records.push({host:G,type:Ft,content:Wt,proxied:ht});else Me.warnings.push(`${G} ${Ft} → ${Wt} failed: ${Zt.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=zc(L),ht=await p.applyZoneSettings(h,G);Me.settingsChanged=ht.changed;for(let Ct of ht.failed)Me.warnings.push(`zone setting '${Ct.id}' could not be applied: ${Ct.error}`)}catch(G){Me.warnings.push(`zone settings could not be read: ${G instanceof Error?G.message:String(G)}`)}let yt=Pc(ze,z);if(yt.length>0){let G=await p.putManagedPhaseRules(h,"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=kc(ze,fe.header,fe.value);if(G.length>0){let ht=await p.putManagedPhaseRules(h,"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 p.purgeCache(h,{hosts:ze}),!Me.purged)Me.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Me}var Vg=(u)=>process.env[u];function ud(u,p){let h=u.replace(/\.$/,"").toLowerCase();if(p){let y=p.replace(/\.$/,"").toLowerCase();if(h===y||h.endsWith(`.${y}`))return y}return h.split(".").slice(-2).join(".")}function zg(u,p={}){let h=p.env??Vg,y=u.infrastructure?.compute?.proxy?.cdn,R=[];if(!y||y.provider!=="cloudflare")return{plan:null,errors:R};if(y.originDomain)R.push(`compute.proxy.cdn.originDomain (${y.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 v=h("CLOUDFLARE_API_TOKEN");if(!v)return R.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:R};let P=u.sites??{},L=y.frontedHosts?.length?[...new Set(y.frontedHosts.map((It)=>It.toLowerCase()))]:mo(P,{autoWww:u.infrastructure?.compute?.proxy?.autoWww!==!1});if(L.length===0)return R.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:R};let z=u.infrastructure?.dns?.domain,fe=new Set(L.map((It)=>ud(It,z)));if(fe.size>1)return R.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:R};let me=y.cloudflare??{},bt=y.secret?{header:y.secretHeader??"X-Origin-Verify",value:y.secret}:void 0;return{plan:{zone:[...fe][0],hosts:L,apiToken:v,zoneId:me.zoneId??h("CLOUDFLARE_ZONE_ID"),accountId:me.accountId??h("CLOUDFLARE_ACCOUNT_ID"),proxied:me.proxied!==!1,settings:me.settings??wi,cache:me.cache,originGuard:bt,purge:me.purgeOnDeploy!==!1,skipOriginProbe:me.skipOriginProbe===!0},errors:R}}var Hg=26214400;var Ug=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class dd{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,p,h){return vs(u,`/accounts/${this.accountId}${p}`,`Bearer ${this.apiToken}`,h)}async getProject(u){try{return await this.request("GET",`/pages/projects/${u}`)}catch(p){if(p instanceof Error&&/\b8000007\b|not found/i.test(p.message))return null;throw p}}async ensureProject(u,p="main"){let h=await this.getProject(u);if(h)return h;return this.request("POST","/pages/projects",{name:u,production_branch:p})}async uploadToken(u){return(await this.request("GET",`/pages/projects/${u}/upload-token`)).jwt}async missingHashes(u,p){let h=await vs("POST","/pages/assets/check-missing",`Bearer ${u}`,{hashes:p});return new Set(h)}async upsertHashes(u,p){await vs("POST","/pages/assets/upsert-hashes",`Bearer ${u}`,{hashes:p})}async uploadBatch(u,p){let h=p.map((y)=>({key:y.hash,value:y.base64,metadata:{contentType:jg(y.extension)},base64:!0}));await vs("POST","/pages/assets/upload",`Bearer ${u}`,h)}async createDeployment(u,p,h){let y={};for(let v of p)y[v.path]=v.hash;let R=new FormData;if(R.append("manifest",JSON.stringify(y)),h)R.append("branch",h);return this.request("POST",`/pages/projects/${u}/deployments`,R)}async deployDirectory(u){let p=await gd(u.directory);if(p.length===0)throw Error(`No files to deploy in ${u.directory}`);let h=await this.uploadToken(u.project),y=await this.missingHashes(h,p.map((z)=>z.hash)),R=p.filter((z)=>y.has(z.hash)),v=[];for(let z=0;z<R.length;z+=100)v.push(R.slice(z,z+100));let P=0;for(let z=0;z<v.length;z+=4){let fe=v.slice(z,z+4);await Promise.all(fe.map((me)=>this.uploadBatch(h,me))),P+=fe.reduce((me,bt)=>me+bt.length,0),u.onProgress?.(P,R.length)}return await this.upsertHashes(h,p.map((z)=>z.hash)),{deployment:await this.createDeployment(u.project,p,u.branch),total:p.length,uploaded:R.length,uploadedBytes:R.reduce((z,fe)=>z+fe.size,0)}}async listCustomDomains(u){return(await this.request("GET",`/pages/projects/${u}/domains`)).map((h)=>h.name)}async attachCustomDomain(u,p){if((await this.listCustomDomains(u)).includes(p))return!1;return await this.request("POST",`/pages/projects/${u}/domains`,{name:p}),!0}}function Gg(u,p){return{type:"CNAME",name:u,value:p.endsWith(".pages.dev")?p:`${p}.pages.dev`,ttl:1,proxied:!0}}async function pd(u,p){let{blake3:h}=await import("./chunk-xd67tr7p.js").then((m)=>BS(m.default,1));return(await h(u+p)).slice(0,32)}async function gd(u){let{readdir:p}=await import("node:fs/promises"),{join:h,relative:y,sep:R}=await import("node:path"),v=[];async function P(L){let z=await p(L,{withFileTypes:!0});for(let fe of z){let me=h(L,fe.name);if(fe.isDirectory()){await P(me);continue}if(!fe.isFile())continue;let bt=`/${y(u,me).split(R).join("/")}`;if(Ug.has(bt))continue;let It=await Bun.file(me).bytes();if(It.byteLength>26214400)throw Error(`${bt} is ${It.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let mt=Buffer.from(It).toString("base64"),Me=fe.name.lastIndexOf("."),ze=Me>0?fe.name.slice(Me+1):"";v.push({path:bt,hash:await pd(mt,ze),base64:mt,extension:ze,size:It.byteLength})}}return await P(u),v.sort((L,z)=>L.path.localeCompare(z.path)),v}function jg(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 vs(u,p,h,y){let R={Authorization:h},v;if(y instanceof FormData)v=y;else if(y!==void 0)R["Content-Type"]="application/json",v=JSON.stringify(y);let P=await fetch(`https://api.cloudflare.com/client/v4${p}`,{method:u,headers:R,body:v}),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 Kg}from"node:crypto";var tp="https://api.cloudflare.com/client/v4",rp=10042,qg=10006,Zg=10059;class Fn extends Error{status;errors;constructor(u,p,h=[]){super(u);this.name="R2ApiError",this.status=p,this.errors=h}hasCode(u){return this.errors.some((p)=>p.code===u)}}class hn extends Fn{accountId;constructor(u,p,h=[]){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.`,p,h);this.name="R2NotEnabledError",this.accountId=u}}class ai{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??((p,h)=>fetch(p,h))}async requestEnvelope(u,p,h,y={}){let R={Authorization:`Bearer ${this.apiToken}`};if(h!==void 0)R["Content-Type"]="application/json";if(y.jurisdiction&&y.jurisdiction!=="default")R["cf-r2-jurisdiction"]=y.jurisdiction;let v=await this.fetchImpl(`${tp}/accounts/${this.accountId}/r2${p}`,{method:u,headers:R,body:h===void 0?void 0:JSON.stringify(h)}),P=await v.text(),L;try{L=JSON.parse(P)}catch{throw new Fn(`Cloudflare R2 API returned ${v.status} with a non-JSON body: ${P.slice(0,200)}`,v.status)}if(!L.success){let z=L.errors??[];if(z.some((me)=>me.code===rp))throw new hn(this.accountId,v.status,z);let fe=z.map((me)=>`${me.code}: ${me.message}`).join(", ");throw new Fn(`Cloudflare R2 API error (${v.status}) on ${u} ${p}: ${fe||P.slice(0,200)}`,v.status,z)}return L}async request(u,p,h,y){return(await this.requestEnvelope(u,p,h,y)).result}bucketPath(u){return`/buckets/${encodeURIComponent(u)}`}async listBuckets(u={}){let p=[],h;do{let y=new URLSearchParams({per_page:"1000"});if(h)y.set("cursor",h);let R=await this.requestEnvelope("GET",`/buckets?${y}`,void 0,u),v=R.result?.buckets??[];p.push(...v),h=v.length>0?R.result_info?.cursor||void 0:void 0}while(h);return p}async getBucket(u,p={}){try{return await this.request("GET",this.bucketPath(u),void 0,p)}catch(h){if(h instanceof hn)throw h;if(h instanceof Fn&&(h.hasCode(qg)||h.status===404))return null;throw h}}async ensureBucket(u,p={}){let h={jurisdiction:p.jurisdiction},y=await this.getBucket(u,h);if(y)return{bucket:y,created:!1};let R={name:u};if(p.locationHint)R.locationHint=p.locationHint;let v=await this.request("POST","/buckets",R,h);return{bucket:{...v,name:v?.name||u},created:!0}}async getCors(u,p={}){try{return(await this.request("GET",`${this.bucketPath(u)}/cors`,void 0,p))?.rules??[]}catch(h){if(h instanceof Fn&&!(h instanceof hn)&&(h.hasCode(Zg)||h.status===404))return[];throw h}}async putCors(u,p,h={}){if(p.length===0){await this.request("DELETE",`${this.bucketPath(u)}/cors`,void 0,h);return}await this.request("PUT",`${this.bucketPath(u)}/cors`,{rules:p},h)}async ensureCors(u,p,h={}){let y=await this.getCors(u,h);if(xs(y,p))return!1;return await this.putCors(u,p,h),!0}async getLifecycle(u,p={}){return(await this.request("GET",`${this.bucketPath(u)}/lifecycle`,void 0,p))?.rules??[]}async putLifecycle(u,p,h={}){await this.request("PUT",`${this.bucketPath(u)}/lifecycle`,{rules:p},h)}async ensureLifecycle(u,p,h={}){let y=await this.getLifecycle(u,h);if(Fs(y,p))return!1;return await this.putLifecycle(u,p,h),!0}async listCustomDomains(u,p={}){return(await this.request("GET",`${this.bucketPath(u)}/domains/custom`,void 0,p))?.domains??[]}async attachCustomDomain(u,p,h={}){return this.request("POST",`${this.bucketPath(u)}/domains/custom`,{domain:p.domain,zoneId:p.zoneId,enabled:p.enabled??!0,minTLS:p.minTLS??"1.2"},h)}async updateCustomDomain(u,p,h,y={}){return this.request("PUT",`${this.bucketPath(u)}/domains/custom/${encodeURIComponent(p)}`,h,y)}async ensureCustomDomain(u,p,h={},y){let R=p.minTLS??"1.2",P=(y??await this.listCustomDomains(u,h)).find((fe)=>fe.domain.toLowerCase()===p.domain.toLowerCase());if(!P){let fe=await this.attachCustomDomain(u,{...p,minTLS:R,enabled:!0},h);return{action:"attached",domain:{...fe,domain:fe?.domain||p.domain}}}let L=P.minTLS??"1.0";if(P.enabled&&L===R)return{action:"unchanged",domain:P};let z=await this.updateCustomDomain(u,P.domain,{enabled:!0,minTLS:R},h);return{action:"updated",domain:{...P,...z}}}async getManagedDomain(u,p={}){return this.request("GET",`${this.bucketPath(u)}/domains/managed`,void 0,p)}async setManagedDomain(u,p,h={}){let y=await this.getManagedDomain(u,h);if(y?.enabled===p)return{changed:!1,domain:y};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(u)}/domains/managed`,{enabled:p},h)}}}function np(u){return`https://${u}.r2.cloudflarestorage.com`}async function Jg(u){let{apiToken:p,accountId:h}=u;if(!p)throw Error("r2S3Credentials needs an API token");if(!h)throw Error("r2S3Credentials needs an account id");let y=u.fetch??((P,L)=>fetch(P,L)),R=[],v;for(let P of[`/accounts/${h}/tokens/verify`,"/user/tokens/verify"]){let L=await y(`${tp}${P}`,{method:"GET",headers:{Authorization:`Bearer ${p}`}}),z=await L.json().catch(()=>null);if(L.ok&&z?.success&&z.result?.id){v=z.result.id;break}let fe=z?.errors?.map((me)=>`${me.code}: ${me.message}`).join(", ");R.push(`${P} -> ${L.status}${fe?` (${fe})`:""}`)}if(!v)throw Error(`Could not verify the Cloudflare API token to derive R2 credentials: ${R.join("; ")}`);return{accessKeyId:v,secretAccessKey:Kg("sha256").update(p).digest("hex"),endpoint:np(h),region:"auto"}}function Ni(u){if(Array.isArray(u))return`[${u.map(Ni).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${Ni(y)}`).join(",")}}`;return JSON.stringify(u)}function ep(u,p){let h=(y)=>y&&y.length>0?[...y].map(String).sort():void 0;return{id:p?u.id:void 0,allowed:{origins:h(u.allowed?.origins),methods:h(u.allowed?.methods?.map((y)=>y.toUpperCase())),headers:h(u.allowed?.headers?.map((y)=>y.toLowerCase()))},exposeHeaders:h(u.exposeHeaders?.map((y)=>y.toLowerCase())),maxAgeSeconds:u.maxAgeSeconds}}function xs(u,p){if(u.length!==p.length)return!1;return p.every((h,y)=>{let R=h.id!==void 0;return Ni(ep(u[y],R))===Ni(ep(h,R))})}function Fs(u,p){if(u.length!==p.length)return!1;let h=(y)=>Ni([...y].map((R)=>({...R,storageClassTransitions:R.storageClassTransitions?.length?R.storageClassTransitions:void 0})).sort((R,v)=>R.id.localeCompare(v.id)));return h(u)===h(p)}var Yg="r2 cache",Xg=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function Qg(u,p={}){let h=p.log??(()=>{}),y={buckets:[],warnings:[]},R=u.infrastructure?.r2??u.r2,v=Object.entries(R?.buckets??{});if(v.length===0)return h("R2: no buckets declared, skipping."),y;if(!p.apiToken||!p.accountId){let me=[!p.apiToken&&"CLOUDFLARE_API_TOKEN",!p.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),bt=`R2: ${v.length} bucket(s) declared but ${me} is not set, skipping.`;return h(bt),y.warnings.push(bt),y}let P=p.dryRun===!0,L=new ai({apiToken:p.apiToken,accountId:p.accountId,fetch:p.fetch}),z=new H(p.apiToken,{zoneId:p.zoneId,accountId:p.accountId}),fe=new Map;for(let[me,bt]of v){let It=bt?.name;if(!It||!Xg.test(It)){y.warnings.push(`R2: bucket '${me}' has an invalid name '${It??""}' (3-63 chars: lowercase letters, digits, hyphens), skipping.`);continue}h(`R2: ${P?"checking":"reconciling"} bucket ${It}...`);let mt={name:It,changes:[],domains:[]};if(y.buckets.push(mt),await hh(bt,{r2:L,cloudflare:z,dryRun:P,summary:mt,warnings:y.warnings,claimed:fe,log:h}),mt.changes.length===0)h(`R2: ${It} is in sync.`);else for(let Me of mt.changes)h(`R2: ${It}: ${Me}`)}return y}async function hh(u,p){let{r2:h,dryRun:y,summary:R,warnings:v}=p,P=u.name,L={jurisdiction:u.jurisdiction},z=(mt,Me)=>{let ze=y?Me&&`would ${Me}`:mt;if(ze)R.changes.push(ze)},fe;if(y)fe=await h.getBucket(P,L)!==null;else{let{created:mt}=await h.ensureBucket(P,{locationHint:u.locationHint,jurisdiction:u.jurisdiction});if(fe=!0,mt)z("created","")}if(!fe)z("","create bucket");let me=Ch(u.customDomains);await ro(p,`cors on ${P}`,async()=>{if(!u.cors)return;if(!fe){z("cors updated","set cors");return}let mt=await h.getCors(P,L);if(xs(mt,u.cors))return;if(!y)await h.putCors(P,u.cors,L);z(u.cors.length===0?"cors removed":"cors updated",u.cors.length===0?"remove cors":"update cors")}),await ro(p,`lifecycle on ${P}`,async()=>{if(!u.lifecycle)return;let mt=u.lifecycle.map(ap);if(fe){let Me=await h.getLifecycle(P,L);if(Fs(Me,mt))return}if(!y)await h.putLifecycle(P,mt,L);z("lifecycle updated","update lifecycle")}),await ro(p,`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 h.getManagedDomain(P,L))?.enabled===mt)return;if(!y)await h.setManagedDomain(P,mt,L);z(mt?"r2.dev URL enabled":"r2.dev URL disabled",mt?"enable r2.dev URL":"disable r2.dev URL")});let bt=[];if(me.length>0&&fe)try{bt=await h.listCustomDomains(P,L)}catch(mt){if(mt instanceof hn)throw mt;v.push(`R2: could not list custom domains on ${P}: ${Kc(mt)}`)}let It=new Map;for(let{domain:mt,minTLS:Me}of me){let ze=p.claimed.get(mt);if(ze&&ze!==P){v.push(`R2: ${mt} is declared on both ${ze} and ${P}; leaving it on ${ze}.`);continue}p.claimed.set(mt,P);let j=bt.find((G)=>G.domain.toLowerCase()===mt),yt=Me??"1.2";if(j&&j.enabled&&(j.minTLS??"1.0")===yt){if(R.domains.push({domain:mt,status:jc(j)}),j.zoneId)It.set(mt,j.zoneId);continue}await ro(p,`custom domain ${mt} on ${P}`,async()=>{if(j){if(!y)await h.updateCustomDomain(P,j.domain,{enabled:!0,minTLS:yt},L);if(z(`custom domain ${mt} updated`,`update custom domain ${mt}`),R.domains.push({domain:mt,status:jc({...j,enabled:!0})}),j.zoneId)It.set(mt,j.zoneId);return}let G=await p.cloudflare.zoneIdFor(mt);if(It.set(mt,G),!y)await h.ensureCustomDomain(P,{domain:mt,zoneId:G,minTLS:yt},L,bt);z(`custom domain ${mt} attached`,`attach custom domain ${mt}`),R.domains.push({domain:mt,status:y?"not attached":"pending"})},()=>R.domains.push({domain:mt,status:"error"}))}if(u.cache&&me.length>0)await yh(u,me.map((mt)=>mt.domain).filter((mt)=>p.claimed.get(mt)===P),It,p,z)}async function yh(u,p,h,y,R){let v=ip(u.cache);if(!v||p.length===0)return;let P=new Map;for(let L of p){let z=h.get(L);if(!z)try{z=await y.cloudflare.zoneIdFor(L)}catch(fe){y.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:`${jt} ${Yg}`,expression:`(${qt(L)})`,enabled:!0,action_parameters:v};await ro(y,`cache rule for ${L.join(", ")}`,async()=>{let fe=await y.cloudflare.getPhaseRules(L[0],"http_request_cache_settings");if(sp(fe,z))return;if(!y.dryRun){let me=await y.cloudflare.putManagedPhaseRules(L[0],"http_request_cache_settings",[z]);if(!me.success)throw Error(me.message||"cache rule write failed")}R(`cache rule updated for ${L.join(", ")}`,`update cache rule for ${L.join(", ")}`)})}}function ip(u){if(u.edgeTtl===void 0&&u.browserTtl===void 0)return null;let p={cache:!0};if(u.edgeTtl!==void 0)p.edge_ttl={mode:"override_origin",default:u.edgeTtl};if(u.browserTtl!==void 0)p.browser_ttl={mode:"override_origin",default:u.browserTtl};return p}function sp(u,p){let h=zt(p.expression),y=zn(p.expression),R=(L)=>(L.description||"").startsWith(jt),v=(L)=>L.action===p.action&&L.description===p.description&&(L.enabled??!0)===(p.enabled??!0)&&zn(L.expression)===y&&Ms(L.action_parameters)===Ms(p.action_parameters),P=!1;for(let L of u){if(!R(L))continue;let z=zt(L.expression);if(!h.some((me)=>z.includes(me)))continue;if(v(L)&&h.every((me)=>z.includes(me))&&!P){P=!0;continue}return!1}return P}function ap(u){let p={id:u.id,enabled:u.enabled??!0,conditions:{prefix:u.prefix??""}};if(u.expireAfterDays!==void 0)p.deleteObjectsTransition={condition:{type:"Age",maxAge:Gc(u.expireAfterDays)}};else if(u.expireOn!==void 0)p.deleteObjectsTransition={condition:{type:"Date",date:u.expireOn}};if(u.abortMultipartUploadsAfterDays!==void 0)p.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:Gc(u.abortMultipartUploadsAfterDays)}};if(u.infrequentAccessAfterDays!==void 0)p.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:Gc(u.infrequentAccessAfterDays)}}];return p}function Gc(u){return Math.round(u*86400)}function Ch(u){let p=new Set,h=[];for(let y of u??[]){let R=typeof y==="string"?{domain:y}:y,v=R.domain?.trim().replace(/\.$/,"").toLowerCase();if(!v||p.has(v))continue;p.add(v),h.push({domain:v,minTLS:R.minTLS})}return h}function jc(u){if(!u.enabled)return"disabled";let p=u.status?.ownership,h=u.status?.ssl;if(p==="active"&&h==="active")return"active";for(let y of[p,h])if(y==="error"||y==="blocked"||y==="deactivated")return y;return"pending"}async function ro(u,p,h,y){try{await h()}catch(R){if(R instanceof hn)throw R;u.warnings.push(`R2: ${p} failed: ${Kc(R)}`),y?.()}}function Kc(u){return u instanceof Error?u.message:String(u)}function Ms(u){if(Array.isArray(u))return`[${u.map(Ms).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${Ms(y)}`).join(",")}}`;return JSON.stringify(u)}import{basename as wh,extname as Ih}from"node:path";import{createHash as Sh}from"node:crypto";var Rh="https://api.cloudflare.com/client/v4",$n="TS_CLOUD_CONTENT_HASH",no="2025-09-01",Zc="application/javascript+module",bh=10007,Ah=[1e4,9109];class li extends Error{status;errors;constructor(u,p,h=[]){super(u);this.name="WorkersApiError",this.status=p,this.errors=h}hasCode(u){return this.errors.some((p)=>p.code===u)}}class Bs extends li{permission;constructor(u,p,h,y=[]){super(`The Cloudflare API token is missing the "${u}" permission (${p}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,h,y);this.name="WorkersPermissionError",this.permission=u}}class Zs{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??((p,h)=>fetch(p,h))}async request(u,p,h){let y={Authorization:`Bearer ${this.apiToken}`},R;if(h instanceof FormData)R=h;else if(h!==void 0)y["Content-Type"]="application/json",R=JSON.stringify(h);let v=await this.fetchImpl(`${Rh}/accounts/${this.accountId}/workers${p}`,{method:u,headers:y,body:R}),P=await v.text(),L;try{L=JSON.parse(P)}catch{throw new li(`Cloudflare Workers API returned ${v.status} with a non-JSON body: ${P.slice(0,200)}`,v.status)}if(!L.success){let z=L.errors??[],fe=z.map((me)=>`${me.code}: ${me.message}`).join(", ");if(Ph(v.status,z))throw new Bs($h(p),`${u} ${p} -> ${v.status}${fe?`, ${fe}`:""}`,v.status,z);throw new li(`Cloudflare Workers API error (${v.status}) on ${u} ${p}: ${fe||P.slice(0,200)}`,v.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(p){if(p instanceof Bs)throw p;if(p instanceof li&&(p.hasCode(bh)||p.status===404))return null;throw p}}async getScript(u){return this.getSettings(u)}async uploadModuleScript(u,p){return this.request("PUT",this.scriptPath(u),lp(p))}async ensureModuleScript(u,p){let h=so(p),y=await this.getSettings(u);if(y&&Ja(y,p,h))return{action:"unchanged",hash:h};return await this.uploadModuleScript(u,up(p,h)),{action:y?"updated":"created",hash:h}}async listCustomDomains(u={}){let p=new URLSearchParams;if(u.service)p.set("service",u.service);if(u.hostname)p.set("hostname",u.hostname);if(u.zoneId)p.set("zone_id",u.zoneId);let h=p.toString(),y=h?`?${h}`:"";return await this.request("GET",`/domains${y}`)??[]}async attachCustomDomain(u,p){let h={hostname:u,service:p.service,environment:p.environment??"production"};if(p.zoneId)h.zone_id=p.zoneId;return this.request("PUT","/domains",h)}async detachCustomDomain(u){await this.request("DELETE",`/domains/${encodeURIComponent(u)}`)}async ensureCustomDomain(u,p,h){let R=(h??await this.listCustomDomains({hostname:u})).find((P)=>P.hostname.toLowerCase()===u.toLowerCase());if(R&&R.service===p.service)return{action:"unchanged",domain:R};if(R)throw Error(`${u} is attached to the Worker '${R.service}'. Detach it there first (Workers & Pages, ${R.service}, Settings, Domains & Routes); ts-cloud does not move it.`);let v=await this.attachCustomDomain(u,p);return{action:"attached",domain:{...v,hostname:v?.hostname||u}}}}function Ph(u,p){if(p.some((h)=>Ah.includes(h.code)))return!0;return(u===401||u===403)&&p.length===0}function $h(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((y)=>y.name===u.mainModule))throw Error(`Worker main module '${u.mainModule}' is not one of the uploaded modules`);let p={main_module:u.mainModule,bindings:u.bindings??[],compatibility_date:u.compatibilityDate??no,compatibility_flags:u.compatibilityFlags??[],keep_bindings:["secret_text"]},h=new FormData;h.append("metadata",JSON.stringify(p));for(let y of u.modules)h.append(y.name,new Blob([y.content],{type:y.type}),y.name);return h}function so(u){let p={mainModule:u.mainModule,modules:[...u.modules].sort((h,y)=>h.name.localeCompare(y.name)).map((h)=>({name:h.name,type:h.type,sha256:cp(h.content)})),bindings:[...u.bindings??[]].filter((h)=>h.name!==$n).sort((h,y)=>h.name.localeCompare(y.name)),compatibilityDate:u.compatibilityDate??no,compatibilityFlags:[...u.compatibilityFlags??[]].sort()};return cp(qc(p))}function up(u,p=so(u)){return{...u,bindings:[...(u.bindings??[]).filter((h)=>h.name!==$n),{type:"plain_text",name:$n,text:p}]}}function Ja(u,p,h){let y=u.bindings??[],R=y.find((v)=>v.name===$n&&v.type==="plain_text");if(!R||R.text!==h)return!1;return(p.bindings??[]).every((v)=>{let P=y.find((z)=>z.name===v.name);if(!P||P.type!==v.type)return!1;let L=v.type==="r2_bucket"?"bucket_name":v.type==="plain_text"?"text":void 0;return!L||P[L]===v[L]})}function cp(u){return Sh("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(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${qc(y)}`).join(",")}}`;return JSON.stringify(u)}async function Jc(u){if(!await Bun.file(u).exists())throw Error(`Worker entry not found: ${u}`);let p;try{p=await Bun.build({entrypoints:[u],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(R){throw Error(`Bundling Worker ${u} failed: ${Dh(R)}`)}if(!p.success)throw Error(`Bundling Worker ${u} failed: ${p.logs.map((R)=>String(R.message??R)).join("; ")}`);if(p.outputs.length!==1)throw Error(`Bundling Worker ${u} produced ${p.outputs.length} files (${p.outputs.map((R)=>R.path).join(", ")}); a Worker is uploaded as a single module, so remove the dynamic imports or asset imports that split it.`);let h=p.outputs[0];if(h.kind!=="entry-point")throw Error(`Bundling Worker ${u} produced a ${h.kind} instead of an entry module`);let y=await h.text();return{name:`${wh(u,Ih(u))}.js`,content:y,type:Zc,size:new TextEncoder().encode(y).byteLength}}function Dh(u){if(u instanceof AggregateError&&u.errors.length>0)return u.errors.map((p)=>p instanceof Error?p.message:String(p?.message??p)).join("; ");return u instanceof Error?u.message:String(u)}import{isAbsolute as kh,resolve as Oh}from"node:path";var Nh="https://api.cloudflare.com/client/v4",xh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function Lh(u,p={}){let h=p.log??(()=>{}),y={workers:[],warnings:[]},R=Object.entries(u.infrastructure?.workers??u.workers??{});if(R.length===0)return h("Workers: none declared, skipping."),y;if(!p.apiToken||!p.accountId){let L=[!p.apiToken&&"CLOUDFLARE_API_TOKEN",!p.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),z=`Workers: ${R.length} Worker(s) declared but ${L} is not set, skipping.`;return h(z),y.warnings.push(z),y}let v=u.infrastructure?.r2??u.r2,P={workers:new Zs({apiToken:p.apiToken,accountId:p.accountId,fetch:p.fetch}),r2:new ai({apiToken:p.apiToken,accountId:p.accountId,fetch:p.fetch}),cloudflare:new H(p.apiToken,{zoneId:p.zoneId,accountId:p.accountId}),apiToken:p.apiToken,fetch:p.fetch??((L,z)=>fetch(L,z)),projectRoot:p.projectRoot??process.cwd(),dryRun:p.dryRun===!0,warnings:y.warnings,log:h,r2ConfigDomains:zh(v),r2Buckets:v,claimed:new Map};for(let[L,z]of R){let fe=z?.name;if(!fe||!xh.test(fe)){y.warnings.push(`Workers: '${L}' has an invalid name '${fe??""}' (1-63 chars: lowercase letters, digits, '-' and '_'), skipping.`);continue}if(!z.entry){y.warnings.push(`Workers: ${fe} has no entry, skipping.`);continue}h(`Workers: ${P.dryRun?"checking":"reconciling"} ${fe}...`);let me={name:fe,changes:[],domains:[]};y.workers.push(me),await Fh(z,me,P);for(let bt of me.changes)h(`Workers: ${fe}: ${bt}`)}return y}async function Fh(u,p,h){let y=u.name,R=kh(u.entry)?u.entry:Oh(h.projectRoot,u.entry),v;try{v=await Jc(R)}catch(L){throw Error(`Worker ${y}: ${di(L)}`)}p.changes.push(`bundled ${Uh(v.size)}`);let P={mainModule:v.name,modules:[{name:v.name,content:v.content,type:v.type}],bindings:dp(u,h),compatibilityDate:u.compatibilityDate??no,compatibilityFlags:u.compatibilityFlags??[]};if(h.dryRun){let L=await h.workers.getSettings(y);p.changes.push(L&&Ja(L,P,so(P))?"unchanged":"would upload")}else{let{action:L}=await h.workers.ensureModuleScript(y,P);p.changes.push(L==="unchanged"?"unchanged":"uploaded")}for(let L of Hh(u.customDomains))await _h(y,L,p,h)}async function _h(u,p,h,y){let R=(mt)=>{h.domains.push({domain:p,status:mt})},v=(mt)=>{y.warnings.push(`Workers: ${mt}`),R("conflict")},P=y.claimed.get(p);if(P&&P!==u){v(`${p} is declared on both ${P} and ${u}; leaving it on ${P}.`);return}y.claimed.set(p,u);let L=y.r2ConfigDomains.get(p);if(L){v(`${p} 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(y);if(z===null){R("error");return}let fe=z.find((mt)=>mt.hostname.toLowerCase()===p);if(fe?.service===u){R("active");return}if(fe){v(`${p} 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 Wh(y))?.get(p);if(me){v(`${p} 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 bt;try{bt=await y.cloudflare.zoneIdFor(p)}catch(mt){y.warnings.push(`Workers: could not resolve the zone for ${p}, not attached: ${di(mt)}`),R("error");return}let It=await Vh(y,bt,p);if(It.length>0){let mt=It.map((Me)=>`${Me.type} ${Me.content}`).join(", ");v(`${p} 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(y.dryRun){h.changes.push(`would attach custom domain ${p}`),R("not attached");return}try{await y.workers.ensureCustomDomain(p,{service:u,zoneId:bt},z),h.changes.push(`custom domain ${p} attached`),z.push({id:"",hostname:p,service:u,zone_id:bt}),R("pending")}catch(mt){y.warnings.push(`Workers: custom domain ${p} on ${u} failed: ${di(mt)}`),R("error")}}async function Bh(u){if(u.attached!==void 0)return u.attached;try{u.attached=await u.workers.listCustomDomains()}catch(p){u.warnings.push(`Workers: could not list Worker custom domains, none attached: ${di(p)}`),u.attached=null}return u.attached}async function Wh(u){if(u.r2AccountDomains!==void 0)return u.r2AccountDomains;let p=new Map;try{let h=(await u.r2.listBuckets()).map((y)=>({name:y.name}));for(let y of Object.values(u.r2Buckets?.buckets??{}))if(y.jurisdiction&&y.jurisdiction!=="default")h.push({name:y.name,jurisdiction:y.jurisdiction});for(let y of h){let R=await u.r2.listCustomDomains(y.name,{jurisdiction:y.jurisdiction}).catch(()=>[]);for(let v of R)p.set(v.domain.toLowerCase(),y.name)}u.r2AccountDomains=p}catch(h){u.log(`Workers: could not check R2 custom domains (${di(h)}); relying on the DNS check.`),u.r2AccountDomains=null}return u.r2AccountDomains}async function Vh(u,p,h){try{let y=await u.fetch(`${Nh}/zones/${p}/dns_records?name=${encodeURIComponent(h)}&per_page=100`,{method:"GET",headers:{Authorization:`Bearer ${u.apiToken}`}}),R=await y.json();if(!R?.success)throw Error(`HTTP ${y.status}`);return(R.result??[]).filter((v)=>v.name?.toLowerCase()===h).map((v)=>({type:v.type??"?",content:v.content??""}))}catch(y){return u.log(`Workers: could not read DNS records for ${h} (${di(y)}); attaching anyway.`),[]}}function dp(u,p){let h=[],y=new Set,R=(P)=>{if(P===$n)return p.warnings.push(`Workers: ${u.name}: binding name ${$n} is reserved for ts-cloud, ignored.`),!1;if(y.has(P))return p.warnings.push(`Workers: ${u.name}: binding ${P} is declared twice; the first one wins.`),!1;return y.add(P),!0},v=new Map;for(let P of Object.values(p.r2Buckets?.buckets??{}))if(P.jurisdiction&&P.jurisdiction!=="default")v.set(P.name,P.jurisdiction);for(let[P,L]of Object.entries(u.bindings?.r2Buckets??{})){if(!R(P))continue;let z=v.get(L);h.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(R(P))h.push({type:"plain_text",name:P,text:String(L)});return h}function zh(u){let p=new Map;for(let h of Object.values(u?.buckets??{}))for(let y of h?.customDomains??[]){let R=pp(typeof y==="string"?y:y.domain);if(R)p.set(R,h.name)}return p}function Hh(u){return[...new Set((u??[]).map(pp).filter(Boolean))]}function pp(u){return(u??"").trim().replace(/\.$/,"").toLowerCase()}function Uh(u){if(u<1024)return`${u} B`;if(u<1048576)return`${(u/1024).toFixed(1)} KB`;return`${(u/1024/1024).toFixed(1)} MB`}function di(u){return u instanceof Error?u.message:String(u)}export{Pl as ABTestManager,ye as ACMClient,Br as ACMDnsValidator,ld as ACME_DIRECTORIES,Oe as AI,uu as API_IDEMPOTENCY_TTL_MS,du as API_TOKEN_DEFAULT_TTL_MS,lu as API_TOKEN_MAX_TTL_MS,ms as API_VERSION,Ie as AUTHORIZATION_CAPABILITIES,su as AUTH_ACTION_TOKEN_TTL_MS,ou as AUTH_MFA_CHALLENGE_TTL_MS,au as AUTH_OIDC_TRANSACTION_TTL_MS,it as AUTH_SESSION_ABSOLUTE_TTL_MS,iu as AUTH_SESSION_IDLE_TTL_MS,Ey as AWSAPIError,n as AWSClient,A as AWSCloudFormationClient,I as AWSCloudFrontClient,Tl as AWSConfigManager,JI as AWS_PSEUDO_PARAMETERS,_e as AWS_REGIONS,Fg as AcmeClient,nn as AlertEvaluator,Gi as AlertStore,No as AnomalyConfigStore,ml as ApiGateway,i as ApiServiceError,vc as ApplicationAutoScalingClient,un as Arn,_ as AssetHasher,Y as Auth,ds as AuthenticationStore,Ki as AutomationApiService,ls as AutomationIdentityStore,Ba as AwsAuroraDataAdapter,$a as AwsAuroraTransport,tc as AwsDatabaseBackupSource,_r as AwsDriver,xa as AwsElastiCacheDataAdapter,Ma as AwsElastiCacheTransport,Zf as AwsIamCapabilityScanner,oc as AwsInfrastructureBackupSource,Na as AwsRdsDataAdapter,La as AwsRdsTransport,gh as AwsRegionalDriver,cc as AwsSecretsManagerConfigurationBackend,fm as AwsSpendTransport,dc as AwsSsmConfigurationBackend,Ts as BackupCoordinator,El as BackupManager,Za as BackupStore,Df as BatchProcessingManager,Hn as BedrockClient,Qn as BedrockRuntimeClient,yu as BitbucketSourceAdapter,Dl as BlueGreenManager,yf as BounceComplaintHandler,df as BuildOptimizationManager,Uu as BunDockerRuntime,hg as BunDockerVolumeRuntime,fg as BunFilesystemArchiveRuntime,Ce as CDN,Jo as CHAIN_HEADER,jt as CLOUDFLARE_MANAGED_RULE_PREFIX,dl as CLOUDFRONT_FAILOVER_STATUS_CODES,LC as COMMON_CROSS_ACCOUNT_ROLES,$n as CONTENT_HASH_BINDING,Ke as CONTROL_PLANE_SCHEMA_VERSION,Vo as Cache,rs as CanaryManager,of as CertificateManager,OA as CloudBlockVolumeDriver,io as CloudDriverFactory,tt as CloudError,Bm as CloudFormationBuilder,A as CloudFormationClient,I as CloudFrontClient,wl as CloudTrailManager,we as CloudWatchLogsClient,dd as CloudflarePagesProvider,H as CloudflareProvider,Vy as CommandHistory,ee as Communication,Yr as ComposeApplicationService,sr as ComposeApplicationStore,Qt as ComprehendClient,a as Compute,hm as ComputeSpendTransport,zo as ConfigurationError,uc as ConfigurationService,ac as ConfigurationStore,Mn as ConnectClient,_a as ContainerDataAdapter,Ol as ContainerRegistryManager,sc as ControlPlaneBackupSource,Wa as ControlPlaneCleanupDriver,Li as ControlPlaneStore,Do as CounterTracker,Bt as CredentialError,zm as CrossRegionReferenceManager,dy as DASHBOARD_ENTRY,ly as DASHBOARD_PORT_BASE,uy as DASHBOARD_PORT_SPAN,cy as DASHBOARD_STATE_DIR,sa as DEFAULT_ATTACK_MODE_HOURS,no as DEFAULT_COMPATIBILITY_DATE,Yd as DEFAULT_DDOS_THRESHOLDS,Im as DEFAULT_FAILOVER_STATUS_CODES,xd as DEFAULT_METER_MAPPINGS,Nd as DEFAULT_PRICE_BOOK,mn as DEFAULT_RECURSION_LIMITS,uo as DEFAULT_RPX_CERTS_DIR,te as DEFAULT_SERVICE_LIMITS,rl as DEFAULT_STATE_DIR,Pg as DEFAULT_STATIC_ASSET_EXTENSIONS,iy as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,zA as DEFAULT_TELEMETRY_POLICY,Zp as DEFAULT_THRESHOLDS,PA as DEPLOYMENT_QUEUE_KINDS,Wo as DEPTH_HEADER,tn as DETECTABLE_SIGNALS,_u as DIAGNOSTIC_PRESETS,Rf as DLQMonitoringManager,W as DNS,hf as DNSSECManager,ys as DataServiceLifecycle,ka as DataServiceStore,lr as Database,nf as DatabaseUserManager,q as DebugLogger,ny as DependencyGraph,Z as Deployment,Cy as DeploymentError,vl as DisasterRecoveryManager,Jn as DnsProviderFactory,Sr as DockerDataTransport,va as DockerDiscoveryAdapter,Xr as DockerNamedVolumeDriver,ic as DockerVolumeBackupSource,c as DurableOperationQueue,bo as DurableQueueWorker,Ue as DynamoDBClient,Gr as EC2Client,He as ECRClient,dt as ECSClient,Dr as EFSClient,Ic as ELBv2Client,LA as ENFORCEMENT_ACTIONS,Qi as ENFORCEMENT_DESCRIPTIONS,O as ENFORCEMENT_SEVERITY,Rp as ENVIRONMENT_LABEL,xu as EcsRuntimeAdapter,ia as EdgeRateLimiter,ut as ElastiCacheClient,f as Email,Cf as EmailAdvanced,Sf as EmailAnalyticsManager,jn as EmailClient,Ef as EmailHandlers,bf as EmailTemplateManager,Fa as EncryptedDataSecretStore,vy as ErrorCodes,wr as EventBridgeClient,dh as EventBridgeJobAdapter,lc as ExternalConfigurationBackend,Go as FAILOVER_REPLICA_POLICY_SID,wf as FIFOQueueManager,Gh as FLY_MACHINES_API,am as FOCUS_VERSION,Al as FileCache,Ze as FileSystem,rc as FilesystemBackupSource,Qa as FleetService,Ua as FleetStore,$s as FlyApiError,fp as FlyClient,e as Fn,Su as GiteaSourceAdapter,hu as GithubSourceAdapter,Au as GitlabSourceAdapter,Km as GlobalResourceManager,Ge as GoDaddyProvider,Rl as GuardDutyManager,Et as HOST_SITES_DIR,Dy as HashCache,Uf as HealthCheckManager,Je as HealthCheckRunner,Ur as HetznerClient,Pe as HetznerDriver,Re as IAMClient,Oc as IPV6_EXCLUDED_HOST_LABELS,cf as ImageScanningManager,vp as InfrastructureGenerator,Id as InvalidOperationTransitionError,kt as JobLoader,lh as JobProviderReconciler,Da as JobService,Pa as JobStore,Tr as KendraClient,Mf as LARAVEL_SERVERLESS_BUILD_STEPS,T as LambdaClient,gf as LambdaConcurrencyManager,ff as LambdaDLQManager,pf as LambdaDestinationsManager,lf as LambdaLayersManager,Ou as LambdaRuntimeAdapter,mf as LambdaVPCManager,uf as LambdaVersionsManager,xn as LocalEncryptedConfigurationBackend,nc as LogicalDatabaseBackupSource,Nl as LogsManager,uS as MANAGED_NODE_VERSIONS,id as MANAGEMENT_DASHBOARD_SITE,xm as MANAGEMENT_DASHBOARD_SITE_PREFIX,as as MAX_CONTROL_HOURS,bd as MAX_CONTROL_PLANE_ERROR_BYTES,Kp as MAX_CONTROL_PLANE_JSON_BYTES,To as METERS,_A as METER_KEYS,$A as MICRO_CENTS,em as MIN_PROJECTION_CONFIDENCE,Og as MTA_STS_PORT,Ka as MaintenanceService,za as MaintenanceStore,le as Messaging,ef as MetricsManager,tf as MigrationManager,Hm as MockCloudFormation,Vm as MockDynamoDB,Gm as MockS3,qo as Monitoring,Xm as MultiAccountManager,jm as MultiRegionManager,My as MultiStepProgress,S as Network,Qf as NetworkSecurityManager,Vi as NotificationRouter,Em as ORIGIN_CONNECTION_ATTEMPTS,vm as ORIGIN_CONNECTION_TIMEOUT,bm as ORIGIN_GROUP_ALLOWED_METHODS,zI as ORIGIN_GROUP_ID_SUFFIX,Cm as ORIGIN_GROUP_SELECTION_CRITERIA,bc as OpenSearchClient,vt as OptimisticConcurrencyError,Ym as OrganizationManager,Hg as PAGES_MAX_FILE_BYTES,bS as PHP_DEFAULT_EXCLUDES,gS as PHP_LAYER_EXTENSIONS,wp as PROJECT_LABEL,pt as PROXIABLE_RECORD_TYPES,D as ParameterStore,rf as PerformanceManager,de as Permissions,Cc as PersonalizeClient,et as Phone,vf as PhoneAdvanced,km as PhoneHandlers,Ga as PlacementService,Ha as PlacementStore,Gn as PollyClient,he as PorkbunProvider,Cn as PreDeployScanner,bl as PreviewEnvironmentManager,Jr as PreviewEnvironmentService,We as PreviewEnvironmentStore,Cl as PreviewNotificationService,$y as ProgressBar,kl as ProgressiveDeploymentManager,oa as ProtectionControlStore,ry as Pseudo,J as Queue,$i as QueueCancellationError,Pf as QueueManagementManager,LI as QueuePresets,Io as QueueTimeoutError,Fn as R2ApiError,hn as R2NotEnabledError,ai as R2Provider,rp as R2_NOT_ENABLED_ERROR_CODE,Jl as RATE_LIMIT_KEY_SEPARATOR,ne as RDSClient,jy as RECOMMENDED_ACCOUNT_STRUCTURES,_C as RECOMMENDED_SCPS,Wf as RELEASE_QUEUE_KINDS,Qy as REPL,Gy as REPLCommandBuilder,Hy as REPLContext,Dp as ROLE_LABEL,Py as RateLimiter,$I as RealtimePresets,cm as RecordingSpendTransport,is as RecursionGuard,Nt as Redirects,Wm as RegionPairManager,qa as RegionService,Va as RegionStore,Ye as Registry,Ht as RekognitionClient,xt as ReleaseService,fa as ReleaseStore,uh as RemoteBuildService,Bl as ReplicaManager,Hf as ResourceManagementManager,ae as RetryableOperationError,b as Route53Client,Sc as Route53DomainsClient,ie as Route53Provider,Af as Route53ResolverManager,Ll as Route53RoutingManager,ve as RuntimeOperationService,wa as RuntimeStreamRegistry,ec as S3BackupDestinationAdapter,o as S3Client,V as S3Error,Cu as SECRET_PATTERNS,sm as SENSITIVITY_THRESHOLDS,gt as SESClient,X as SMS,lt as SNSClient,mm as SPEND_CYCLE_SECONDS,jd as SPEND_GATE_SETTING,XA as SPEND_LEASE_SETTING,pe as SQSClient,ke as SSH_BOOTSTRAP_VERSION,hi as SSH_PREFLIGHT_SCRIPT,Be as SSMClient,ym as STATE_DIR_ENV_VAR,wi as STATIC_SITE_ZONE_SETTINGS,ul as STORAGE_FAILOVER_METADATA_KEY,Te as STSClient,Vn as SchedulerClient,ur as Search,En as SecretFindingScanner,Yi as Secrets,xl as SecretsManager,re as SecretsManagerClient,sf as SecretsRotationManager,E as Security,mr as SecurityHubManager,bn as SecurityPostureStore,Ot as SecurityScannerRunner,af as SecurityScanningManager,If as SenderReputationManager,ch as ServerCronJobAdapter,Oa as ServerDataAdapter,vo as ServerPathVolumeDriver,_l as ServiceMeshManager,pl as Sftp,xo as SignalSource,Tf as SmsAdvanced,Vt as SmsClient,Nm as SmsHandlers,Rc as SmsVoiceClient,ha as SourceConnectionStore,Ar as SourceProviderError,zd as SpendCapError,rn as SpendGate,gm as SpendLoopLease,Mo as SpendNotificationRouter,pm as SpendRunner,ar as SpendService,Fi as SpendStore,Fy as Spinner,Qr as SshDriver,wn as SshFleetDriver,Jm as StackDependencyManager,WI as StacksIntegration,Ff as StaticSiteManager,xe as Storage,zl as StorageAdvancedManager,qn as SupportClient,fr as SyntheticsManager,Qu as SystemFleetSshTransport,St as SystemSshTransport,Ta as SystemdDiscoveryAdapter,Xo as TRACE_HEADER,Uy as TaskList,Rt as TelemetryStore,al as TemplateBuilder,yl as TemplateCache,Gt as TextractClient,Un as TranscribeClient,vr as TranslateClient,fh as TransportDisasterRecoveryDriver,mh as TransportPlatformMaintenanceDriver,Ss as TransportRemoteBuildDriver,Ca as TrivyImageScanner,ma as TsCloudApiError,gu as TsCloudClient,JA as URGENT_SPEND_EVENTS,tm as USER_VISIBLE_ACTIONS,ja as UnavailableRegionalDriver,Ae as UnifiedDnsValidator,Ao as UnsupportedSchemaVersionError,$m as ValidationError,Rr as VoiceClient,Eo as VolumeService,ir as VolumeStore,Zc as WORKER_MODULE_TYPE,li as WorkersApiError,Bs as WorkersPermissionError,Zs as WorkersProvider,ay as Workflow,Zm as XRayManager,tS as abTestManager,pu as activateImmutableRelease,Ig as addDns01ChallengeRecord,Dn as addSiteToCloudConfig,Lt as ageSeconds,_d as aggregateDeltas,qp as allocateSitePorts,Pm as amazonLinuxImageId,oy as amazonLinuxImageParameter,qI as analyzeStackDiff,Hi as anomalyOptionsForSignal,aa as applyControlsToDdos,tu as applyControlsToRateLimits,Vs as applyDeclaredZoneSettings,gi as applyHetznerVolumes,an as applyMitigationFactor,lA as applyPlan,Ks as applyZoneMigration,$l as artifactKey,Dt as assertOriginGroupMethods,us as assertReleaseStrategy,jA as assertSpendAllows,fA as attachConflicts,hA as attachIsViable,mA as attachPreconditions,Ru as attachProvenanceToRelease,Ea as attachSbomToRelease,Tu as attachVulnerabilitySummary,zf as authEncryptionKeyFile,x as authorizeOrganization,oh as authorizeRuntimePath,uC as autocomplete,Wy as awsConfigManager,pg as backupCredentialStatus,zy as backupManager,Lb as batch,wE as batchProcessingManager,ga as beginOidcAuthorization,Zy as blueGreenManager,IE as bounceComplaintHandler,Tt as budgetWindow,hc as buildAndPushServerlessImage,PE as buildBunRuntimeLayerZip,CA as buildCertificatePackScript,SA as buildCertificateStateScript,EA as buildCertificateUnpackScript,fl as buildCloudFormationTemplate,Yc as buildCloudInitFirstBoot,Td as buildComposeLogsCommand,OI as buildComposeRuntimeCommand,_I as buildComposeScaleCommand,wd as buildComposeShellCommand,ti as buildComputeStorageInstallScript,Lr as buildComputeStorageSiteScript,Hp as buildDrainSourceScript,tA as buildDrainedSiteScanScript,gl as buildFailoverReplicaPolicyStatement,br as buildFunctionEnv,Qp as buildHealthGateScript,ni as buildHostCleanupDeployScript,to as buildHostCleanupInstallScript,ri as buildHostCleanupScript,Oi as buildHostSitePortsScript,Ji as buildMailEnv,ao as buildManagementDashboardArtifact,qS as buildMediaCdnPlan,xg as buildMtaStsPolicy,Mh as buildMtaStsServer,DE as buildNodeRuntimeLayerZip,uE as buildOptimizationManager,ll as buildOriginGroup,ln as buildOriginGroups,kc as buildOriginGuardRule,Op as buildPauseWorkersScript,xE as buildPhpRuntimeLayerZip,Dm as buildReplicationConfiguration,Rm as buildReplicationRole,Mp as buildRestoreScript,B as buildRpxConfig,Ne as buildRpxFragmentRefreshScript,gA as buildSetHostnameScript,si as buildSiteDeployScript,$p as buildSnapshotScript,Gp as buildSourceStateScript,ci as buildSshArgs,mi as buildSshBootstrapScript,Pc as buildStaticSiteCacheRules,oi as buildStaticSiteDeployScript,Fp as buildTargetStateScript,lp as buildUploadForm,_p as buildWorkersStateScript,Jc as bundleWorker,Pu as bytes,ip as cacheRuleParameters,eS as canaryManager,Rn as canonicalJson,_t as capabilities,Ir as capacity,qb as categorizeChanges,cE as certificateManager,bA as certificatesMatch,wb as checkIAMPermissions,Of as checkInvocation,Db as checkServiceQuotas,ky as chunk,pR as cleanupDns01Challenge,DS as clearSigningKeyCache,ya as cloneSourceBinding,Ny as cloudConfigSchema,op as cloudDrivers,Jy as cloudTrailManager,gd as collectAssets,ta as collectPhpAppEntries,kg as collectServerDnsDomains,Wp as completeComposeVolumeDeletion,pa as completeOidcAuthorization,mb as composePresets,So as composeProjectName,Fl as composeServerlessAppTemplate,ZA as compositeSpendTransport,Ut as compressBackup,_S as config,Dc as configOrigins,Mu as connectionGuidance,aS as containerRegistryManager,RA as controlPlaneDatabaseFile,yd as controlPlaneMigrations,rb as createApiBackendPreset,ba as createApiV1Handler,VS as createAsgBuildDriver,mg as createBackupQueueHandlers,IS as createCliHandler,F as createCloudDriver,ed as createCloudFrontPolicy,Cb as createCredentialProvider,gb as createDashboardSite,ab as createDataPipelinePreset,Fu as createDataServiceQueueHandlers,Rd as createDeploymentQueueHandlers,N as createDnsProvider,GS as createEcsBuildDriver,Kd as createEnforcementHandlers,Mm as createError,hl as createExistingStaticFullStackPreset,Hu as createFleetQueueHandlers,tb as createFullStackAppPreset,Xs as createGoDaddyValidator,BE as createHandlers,yS as createHttpHandler,ib as createJamstackPreset,$u as createJobQueueHandlers,lb as createLaravelPreset,cb as createMLApiPreset,Wu as createMaintenanceQueueHandlers,zS as createMediaAccessToken,sb as createMicroservicesPreset,Zb as createMockAWS,YI as createNodeJsServerPreset,ZI as createNodeJsServerlessPreset,Ls as createObjectStorageClient,Js as createPorkbunValidator,fb as createPreset,ra as createPresignedUrl,ES as createPresignedUrlAsync,SS as createQueueHandler,ob as createRealtimeAppPreset,Vu as createRegionQueueHandlers,wu as createReleaseProvenance,fu as createReleaseQueueHandlers,QS as createRemoteBuildQueueHandlers,Ys as createRoute53Validator,sh as createRuntimeAdapters,by as createS3Client,HS as createServerBuildDriver,ub as createServerlessLaravelPreset,eb as createServerlessNodePreset,Dg as createSmsInfrastructure,ot as createSourceAdapter,XI as createStaticSitePreset,db as createTraditionalWebAppPreset,Dd as createVolumeQueueHandlers,nb as createWordPressPreset,rt as createZip,SC as crossRegionReferenceManager,On as dashboardActions,oo as dashboardCredentialsFile,Tn as dataServiceCapabilities,oE as databaseUserManager,nu as decodeBase32,Fe as decompressBackup,Th as decryptBackup,ca as defaultConfig,Qm as defaultLocalConfig,Yl as defaultRateLimitRules,Nr as delegateZone,Hs as delegateZoneFromConfig,dg as deleteFailoverReplicaBuckets,mc as deleteStaticSite,od as deployAllComputeSites,Xa as deployServerlessApp,lg as deploySite,co as deploySiteRelease,Ps as deployStaticSite,fc as deployStaticSiteFull,_n as deployStaticSiteWithExternalDns,Ln as deployStaticSiteWithExternalDnsFull,Zh as deployToFly,ol as deploymentCoexistenceError,gy as deriveManagementDashboardPort,Gs as describeDelegation,eu as describePosture,qs as describeZoneSettings,ah as desiredJobProviderState,im as detectAnomalies,Sm as detectDeploymentTargets,Nc as detectDnsProvider,Gd as detectLatestAnomaly,vb as detectMisconfigurations,Kl as detectServiceRegion,Ed as diffCompose,Hb as diffTemplates,Aa as discoverGitRefs,ua as discoverOidcProvider,ku as discoverRuntimeInventory,TE as dlqMonitoringManager,Bc as dnsProviders,yE as dnssecManager,rh as dockerWorkloads,Is as documentDigest,jc as domainStatus,Ky as drManager,qe as driverStatePath,Nu as ecsWorkloads,nr as effectiveCapabilities,bE as emailAnalyticsManager,EE as emailTemplateManager,cs as encodeBase32,vh as encryptBackup,Du as ensureDefaultSecurityPolicies,og as ensureFailoverReplicaBuckets,Ei as ensureFirewall,Ri as ensureManagementDashboard,vi as ensureServer,Ci as ensureSshKey,oe as escapeSecLang,$d as evaluateBudget,yi as evaluatePreflight,$o as evaluateTelemetryAlertRules,Lu as eventBridgeScheduleInput,AS as eventToRequest,GA as ewma,Cd as exportCompose,js as exportRoute53Zone,_m as extendPreset,vE as fifoQueueManager,_b as findChangedFiles,Xp as findMapping,Jp as findPriceEntry,qh as flyDeployOptions,Qc as flyIpType,yp as flyMachineConfig,UC as formatAccountStructure,AA as formatAttachPlan,nC as formatBytes,sn as formatCents,jI as formatDiff,nA as formatDrainedSiteRefusal,iC as formatDuration,pC as formatFlagSuggestions,hC as formatHistory,AC as formatHistoryStats,aA as formatInventory,oC as formatKeyValue,sC as formatList,dA as formatPlan,Ii as formatPreflightFindings,rC as formatProgressBar,qy as formatRegion,NC as formatRegionList,Yf as formatScanResults,aC as formatSuggestion,eC as formatTable,en as formatTimeToExhaustion,tC as formatTree,Ay as fromEC2Metadata,yy as fromECSMetadata,fy as fromEnvironment,hy as fromSharedCredentials,Sy as fromWebIdentity,Hl as functionFingerprint,mo as gatewayHostnames,Ql as generateAppImageDockerfile,eE as generateApprovalConfig,kf as generateBootstrap,Oy as generateCleanupWorkflow,_y as generateCostReportWorkflow,MC as generateCrossAccountRoleCF,Eu as generateCycloneDxSbom,XC as generateDeploymentConfig,jC as generateDeploymentPipeline,QC as generateDeploymentWorkflow,pc as generateExternalDnsStaticSiteTemplate,uR as generateHttpsServerCode,vu as generateImageSbom,lR as generateLetsEncryptUserData,t as generateLogicalId,JC as generateManualPipeline,qC as generateMatrixWorkflow,YC as generateMultiEnvConfig,zC as generateMultiEnvPipeline,HC as generateMultiEnvWorkflow,GC as generatePRPreviewWorkflow,tE as generateParallelConfig,$f as generatePhpFpmConfig,Nf as generatePhpLayerDockerfile,KC as generatePreviewPipeline,xy as generatePreviewWorkflow,r as generateResourceName,ZC as generateScheduledConfig,WC as generateScheduledPipeline,VC as generateScheduledWorkflow,Ds as generateStaticSiteTemplate,M as generateUbuntuAppCloudInit,Lm as getAccountId,EC as getAllRegions,DC as getClosestRegion,mC as getCommandUsage,DA as getComposeTemplate,Vf as getConfig,dC as getContextualHelp,es as getCredentials,jb as getDeploymentStrategy,zb as getDiffStats,Gb as getDiffSummary,Ty as getErrorDetails,Il as getLocalConfig,Xb as getLocalCredentials,Jb as getLocalEndpoint,Yb as getLocalEnvVars,Pb as getQuotaUsageSummary,$C as getRecommendedStructure,ts as getRegion,BC as getRegionStats,TC as getRegionsByCompliance,vC as getRegionsByLocation,wC as getRegionsByPricingTier,wy as getRequiredPermissions,PS as getSigningKeyCacheSize,Rg as getSmsInfrastructureStatus,MI as getTimestamp,na as globMatches,lo as globToRegex,IC as globalResourceManager,Ui as governingLimitCents,ag as grantFailoverReplicaAccess,Xy as guardDutyManager,Fo as handleSpendRequest,po as hasAutoWwwVariant,gr as hasManagementDashboardSite,Ad as hasProxyUpstream,Nb as hashBuffer,Bb as hashDirectory,Fm as hashFile,xb as hashManifest,Um as hashString,_E as healthCheckManager,Xn as hostAcceptsIpv6,qt as hostCondition,da as hotp,Zr as hourBucket,HA as hourBucketsBetween,lE as imageScanningManager,Es as infraEnvFromOutputs,Vl as inspectInvocation,fS as installRecursionFetch,Ns as invalidateCache,xf as invocationContext,sy as isArmInstanceType,cC as isLikelyTypo,Zn as isLocalDatabase,Wb as isLocalDevelopment,pr as isManagementDashboardSiteName,Pr as isNameserverRegistrar,kS as isNodeCryptoAvailable,Hd as isOperationAllowed,Lo as isQuietHours,Ho as isS3RestEndpoint,Pi as isSafePattern,il as isStateDirConfigured,sl as isStatePath,on as isValidCidr,RC as isValidRegion,Mi as isValidTimeZone,NS as isWebCryptoAvailable,kr as isZoneHost,vn as jobProviderCapability,_s as keyMatchesFilters,mE as lambdaConcurrencyManager,AE as lambdaDLQManager,fE as lambdaDestinationsManager,gE as lambdaLayersManager,hE as lambdaVPCManager,pE as lambdaVersionsManager,Bu as lambdaWorkloads,ql as laravelServerlessEnvDefaults,Wr as listComposeTemplates,ps as listSourceReferences,ru as loadCloudConfig,cr as loadTelemetryPolicy,nS as logsManager,Vd as lookbackHoursForSignal,ty as mailEnabled,Xe as mailFirewallPorts,dn as mailWebmailSites,ph as maintenanceWindowOpen,Gf as makeAWSRequest,TS as makeAWSRequestAsync,vS as makeAWSRequestOnce,sp as managedRuleInSync,Om as managementDashboardSiteName,qu as manifestDigest,An as matchTotpCounter,KS as mediaObjectHeaders,ko as median,rm as medianAbsoluteDeviation,Md as mergeDecisions,gn as mergeInfrastructure,UA as mergePriceBooks,Od as meterTelemetry,nE as metricsManager,Cg as migrateObjectStorage,iE as migrationManager,xC as multiAccountManager,yC as multiRegionManager,mR as needsRenewal,LE as networkSecurityManager,$t as nextScheduleRuns,De as normalizePublicIpv6,Le as normalizeRuntimeStatus,at as normalizeScheduleExpression,Jf as normalizeSourceEvent,Ve as normalizeSshPublicKey,dm as normalizeTelemetryPolicy,xi as occupiedHostPorts,Ia as openApiDocument,Oo as optionsForSignal,OC as organizationManager,jl as packagePhpApp,pn as packageServerlessApp,pd as pagesAssetHash,Gg as pagesDnsRecord,Sl as parallel,$b as parallelMap,Mb as parallelWithRetry,IA as parseCertificateState,Gl as parseChain,Kr as parseCompose,BI as parseComposeCatalog,th as parseDockerInspect,Ag as parseDotenv,rA as parseDrainedSites,_i as parseHostSiteFragments,RS as parseJSONResponse,Ai as parsePreflightFacts,Vp as parseSourceDrained,nh as parseSystemdRecords,Up as parseTargetReady,hd as parseUpstreamPort,Lp as parseWorkersPaused,wS as parseXMLResponse,ji as pathTemplate,md as pendingSteps,Po as percentOfLimit,sE as performanceManager,Ul as phpLayerBuildStage,pS as phpLayerPackages,fn as phpRuntimeLayerAssets,xI as planComposeTemplateUpgrade,Fd as planEnforcement,ui as planHetznerVolumes,Bp as planIsDestructive,Am as planMitigation,uA as planServerRename,vA as planSiteMove,zs as planZoneMigration,Kt as policyTag,Si as preflightFailed,By as previewManager,Ly as previewNotifications,Mt as previewSchedule,QA as previousBudgetWindow,wo as priceUsage,MA as priceUsageLines,sA as probeHostRoutes,Uc as probeOriginTls,Qb as processInChunks,Iu as processSourceWebhook,hs as productionChangeReview,rS as progressiveDeploymentManager,Ld as projectSpend,Yo as propagationHeaders,Ac as providerEndpoint,ju as publicKeyFingerprint,Kn as qualifyName,RE as queueManagementManager,Ob as quickHash,np as r2Endpoint,Jg as r2S3Credentials,Xl as rateLimitHeaders,os as rateLimitKey,je as readDriverState,oA as reconcile,Bg as reconcileAddressRecords,Wg as reconcileCloudflareCdn,Lh as reconcileCloudflareWorkers,Qs as reconcileDeclaredRecords,US as reconcileJobObservation,Qg as reconcileR2Buckets,In as reconcileSourceWebhook,fs as recordDashboardHostPosture,$S as recordPreDeploySecretScan,MS as recordSkippedSecretScan,Zo as recursionBlockedResponse,$e as redactRuntimeConfig,Xd as redactTelemetryText,qi as redactTelemetryValue,kn as redeployServerlessApp,bC as regionPairManager,Sn as releaseStrategyCapabilities,Kf as releaseTrafficPlan,Di as reloadRpxGateway,Os as remapKey,Ng as removeAddressRecords,vg as removeDns01ChallengeRecord,Pn as removeSiteFromCloudConfig,bu as removeSourceWebhook,xc as removeStaleServerAddressRecords,vd as renderComposeTemplate,Wi as renderDdosInstallScript,tl as renderNftablesRuleset,As as renderServerCron,el as renderSysctlFile,cd as renderWafConfig,ki as renderWafInstallScript,ad as renewRpxCertificates,sS as replicaManager,ey as requestHash,Vb as requiresReplacement,kE as resetRecursionRuntime,NE as resolveApp,g as resolveAppDatabase,pA as resolveAttachTarget,st as resolveAuthEncryptionKey,be as resolveCloudProvider,zg as resolveCloudflareCdnPlan,ei as resolveComputeVolumes,jo as resolveCredentials,Rs as resolveDashboardAction,sd as resolveDashboardAuth,py as resolveDashboardDomain,my as resolveDashboardDomains,Us as resolveDeclaredRecords,VI as resolveDeployBucketName,K as resolveDeploymentMode,ii as resolveExecStart,Qo as resolveFailoverStatusCodes,Hc as resolveHetznerApiToken,Mr as resolveHostCleanupConfig,w as resolveMailProxy,C as resolveMailService,pb as resolveManagementDashboardSite,Zi as resolveManagementDashboardSites,yc as resolveObjectStorage,ce as resolveOriginConnection,cA as resolvePlan,m as resolveProjectStackName,zr as resolveProxyUpstreams,Ml as resolveQueueNames,kA as resolveQueuedDeploymentCommand,hr as resolveQueues,mS as resolveRecursionConfig,Iy as resolveRegion,ge as resolveRuntimeInventory,dr as resolveServerlessAppStackName,cl as resolveServerlessArtifactBucketName,Xi as resolveServerlessAssetBucketName,ns as resolveServerlessRuntime,HI as resolveSiteBucketName,ho as resolveSiteDeployTarget,d as resolveSiteKind,QI as resolveSiteResourceName,UI as resolveSiteStackName,fi as resolveSshSettings,l as resolveStatePath,GI as resolveStorageBucketName,Tm as resolveStorageFailover,er as resolveUiSource,ud as resolveZoneApex,$E as resourceManagementManager,Lf as responseToResult,nm as robustZScore,rr as roleCapabilities,mu as rollbackImmutableRelease,Nn as rollbackServerlessApp,FA as roundCents,SE as route53ResolverManager,dS as route53RoutingManager,om as routeMatches,Pp as routesFromFragments,ss as ruleMatches,lS as runBuildHooks,Ud as runEnforcement,ea as runPhpBuildHooks,ct as runRemoteCommand,Ee as runtimeId,Qe as s3OriginBucket,wm as s3RegionalDomain,xs as sameCorsRules,Fs as sameLifecycleRules,Wn as sameNameservers,ws as sanitizeCloudConfig,s as sanitizeControlPlaneValue,FI as sanitizeName,cu as sanitizeOidcReturnPath,Wd as saveTelemetryPolicy,Xf as scanForSecrets,Sd as scopeContains,wt as scopeKey,Mc as scpUpload,lC as searchCommands,yo as searchControlPlane,oS as secretsManager,aE as secretsRotationManager,FS as secureContainerRelease,Yy as securityHubManager,dE as securityScanningManager,ue as securityScope,cg as seedFailoverReplicas,yn as sendAuthenticationEmail,CE as senderReputationManager,Fb as sequence,yg as serializeDotenv,Ti as serverPublicIpv4,cS as serviceMeshManager,rg as setAttachToInCloudConfig,Cr as setMaintenance,bs as setSitePropertyInCloudConfig,nl as setStateDir,dR as setupDns01Challenge,wc as setupSmsInfrastructure,Ko as sha256,hS as sharedRecursionGuard,Bf as sharedRuntimeLoop,zp as shipsARelease,WS as signCloudFrontCookies,xS as signCloudFrontUrl,k as signRequest,Wl as signRequestAsync,Bo as signalDefinition,U as siteInstallBase,Bi as siteMoveArchivePath,yA as siteMoveCertArchivePath,fd as siteUnitGlob,um as spendNotificationText,Uo as spendOpenApiPaths,Fr as sshExec,Se as sshExecOrThrow,CC as stackDependencyManager,gc as startLocalDashboardServer,YA as startSpendLoop,cn as stateDir,Q as statePath,OE as staticSiteManager,CS as storageAdvancedManager,KI as storageFailoverReplicasFromTemplate,VA as streamFocusJsonl,Qd as strongestActiveAction,qm as suggestCommand,gC as suggestFlags,Rb as suggestIAMPolicy,kb as suggestQuotaIncrease,kC as suggestRegionPairs,PC as suggestRegions,gs as syncSourceRepositories,Pd as synchronizeComposeVolumes,Sg as synchronizeConfiguredConfiguration,Ra as synchronizeConfiguredJobs,iS as syntheticsManager,Zd as sysctlHardening,ih as systemdWorkloads,WA as telemetryBucketLabel,zi as telemetryCursor,Jd as telemetryEstimatedMonthlyCost,KA as telemetryPercentile,lm as telemetryPolicyKey,Ry as templateCache,kp as tenantsOf,Sa as testSourceConnection,kd as tieredMicroCents,ap as toApiLifecycleRule,zc as toCloudflareZoneSettings,_o as toFocusJsonl,qd as toFocusRecords,iA as toInventoryServer,qf as totp,la as totpUri,Np as unaccountedSites,eh as unsupportedCapabilities,NA as unsupportedVolumeCapabilities,Ku as updateCompatibility,Ju as updateSiteInCloudConfig,ks as uploadStaticFiles,Yp as usageDeltaKey,or as utcInstantOfLocal,FC as validateAccountStructure,Kb as validateAgainstSchema,xA as validateAttachment,Eh as validateBackupDestination,fC as validateCommand,Eb as validateConfiguration,Tb as validateCredentials,jp as validateDeploymentConfig,BA as validateMountPath,Pt as validateOriginGroups,ug as validateResourceLimits,xp as validateServerName,Ep as validateTemplate,sg as validateTemplateSize,_c as verifyAddressRecord,LS as verifyArtifactSignature,jS as verifyMediaAccessToken,jf as verifyTotp,zu as verifyUpdateSignature,Ws as verifyZoneParity,Co as volumeCapabilities,Ip as wafEventTelemetry,Fc as waitForCloudInit,ft as waitForSsh,yr as webhookEndpoint,Ib as withCDN,Sb as withCache,up as withContentHash,yb as withDatabase,_f as withInvocation,hb as withMonitoring,bb as withQueue,Ab as withSecurity,Ub as withTimeout,dp as workerBindings,so as workerContentHash,Ja as workerInSync,se as wrapCloudInitUserData,At as writeDriverState,rE as xrayManager,Gu as zeroCapacity,qA as zeroFill,Bd as zoneOffsetMs,Ro as zonedParts};
604
+ `}async function Ig(u,p,h){let y=`_acme-challenge.${p}`;if(await Eg(u,p,y,h))return;let R=await u.createRecord(p,{name:y,type:"TXT",content:h,ttl:60});if(!R.success)throw Error(`Failed to create DNS challenge record: ${R.message}`)}async function vg(u,p,h){let y=await u.deleteRecord(p,{name:`_acme-challenge.${p}`,type:"TXT",content:h});if(!y.success)console.warn(`Failed to delete DNS challenge record: ${y.message}`)}async function Eg(u,p,h,y){try{let R=await u.listRecords(p,"TXT"),v=h.replace(/\.$/,"").toLowerCase();return(R.records??[]).some((P)=>P.name.replace(/\.$/,"").toLowerCase()===v&&P.content.replace(/^"|"$/g,"")===y)}catch{return!1}}function td(u){let{hostedZoneId:p,dnsProvider:h,region:y="us-east-1"}=u;if(h)return N(h);if(p)return new ie(y,p);throw Error("Either dnsProvider or hostedZoneId must be provided")}async function dR(u){await Ig(td(u),u.domain,u.challengeValue)}async function pR(u){await vg(td(u),u.domain,u.challengeValue)}function mR(u){try{let{execSync:p}=it("node:child_process"),h=p(`openssl x509 -checkend 2592000 -noout -in ${u}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as rd,createSign as Lg,generateKeyPairSync as nd}from"node:crypto";var ld={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class Fg{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(u){this.directoryUrl=u.staging?ld.staging:ld.production,this.email=u.email,this.accountKey=u.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:u}=nd("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 y=this.nonce;return this.nonce=null,y}let u=await this.getDirectory(),h=(await fetch(u.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!h)throw Error("Failed to get nonce from ACME server");return h}getJwk(){let u=this.accountKey.split(`
605
+ `).filter((v)=>!v.startsWith("-----")).join(""),p=Buffer.from(u,"base64"),h=p.length-65,y=p.subarray(h+1,h+33),R=p.subarray(h+33,h+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(y),y:this.base64UrlEncode(R)}}getJwkThumbprint(){let u=this.getJwk(),p=JSON.stringify({crv:u.crv,kty:u.kty,x:u.x,y:u.y}),h=rd("sha256").update(p).digest();return this.base64UrlEncode(h)}base64UrlEncode(u){return(typeof u==="string"?Buffer.from(u):u).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(u,p){let h=await this.getNonce(),y=this.getJwk(),R={alg:"ES256",nonce:h,url:u};if(this.accountUrl)R.kid=this.accountUrl;else R.jwk=y;let v=this.base64UrlEncode(JSON.stringify(R)),P=p===""?"":this.base64UrlEncode(JSON.stringify(p)),L=`${v}.${P}`,z=Lg("SHA256");z.update(L);let fe=z.sign(this.accountKey),me=fe.subarray(4,4+fe[3]),bt=4+fe[3]+2,At=fe.subarray(bt,bt+fe[bt-1]),Ke=Buffer.alloc(32),Me=Buffer.alloc(32);me.copy(Ke,32-me.length),At.copy(Me,32-At.length);let ze=Buffer.concat([Ke,Me]);return JSON.stringify({protected:v,payload:P,signature:this.base64UrlEncode(ze)})}async acmeRequest(u,p){let h=await this.signPayload(u,p),y=await fetch(u,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:h}),R=y.headers.get("replay-nonce");if(R)this.nonce=R;let v,P=y.headers.get("content-type");if(P?.includes("application/json")||P?.includes("application/problem+json"))v=await y.json();else v=await y.text();if(!y.ok)throw Error(`ACME request failed: ${JSON.stringify(v)}`);return{body:v,headers:y.headers}}async registerAccount(){let u=await this.getDirectory(),{body:p,headers:h}=await this.acmeRequest(u.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),y=h.get("location");if(!y)throw Error("No account URL returned");return this.accountUrl=y,y}async createOrder(u){if(!this.accountUrl)await this.registerAccount();let p=await this.getDirectory(),{body:h,headers:y}=await this.acmeRequest(p.newOrder,{identifiers:u.map((v)=>({type:"dns",value:v}))}),R=y.get("location");if(!R)throw Error("No order URL returned");return{orderUrl:R,authorizations:h.authorizations,finalize:h.finalize}}async getAuthorization(u){let{body:p}=await this.acmeRequest(u,""),h=p.identifier.value,y=this.getJwkThumbprint(),R=p.challenges.filter((v)=>v.type==="http-01"||v.type==="dns-01").map((v)=>{let P=`${v.token}.${y}`;if(v.type==="http-01")return{type:"http-01",token:v.token,keyAuthorization:P,identifier:`/.well-known/acme-challenge/${v.token}`};else{let L=this.base64UrlEncode(rd("sha256").update(P).digest());return{type:"dns-01",token:v.token,keyAuthorization:P,identifier:`_acme-challenge.${h}`,dnsValue:L}}});return{domain:h,challenges:R}}async respondToChallenge(u){await this.acmeRequest(u,{})}async waitForAuthorization(u,p=30){for(let h=0;h<p;h++){let{body:y}=await this.acmeRequest(u,"");if(y.status==="valid")return;if(y.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(y)}`);await new Promise((R)=>setTimeout(R,2000))}throw Error("Authorization timed out")}generateCsr(u){let{privateKey:p}=nd("rsa",{modulusLength:2048}),h=p.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(u,p),privateKey:h}}createSimpleCsr(u,p){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(u,p){let{csr:h,privateKey:y}=this.generateCsr(p),{body:R}=await this.acmeRequest(u,{csr:this.base64UrlEncode(Buffer.from(h,"base64"))}),v=R.certificate;if(!v)throw Error("Certificate not immediately available - polling not implemented");let L=await(await fetch(v)).text(),z=L.split(/(?=-----BEGIN CERTIFICATE-----)/g),fe=z[0],me=z.slice(1).join("");return{certificate:fe,privateKey:y,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 zc(u){let p={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)p.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 h of Object.keys(p))if(p[h]===void 0)delete p[h];return{...p,...u.raw??{}}}var wi={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 _g}from"node:tls";async function Uc(u){let{address:p,serverName:h,port:y=443,timeoutMs:R=5000}=u;return new Promise((v)=>{let P=!1,L=(fe)=>{if(P)return;P=!0;try{z.destroy()}catch{}v(fe)},z=_g({host:p,port:y,servername:h,rejectUnauthorized:!1,timeout:R});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 ${R}ms`})}),z.once("error",(fe)=>{L({reachable:!1,trusted:!1,reason:fe.message})})})}function Mg(u,p){let h=p.replace(/\.$/,"").toLowerCase();return u.some((y)=>{let R=y.replace(/\.$/,"").toLowerCase();if(R===h)return!0;if(!R.startsWith("*."))return!1;let v=R.slice(2);if(!h.endsWith(`.${v}`))return!1;return!h.slice(0,h.length-v.length-1).includes(".")})}async function Wg(u){let{provider:p,zone:h,hosts:y,ipv4:R,ipv6:v,proxied:P=!0,settings:L=wi,cache:z,originGuard:fe,purge:me=!0,ttl:bt=300,skipOriginProbe:At=!1,skipEdgeCertificateCheck:Ke=!1}=u,Me={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(y.length===0)return Me;let ze=[],j=P&&!Ke?await p.listEdgeCertificateHosts(h):null;for(let G of y){let ft=P;if(ft&&j&&!Mg(j,G)){ft=!1;let Et=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:Et}),Me.warnings.push(`${G}: publishing DNS-only — ${Et}. 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(ft&&!At){let Et=await Uc({address:R,serverName:G});if(!Et.trusted){ft=!1;let Ut=Et.reason||"origin is not serving a trusted certificate";Me.deferredProxy.push({host:G,reason:Ut}),Me.warnings.push(`${G}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${Ut}). 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(ft)ze.push(G);let St=[{type:"A",content:R}];if(v&&Xn(G))St.push({type:"AAAA",content:v});for(let{type:Et,content:Ut}of St){let Zt=await p.upsertRecord(h,{name:G,type:Et,content:Ut,ttl:bt,proxied:ft});if(Zt.success)Me.records.push({host:G,type:Et,content:Ut,proxied:ft});else Me.warnings.push(`${G} ${Et} → ${Ut} failed: ${Zt.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=zc(L),ft=await p.applyZoneSettings(h,G);Me.settingsChanged=ft.changed;for(let St of ft.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 Ct=Pc(ze,z);if(Ct.length>0){let G=await p.putManagedPhaseRules(h,"http_request_cache_settings",Ct);if(G.success)Me.cacheRules=Ct.length;else Me.warnings.push(`cache rules could not be written: ${G.message}`)}if(fe){let G=kc(ze,fe.header,fe.value);if(G.length>0){let ft=await p.putManagedPhaseRules(h,"http_request_late_transform",G);if(ft.success)Me.originGuard=!0;else Me.warnings.push(`origin guard header could not be written: ${ft.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 p.purgeCache(h,{hosts:ze}),!Me.purged)Me.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Me}var Vg=(u)=>process.env[u];function ud(u,p){let h=u.replace(/\.$/,"").toLowerCase();if(p){let y=p.replace(/\.$/,"").toLowerCase();if(h===y||h.endsWith(`.${y}`))return y}return h.split(".").slice(-2).join(".")}function zg(u,p={}){let h=p.env??Vg,y=u.infrastructure?.compute?.proxy?.cdn,R=[];if(!y||y.provider!=="cloudflare")return{plan:null,errors:R};if(y.originDomain)R.push(`compute.proxy.cdn.originDomain (${y.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 v=h("CLOUDFLARE_API_TOKEN");if(!v)return R.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:R};let P=u.sites??{},L=y.frontedHosts?.length?[...new Set(y.frontedHosts.map((At)=>At.toLowerCase()))]:mo(P,{autoWww:u.infrastructure?.compute?.proxy?.autoWww!==!1});if(L.length===0)return R.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:R};let z=u.infrastructure?.dns?.domain,fe=new Set(L.map((At)=>ud(At,z)));if(fe.size>1)return R.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:R};let me=y.cloudflare??{},bt=y.secret?{header:y.secretHeader??"X-Origin-Verify",value:y.secret}:void 0;return{plan:{zone:[...fe][0],hosts:L,apiToken:v,zoneId:me.zoneId??h("CLOUDFLARE_ZONE_ID"),accountId:me.accountId??h("CLOUDFLARE_ACCOUNT_ID"),proxied:me.proxied!==!1,settings:me.settings??wi,cache:me.cache,originGuard:bt,purge:me.purgeOnDeploy!==!1,skipOriginProbe:me.skipOriginProbe===!0},errors:R}}var Hg=26214400;var Ug=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class dd{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,p,h){return vs(u,`/accounts/${this.accountId}${p}`,`Bearer ${this.apiToken}`,h)}async getProject(u){try{return await this.request("GET",`/pages/projects/${u}`)}catch(p){if(p instanceof Error&&/\b8000007\b|not found/i.test(p.message))return null;throw p}}async ensureProject(u,p="main"){let h=await this.getProject(u);if(h)return h;return this.request("POST","/pages/projects",{name:u,production_branch:p})}async uploadToken(u){return(await this.request("GET",`/pages/projects/${u}/upload-token`)).jwt}async missingHashes(u,p){let h=await vs("POST","/pages/assets/check-missing",`Bearer ${u}`,{hashes:p});return new Set(h)}async upsertHashes(u,p){await vs("POST","/pages/assets/upsert-hashes",`Bearer ${u}`,{hashes:p})}async uploadBatch(u,p){let h=p.map((y)=>({key:y.hash,value:y.base64,metadata:{contentType:jg(y.extension)},base64:!0}));await vs("POST","/pages/assets/upload",`Bearer ${u}`,h)}async createDeployment(u,p,h){let y={};for(let v of p)y[v.path]=v.hash;let R=new FormData;if(R.append("manifest",JSON.stringify(y)),h)R.append("branch",h);return this.request("POST",`/pages/projects/${u}/deployments`,R)}async deployDirectory(u){let p=await gd(u.directory);if(p.length===0)throw Error(`No files to deploy in ${u.directory}`);let h=await this.uploadToken(u.project),y=await this.missingHashes(h,p.map((z)=>z.hash)),R=p.filter((z)=>y.has(z.hash)),v=[];for(let z=0;z<R.length;z+=100)v.push(R.slice(z,z+100));let P=0;for(let z=0;z<v.length;z+=4){let fe=v.slice(z,z+4);await Promise.all(fe.map((me)=>this.uploadBatch(h,me))),P+=fe.reduce((me,bt)=>me+bt.length,0),u.onProgress?.(P,R.length)}return await this.upsertHashes(h,p.map((z)=>z.hash)),{deployment:await this.createDeployment(u.project,p,u.branch),total:p.length,uploaded:R.length,uploadedBytes:R.reduce((z,fe)=>z+fe.size,0)}}async listCustomDomains(u){return(await this.request("GET",`/pages/projects/${u}/domains`)).map((h)=>h.name)}async attachCustomDomain(u,p){if((await this.listCustomDomains(u)).includes(p))return!1;return await this.request("POST",`/pages/projects/${u}/domains`,{name:p}),!0}}function Gg(u,p){return{type:"CNAME",name:u,value:p.endsWith(".pages.dev")?p:`${p}.pages.dev`,ttl:1,proxied:!0}}async function pd(u,p){let{blake3:h}=await import("./chunk-s4wz0csj.js").then((m)=>BS(m.default,1));return(await h(u+p)).slice(0,32)}async function gd(u){let{readdir:p}=await import("node:fs/promises"),{join:h,relative:y,sep:R}=await import("node:path"),v=[];async function P(L){let z=await p(L,{withFileTypes:!0});for(let fe of z){let me=h(L,fe.name);if(fe.isDirectory()){await P(me);continue}if(!fe.isFile())continue;let bt=`/${y(u,me).split(R).join("/")}`;if(Ug.has(bt))continue;let At=await Bun.file(me).bytes();if(At.byteLength>26214400)throw Error(`${bt} is ${At.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let Ke=Buffer.from(At).toString("base64"),Me=fe.name.lastIndexOf("."),ze=Me>0?fe.name.slice(Me+1):"";v.push({path:bt,hash:await pd(Ke,ze),base64:Ke,extension:ze,size:At.byteLength})}}return await P(u),v.sort((L,z)=>L.path.localeCompare(z.path)),v}function jg(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 vs(u,p,h,y){let R={Authorization:h},v;if(y instanceof FormData)v=y;else if(y!==void 0)R["Content-Type"]="application/json",v=JSON.stringify(y);let P=await fetch(`https://api.cloudflare.com/client/v4${p}`,{method:u,headers:R,body:v}),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 Kg}from"node:crypto";var tp="https://api.cloudflare.com/client/v4",rp=10042,qg=10006,Zg=10059;class Fn extends Error{status;errors;constructor(u,p,h=[]){super(u);this.name="R2ApiError",this.status=p,this.errors=h}hasCode(u){return this.errors.some((p)=>p.code===u)}}class hn extends Fn{accountId;constructor(u,p,h=[]){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.`,p,h);this.name="R2NotEnabledError",this.accountId=u}}class ai{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??((p,h)=>fetch(p,h))}async requestEnvelope(u,p,h,y={}){let R={Authorization:`Bearer ${this.apiToken}`};if(h!==void 0)R["Content-Type"]="application/json";if(y.jurisdiction&&y.jurisdiction!=="default")R["cf-r2-jurisdiction"]=y.jurisdiction;let v=await this.fetchImpl(`${tp}/accounts/${this.accountId}/r2${p}`,{method:u,headers:R,body:h===void 0?void 0:JSON.stringify(h)}),P=await v.text(),L;try{L=JSON.parse(P)}catch{throw new Fn(`Cloudflare R2 API returned ${v.status} with a non-JSON body: ${P.slice(0,200)}`,v.status)}if(!L.success){let z=L.errors??[];if(z.some((me)=>me.code===rp))throw new hn(this.accountId,v.status,z);let fe=z.map((me)=>`${me.code}: ${me.message}`).join(", ");throw new Fn(`Cloudflare R2 API error (${v.status}) on ${u} ${p}: ${fe||P.slice(0,200)}`,v.status,z)}return L}async request(u,p,h,y){return(await this.requestEnvelope(u,p,h,y)).result}bucketPath(u){return`/buckets/${encodeURIComponent(u)}`}async listBuckets(u={}){let p=[],h;do{let y=new URLSearchParams({per_page:"1000"});if(h)y.set("cursor",h);let R=await this.requestEnvelope("GET",`/buckets?${y}`,void 0,u),v=R.result?.buckets??[];p.push(...v),h=v.length>0?R.result_info?.cursor||void 0:void 0}while(h);return p}async getBucket(u,p={}){try{return await this.request("GET",this.bucketPath(u),void 0,p)}catch(h){if(h instanceof hn)throw h;if(h instanceof Fn&&(h.hasCode(qg)||h.status===404))return null;throw h}}async ensureBucket(u,p={}){let h={jurisdiction:p.jurisdiction},y=await this.getBucket(u,h);if(y)return{bucket:y,created:!1};let R={name:u};if(p.locationHint)R.locationHint=p.locationHint;let v=await this.request("POST","/buckets",R,h);return{bucket:{...v,name:v?.name||u},created:!0}}async getCors(u,p={}){try{return(await this.request("GET",`${this.bucketPath(u)}/cors`,void 0,p))?.rules??[]}catch(h){if(h instanceof Fn&&!(h instanceof hn)&&(h.hasCode(Zg)||h.status===404))return[];throw h}}async putCors(u,p,h={}){if(p.length===0){await this.request("DELETE",`${this.bucketPath(u)}/cors`,void 0,h);return}await this.request("PUT",`${this.bucketPath(u)}/cors`,{rules:p},h)}async ensureCors(u,p,h={}){let y=await this.getCors(u,h);if(xs(y,p))return!1;return await this.putCors(u,p,h),!0}async getLifecycle(u,p={}){return(await this.request("GET",`${this.bucketPath(u)}/lifecycle`,void 0,p))?.rules??[]}async putLifecycle(u,p,h={}){await this.request("PUT",`${this.bucketPath(u)}/lifecycle`,{rules:p},h)}async ensureLifecycle(u,p,h={}){let y=await this.getLifecycle(u,h);if(Fs(y,p))return!1;return await this.putLifecycle(u,p,h),!0}async listCustomDomains(u,p={}){return(await this.request("GET",`${this.bucketPath(u)}/domains/custom`,void 0,p))?.domains??[]}async attachCustomDomain(u,p,h={}){return this.request("POST",`${this.bucketPath(u)}/domains/custom`,{domain:p.domain,zoneId:p.zoneId,enabled:p.enabled??!0,minTLS:p.minTLS??"1.2"},h)}async updateCustomDomain(u,p,h,y={}){return this.request("PUT",`${this.bucketPath(u)}/domains/custom/${encodeURIComponent(p)}`,h,y)}async ensureCustomDomain(u,p,h={},y){let R=p.minTLS??"1.2",P=(y??await this.listCustomDomains(u,h)).find((fe)=>fe.domain.toLowerCase()===p.domain.toLowerCase());if(!P){let fe=await this.attachCustomDomain(u,{...p,minTLS:R,enabled:!0},h);return{action:"attached",domain:{...fe,domain:fe?.domain||p.domain}}}let L=P.minTLS??"1.0";if(P.enabled&&L===R)return{action:"unchanged",domain:P};let z=await this.updateCustomDomain(u,P.domain,{enabled:!0,minTLS:R},h);return{action:"updated",domain:{...P,...z}}}async getManagedDomain(u,p={}){return this.request("GET",`${this.bucketPath(u)}/domains/managed`,void 0,p)}async setManagedDomain(u,p,h={}){let y=await this.getManagedDomain(u,h);if(y?.enabled===p)return{changed:!1,domain:y};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(u)}/domains/managed`,{enabled:p},h)}}}function np(u){return`https://${u}.r2.cloudflarestorage.com`}async function Jg(u){let{apiToken:p,accountId:h}=u;if(!p)throw Error("r2S3Credentials needs an API token");if(!h)throw Error("r2S3Credentials needs an account id");let y=u.fetch??((P,L)=>fetch(P,L)),R=[],v;for(let P of[`/accounts/${h}/tokens/verify`,"/user/tokens/verify"]){let L=await y(`${tp}${P}`,{method:"GET",headers:{Authorization:`Bearer ${p}`}}),z=await L.json().catch(()=>null);if(L.ok&&z?.success&&z.result?.id){v=z.result.id;break}let fe=z?.errors?.map((me)=>`${me.code}: ${me.message}`).join(", ");R.push(`${P} -> ${L.status}${fe?` (${fe})`:""}`)}if(!v)throw Error(`Could not verify the Cloudflare API token to derive R2 credentials: ${R.join("; ")}`);return{accessKeyId:v,secretAccessKey:Kg("sha256").update(p).digest("hex"),endpoint:np(h),region:"auto"}}function Ni(u){if(Array.isArray(u))return`[${u.map(Ni).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${Ni(y)}`).join(",")}}`;return JSON.stringify(u)}function ep(u,p){let h=(y)=>y&&y.length>0?[...y].map(String).sort():void 0;return{id:p?u.id:void 0,allowed:{origins:h(u.allowed?.origins),methods:h(u.allowed?.methods?.map((y)=>y.toUpperCase())),headers:h(u.allowed?.headers?.map((y)=>y.toLowerCase()))},exposeHeaders:h(u.exposeHeaders?.map((y)=>y.toLowerCase())),maxAgeSeconds:u.maxAgeSeconds}}function xs(u,p){if(u.length!==p.length)return!1;return p.every((h,y)=>{let R=h.id!==void 0;return Ni(ep(u[y],R))===Ni(ep(h,R))})}function Fs(u,p){if(u.length!==p.length)return!1;let h=(y)=>Ni([...y].map((R)=>({...R,storageClassTransitions:R.storageClassTransitions?.length?R.storageClassTransitions:void 0})).sort((R,v)=>R.id.localeCompare(v.id)));return h(u)===h(p)}var Yg="r2 cache",Xg=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function Qg(u,p={}){let h=p.log??(()=>{}),y={buckets:[],warnings:[]},R=u.infrastructure?.r2??u.r2,v=Object.entries(R?.buckets??{});if(v.length===0)return h("R2: no buckets declared, skipping."),y;if(!p.apiToken||!p.accountId){let me=[!p.apiToken&&"CLOUDFLARE_API_TOKEN",!p.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),bt=`R2: ${v.length} bucket(s) declared but ${me} is not set, skipping.`;return h(bt),y.warnings.push(bt),y}let P=p.dryRun===!0,L=new ai({apiToken:p.apiToken,accountId:p.accountId,fetch:p.fetch}),z=new H(p.apiToken,{zoneId:p.zoneId,accountId:p.accountId}),fe=new Map;for(let[me,bt]of v){let At=bt?.name;if(!At||!Xg.test(At)){y.warnings.push(`R2: bucket '${me}' has an invalid name '${At??""}' (3-63 chars: lowercase letters, digits, hyphens), skipping.`);continue}h(`R2: ${P?"checking":"reconciling"} bucket ${At}...`);let Ke={name:At,changes:[],domains:[]};if(y.buckets.push(Ke),await hh(bt,{r2:L,cloudflare:z,dryRun:P,summary:Ke,warnings:y.warnings,claimed:fe,log:h}),Ke.changes.length===0)h(`R2: ${At} is in sync.`);else for(let Me of Ke.changes)h(`R2: ${At}: ${Me}`)}return y}async function hh(u,p){let{r2:h,dryRun:y,summary:R,warnings:v}=p,P=u.name,L={jurisdiction:u.jurisdiction},z=(Ke,Me)=>{let ze=y?Me&&`would ${Me}`:Ke;if(ze)R.changes.push(ze)},fe;if(y)fe=await h.getBucket(P,L)!==null;else{let{created:Ke}=await h.ensureBucket(P,{locationHint:u.locationHint,jurisdiction:u.jurisdiction});if(fe=!0,Ke)z("created","")}if(!fe)z("","create bucket");let me=Ch(u.customDomains);await ro(p,`cors on ${P}`,async()=>{if(!u.cors)return;if(!fe){z("cors updated","set cors");return}let Ke=await h.getCors(P,L);if(xs(Ke,u.cors))return;if(!y)await h.putCors(P,u.cors,L);z(u.cors.length===0?"cors removed":"cors updated",u.cors.length===0?"remove cors":"update cors")}),await ro(p,`lifecycle on ${P}`,async()=>{if(!u.lifecycle)return;let Ke=u.lifecycle.map(ap);if(fe){let Me=await h.getLifecycle(P,L);if(Fs(Me,Ke))return}if(!y)await h.putLifecycle(P,Ke,L);z("lifecycle updated","update lifecycle")}),await ro(p,`r2.dev URL on ${P}`,async()=>{let Ke=u.publicDevUrl===!0;if(!fe){if(Ke)z("r2.dev URL enabled","enable r2.dev URL");return}if((await h.getManagedDomain(P,L))?.enabled===Ke)return;if(!y)await h.setManagedDomain(P,Ke,L);z(Ke?"r2.dev URL enabled":"r2.dev URL disabled",Ke?"enable r2.dev URL":"disable r2.dev URL")});let bt=[];if(me.length>0&&fe)try{bt=await h.listCustomDomains(P,L)}catch(Ke){if(Ke instanceof hn)throw Ke;v.push(`R2: could not list custom domains on ${P}: ${Kc(Ke)}`)}let At=new Map;for(let{domain:Ke,minTLS:Me}of me){let ze=p.claimed.get(Ke);if(ze&&ze!==P){v.push(`R2: ${Ke} is declared on both ${ze} and ${P}; leaving it on ${ze}.`);continue}p.claimed.set(Ke,P);let j=bt.find((G)=>G.domain.toLowerCase()===Ke),Ct=Me??"1.2";if(j&&j.enabled&&(j.minTLS??"1.0")===Ct){if(R.domains.push({domain:Ke,status:jc(j)}),j.zoneId)At.set(Ke,j.zoneId);continue}await ro(p,`custom domain ${Ke} on ${P}`,async()=>{if(j){if(!y)await h.updateCustomDomain(P,j.domain,{enabled:!0,minTLS:Ct},L);if(z(`custom domain ${Ke} updated`,`update custom domain ${Ke}`),R.domains.push({domain:Ke,status:jc({...j,enabled:!0})}),j.zoneId)At.set(Ke,j.zoneId);return}let G=await p.cloudflare.zoneIdFor(Ke);if(At.set(Ke,G),!y)await h.ensureCustomDomain(P,{domain:Ke,zoneId:G,minTLS:Ct},L,bt);z(`custom domain ${Ke} attached`,`attach custom domain ${Ke}`),R.domains.push({domain:Ke,status:y?"not attached":"pending"})},()=>R.domains.push({domain:Ke,status:"error"}))}if(u.cache&&me.length>0)await yh(u,me.map((Ke)=>Ke.domain).filter((Ke)=>p.claimed.get(Ke)===P),At,p,z)}async function yh(u,p,h,y,R){let v=ip(u.cache);if(!v||p.length===0)return;let P=new Map;for(let L of p){let z=h.get(L);if(!z)try{z=await y.cloudflare.zoneIdFor(L)}catch(fe){y.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:`${zt} ${Yg}`,expression:`(${jt(L)})`,enabled:!0,action_parameters:v};await ro(y,`cache rule for ${L.join(", ")}`,async()=>{let fe=await y.cloudflare.getPhaseRules(L[0],"http_request_cache_settings");if(sp(fe,z))return;if(!y.dryRun){let me=await y.cloudflare.putManagedPhaseRules(L[0],"http_request_cache_settings",[z]);if(!me.success)throw Error(me.message||"cache rule write failed")}R(`cache rule updated for ${L.join(", ")}`,`update cache rule for ${L.join(", ")}`)})}}function ip(u){if(u.edgeTtl===void 0&&u.browserTtl===void 0)return null;let p={cache:!0};if(u.edgeTtl!==void 0)p.edge_ttl={mode:"override_origin",default:u.edgeTtl};if(u.browserTtl!==void 0)p.browser_ttl={mode:"override_origin",default:u.browserTtl};return p}function sp(u,p){let h=Kt(p.expression),y=zn(p.expression),R=(L)=>(L.description||"").startsWith(zt),v=(L)=>L.action===p.action&&L.description===p.description&&(L.enabled??!0)===(p.enabled??!0)&&zn(L.expression)===y&&Ms(L.action_parameters)===Ms(p.action_parameters),P=!1;for(let L of u){if(!R(L))continue;let z=Kt(L.expression);if(!h.some((me)=>z.includes(me)))continue;if(v(L)&&h.every((me)=>z.includes(me))&&!P){P=!0;continue}return!1}return P}function ap(u){let p={id:u.id,enabled:u.enabled??!0,conditions:{prefix:u.prefix??""}};if(u.expireAfterDays!==void 0)p.deleteObjectsTransition={condition:{type:"Age",maxAge:Gc(u.expireAfterDays)}};else if(u.expireOn!==void 0)p.deleteObjectsTransition={condition:{type:"Date",date:u.expireOn}};if(u.abortMultipartUploadsAfterDays!==void 0)p.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:Gc(u.abortMultipartUploadsAfterDays)}};if(u.infrequentAccessAfterDays!==void 0)p.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:Gc(u.infrequentAccessAfterDays)}}];return p}function Gc(u){return Math.round(u*86400)}function Ch(u){let p=new Set,h=[];for(let y of u??[]){let R=typeof y==="string"?{domain:y}:y,v=R.domain?.trim().replace(/\.$/,"").toLowerCase();if(!v||p.has(v))continue;p.add(v),h.push({domain:v,minTLS:R.minTLS})}return h}function jc(u){if(!u.enabled)return"disabled";let p=u.status?.ownership,h=u.status?.ssl;if(p==="active"&&h==="active")return"active";for(let y of[p,h])if(y==="error"||y==="blocked"||y==="deactivated")return y;return"pending"}async function ro(u,p,h,y){try{await h()}catch(R){if(R instanceof hn)throw R;u.warnings.push(`R2: ${p} failed: ${Kc(R)}`),y?.()}}function Kc(u){return u instanceof Error?u.message:String(u)}function Ms(u){if(Array.isArray(u))return`[${u.map(Ms).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${Ms(y)}`).join(",")}}`;return JSON.stringify(u)}import{basename as wh,extname as Ih}from"node:path";import{createHash as Sh}from"node:crypto";var Rh="https://api.cloudflare.com/client/v4",$n="TS_CLOUD_CONTENT_HASH",no="2025-09-01",Zc="application/javascript+module",bh=10007,Ah=[1e4,9109];class li extends Error{status;errors;constructor(u,p,h=[]){super(u);this.name="WorkersApiError",this.status=p,this.errors=h}hasCode(u){return this.errors.some((p)=>p.code===u)}}class Bs extends li{permission;constructor(u,p,h,y=[]){super(`The Cloudflare API token is missing the "${u}" permission (${p}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,h,y);this.name="WorkersPermissionError",this.permission=u}}class Zs{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??((p,h)=>fetch(p,h))}async request(u,p,h){let y={Authorization:`Bearer ${this.apiToken}`},R;if(h instanceof FormData)R=h;else if(h!==void 0)y["Content-Type"]="application/json",R=JSON.stringify(h);let v=await this.fetchImpl(`${Rh}/accounts/${this.accountId}/workers${p}`,{method:u,headers:y,body:R}),P=await v.text(),L;try{L=JSON.parse(P)}catch{throw new li(`Cloudflare Workers API returned ${v.status} with a non-JSON body: ${P.slice(0,200)}`,v.status)}if(!L.success){let z=L.errors??[],fe=z.map((me)=>`${me.code}: ${me.message}`).join(", ");if(Ph(v.status,z))throw new Bs($h(p),`${u} ${p} -> ${v.status}${fe?`, ${fe}`:""}`,v.status,z);throw new li(`Cloudflare Workers API error (${v.status}) on ${u} ${p}: ${fe||P.slice(0,200)}`,v.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(p){if(p instanceof Bs)throw p;if(p instanceof li&&(p.hasCode(bh)||p.status===404))return null;throw p}}async getScript(u){return this.getSettings(u)}async uploadModuleScript(u,p){return this.request("PUT",this.scriptPath(u),lp(p))}async ensureModuleScript(u,p){let h=so(p),y=await this.getSettings(u);if(y&&Ja(y,p,h))return{action:"unchanged",hash:h};return await this.uploadModuleScript(u,up(p,h)),{action:y?"updated":"created",hash:h}}async listCustomDomains(u={}){let p=new URLSearchParams;if(u.service)p.set("service",u.service);if(u.hostname)p.set("hostname",u.hostname);if(u.zoneId)p.set("zone_id",u.zoneId);let h=p.toString(),y=h?`?${h}`:"";return await this.request("GET",`/domains${y}`)??[]}async attachCustomDomain(u,p){let h={hostname:u,service:p.service,environment:p.environment??"production"};if(p.zoneId)h.zone_id=p.zoneId;return this.request("PUT","/domains",h)}async detachCustomDomain(u){await this.request("DELETE",`/domains/${encodeURIComponent(u)}`)}async ensureCustomDomain(u,p,h){let R=(h??await this.listCustomDomains({hostname:u})).find((P)=>P.hostname.toLowerCase()===u.toLowerCase());if(R&&R.service===p.service)return{action:"unchanged",domain:R};if(R)throw Error(`${u} is attached to the Worker '${R.service}'. Detach it there first (Workers & Pages, ${R.service}, Settings, Domains & Routes); ts-cloud does not move it.`);let v=await this.attachCustomDomain(u,p);return{action:"attached",domain:{...v,hostname:v?.hostname||u}}}}function Ph(u,p){if(p.some((h)=>Ah.includes(h.code)))return!0;return(u===401||u===403)&&p.length===0}function $h(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((y)=>y.name===u.mainModule))throw Error(`Worker main module '${u.mainModule}' is not one of the uploaded modules`);let p={main_module:u.mainModule,bindings:u.bindings??[],compatibility_date:u.compatibilityDate??no,compatibility_flags:u.compatibilityFlags??[],keep_bindings:["secret_text"]},h=new FormData;h.append("metadata",JSON.stringify(p));for(let y of u.modules)h.append(y.name,new Blob([y.content],{type:y.type}),y.name);return h}function so(u){let p={mainModule:u.mainModule,modules:[...u.modules].sort((h,y)=>h.name.localeCompare(y.name)).map((h)=>({name:h.name,type:h.type,sha256:cp(h.content)})),bindings:[...u.bindings??[]].filter((h)=>h.name!==$n).sort((h,y)=>h.name.localeCompare(y.name)),compatibilityDate:u.compatibilityDate??no,compatibilityFlags:[...u.compatibilityFlags??[]].sort()};return cp(qc(p))}function up(u,p=so(u)){return{...u,bindings:[...(u.bindings??[]).filter((h)=>h.name!==$n),{type:"plain_text",name:$n,text:p}]}}function Ja(u,p,h){let y=u.bindings??[],R=y.find((v)=>v.name===$n&&v.type==="plain_text");if(!R||R.text!==h)return!1;return(p.bindings??[]).every((v)=>{let P=y.find((z)=>z.name===v.name);if(!P||P.type!==v.type)return!1;let L=v.type==="r2_bucket"?"bucket_name":v.type==="plain_text"?"text":void 0;return!L||P[L]===v[L]})}function cp(u){return Sh("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(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${qc(y)}`).join(",")}}`;return JSON.stringify(u)}async function Jc(u){if(!await Bun.file(u).exists())throw Error(`Worker entry not found: ${u}`);let p;try{p=await Bun.build({entrypoints:[u],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(R){throw Error(`Bundling Worker ${u} failed: ${Dh(R)}`)}if(!p.success)throw Error(`Bundling Worker ${u} failed: ${p.logs.map((R)=>String(R.message??R)).join("; ")}`);if(p.outputs.length!==1)throw Error(`Bundling Worker ${u} produced ${p.outputs.length} files (${p.outputs.map((R)=>R.path).join(", ")}); a Worker is uploaded as a single module, so remove the dynamic imports or asset imports that split it.`);let h=p.outputs[0];if(h.kind!=="entry-point")throw Error(`Bundling Worker ${u} produced a ${h.kind} instead of an entry module`);let y=await h.text();return{name:`${wh(u,Ih(u))}.js`,content:y,type:Zc,size:new TextEncoder().encode(y).byteLength}}function Dh(u){if(u instanceof AggregateError&&u.errors.length>0)return u.errors.map((p)=>p instanceof Error?p.message:String(p?.message??p)).join("; ");return u instanceof Error?u.message:String(u)}import{isAbsolute as kh,resolve as Oh}from"node:path";var Nh="https://api.cloudflare.com/client/v4",xh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function Lh(u,p={}){let h=p.log??(()=>{}),y={workers:[],warnings:[]},R=Object.entries(u.infrastructure?.workers??u.workers??{});if(R.length===0)return h("Workers: none declared, skipping."),y;if(!p.apiToken||!p.accountId){let L=[!p.apiToken&&"CLOUDFLARE_API_TOKEN",!p.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),z=`Workers: ${R.length} Worker(s) declared but ${L} is not set, skipping.`;return h(z),y.warnings.push(z),y}let v=u.infrastructure?.r2??u.r2,P={workers:new Zs({apiToken:p.apiToken,accountId:p.accountId,fetch:p.fetch}),r2:new ai({apiToken:p.apiToken,accountId:p.accountId,fetch:p.fetch}),cloudflare:new H(p.apiToken,{zoneId:p.zoneId,accountId:p.accountId}),apiToken:p.apiToken,fetch:p.fetch??((L,z)=>fetch(L,z)),projectRoot:p.projectRoot??process.cwd(),dryRun:p.dryRun===!0,warnings:y.warnings,log:h,r2ConfigDomains:zh(v),r2Buckets:v,claimed:new Map};for(let[L,z]of R){let fe=z?.name;if(!fe||!xh.test(fe)){y.warnings.push(`Workers: '${L}' has an invalid name '${fe??""}' (1-63 chars: lowercase letters, digits, '-' and '_'), skipping.`);continue}if(!z.entry){y.warnings.push(`Workers: ${fe} has no entry, skipping.`);continue}h(`Workers: ${P.dryRun?"checking":"reconciling"} ${fe}...`);let me={name:fe,changes:[],domains:[]};y.workers.push(me),await Fh(z,me,P);for(let bt of me.changes)h(`Workers: ${fe}: ${bt}`)}return y}async function Fh(u,p,h){let y=u.name,R=kh(u.entry)?u.entry:Oh(h.projectRoot,u.entry),v;try{v=await Jc(R)}catch(L){throw Error(`Worker ${y}: ${di(L)}`)}p.changes.push(`bundled ${Uh(v.size)}`);let P={mainModule:v.name,modules:[{name:v.name,content:v.content,type:v.type}],bindings:dp(u,h),compatibilityDate:u.compatibilityDate??no,compatibilityFlags:u.compatibilityFlags??[]};if(h.dryRun){let L=await h.workers.getSettings(y);p.changes.push(L&&Ja(L,P,so(P))?"unchanged":"would upload")}else{let{action:L}=await h.workers.ensureModuleScript(y,P);p.changes.push(L==="unchanged"?"unchanged":"uploaded")}for(let L of Hh(u.customDomains))await _h(y,L,p,h)}async function _h(u,p,h,y){let R=(Ke)=>{h.domains.push({domain:p,status:Ke})},v=(Ke)=>{y.warnings.push(`Workers: ${Ke}`),R("conflict")},P=y.claimed.get(p);if(P&&P!==u){v(`${p} is declared on both ${P} and ${u}; leaving it on ${P}.`);return}y.claimed.set(p,u);let L=y.r2ConfigDomains.get(p);if(L){v(`${p} 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(y);if(z===null){R("error");return}let fe=z.find((Ke)=>Ke.hostname.toLowerCase()===p);if(fe?.service===u){R("active");return}if(fe){v(`${p} 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 Wh(y))?.get(p);if(me){v(`${p} 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 bt;try{bt=await y.cloudflare.zoneIdFor(p)}catch(Ke){y.warnings.push(`Workers: could not resolve the zone for ${p}, not attached: ${di(Ke)}`),R("error");return}let At=await Vh(y,bt,p);if(At.length>0){let Ke=At.map((Me)=>`${Me.type} ${Me.content}`).join(", ");v(`${p} already has a DNS record (${Ke}). 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(y.dryRun){h.changes.push(`would attach custom domain ${p}`),R("not attached");return}try{await y.workers.ensureCustomDomain(p,{service:u,zoneId:bt},z),h.changes.push(`custom domain ${p} attached`),z.push({id:"",hostname:p,service:u,zone_id:bt}),R("pending")}catch(Ke){y.warnings.push(`Workers: custom domain ${p} on ${u} failed: ${di(Ke)}`),R("error")}}async function Bh(u){if(u.attached!==void 0)return u.attached;try{u.attached=await u.workers.listCustomDomains()}catch(p){u.warnings.push(`Workers: could not list Worker custom domains, none attached: ${di(p)}`),u.attached=null}return u.attached}async function Wh(u){if(u.r2AccountDomains!==void 0)return u.r2AccountDomains;let p=new Map;try{let h=(await u.r2.listBuckets()).map((y)=>({name:y.name}));for(let y of Object.values(u.r2Buckets?.buckets??{}))if(y.jurisdiction&&y.jurisdiction!=="default")h.push({name:y.name,jurisdiction:y.jurisdiction});for(let y of h){let R=await u.r2.listCustomDomains(y.name,{jurisdiction:y.jurisdiction}).catch(()=>[]);for(let v of R)p.set(v.domain.toLowerCase(),y.name)}u.r2AccountDomains=p}catch(h){u.log(`Workers: could not check R2 custom domains (${di(h)}); relying on the DNS check.`),u.r2AccountDomains=null}return u.r2AccountDomains}async function Vh(u,p,h){try{let y=await u.fetch(`${Nh}/zones/${p}/dns_records?name=${encodeURIComponent(h)}&per_page=100`,{method:"GET",headers:{Authorization:`Bearer ${u.apiToken}`}}),R=await y.json();if(!R?.success)throw Error(`HTTP ${y.status}`);return(R.result??[]).filter((v)=>v.name?.toLowerCase()===h).map((v)=>({type:v.type??"?",content:v.content??""}))}catch(y){return u.log(`Workers: could not read DNS records for ${h} (${di(y)}); attaching anyway.`),[]}}function dp(u,p){let h=[],y=new Set,R=(P)=>{if(P===$n)return p.warnings.push(`Workers: ${u.name}: binding name ${$n} is reserved for ts-cloud, ignored.`),!1;if(y.has(P))return p.warnings.push(`Workers: ${u.name}: binding ${P} is declared twice; the first one wins.`),!1;return y.add(P),!0},v=new Map;for(let P of Object.values(p.r2Buckets?.buckets??{}))if(P.jurisdiction&&P.jurisdiction!=="default")v.set(P.name,P.jurisdiction);for(let[P,L]of Object.entries(u.bindings?.r2Buckets??{})){if(!R(P))continue;let z=v.get(L);h.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(R(P))h.push({type:"plain_text",name:P,text:String(L)});return h}function zh(u){let p=new Map;for(let h of Object.values(u?.buckets??{}))for(let y of h?.customDomains??[]){let R=pp(typeof y==="string"?y:y.domain);if(R)p.set(R,h.name)}return p}function Hh(u){return[...new Set((u??[]).map(pp).filter(Boolean))]}function pp(u){return(u??"").trim().replace(/\.$/,"").toLowerCase()}function Uh(u){if(u<1024)return`${u} B`;if(u<1048576)return`${(u/1024).toFixed(1)} KB`;return`${(u/1024/1024).toFixed(1)} MB`}function di(u){return u instanceof Error?u.message:String(u)}export{Pl as ABTestManager,ye as ACMClient,xr as ACMDnsValidator,ld as ACME_DIRECTORIES,Oe as AI,uu as API_IDEMPOTENCY_TTL_MS,du as API_TOKEN_DEFAULT_TTL_MS,lu as API_TOKEN_MAX_TTL_MS,ms as API_VERSION,Ie as AUTHORIZATION_CAPABILITIES,su as AUTH_ACTION_TOKEN_TTL_MS,ou as AUTH_MFA_CHALLENGE_TTL_MS,au as AUTH_OIDC_TRANSACTION_TTL_MS,st as AUTH_SESSION_ABSOLUTE_TTL_MS,iu as AUTH_SESSION_IDLE_TTL_MS,Ey as AWSAPIError,n as AWSClient,A as AWSCloudFormationClient,I as AWSCloudFrontClient,Tl as AWSConfigManager,JI as AWS_PSEUDO_PARAMETERS,_e as AWS_REGIONS,Fg as AcmeClient,nn as AlertEvaluator,Gi as AlertStore,No as AnomalyConfigStore,ml as ApiGateway,i as ApiServiceError,vc as ApplicationAutoScalingClient,un as Arn,_ as AssetHasher,Y as Auth,ds as AuthenticationStore,Ki as AutomationApiService,ls as AutomationIdentityStore,Ba as AwsAuroraDataAdapter,$a as AwsAuroraTransport,tc as AwsDatabaseBackupSource,Lr as AwsDriver,xa as AwsElastiCacheDataAdapter,Ma as AwsElastiCacheTransport,Zf as AwsIamCapabilityScanner,oc as AwsInfrastructureBackupSource,Na as AwsRdsDataAdapter,La as AwsRdsTransport,gh as AwsRegionalDriver,cc as AwsSecretsManagerConfigurationBackend,fm as AwsSpendTransport,dc as AwsSsmConfigurationBackend,Ts as BackupCoordinator,El as BackupManager,Za as BackupStore,Df as BatchProcessingManager,Hn as BedrockClient,Qn as BedrockRuntimeClient,yu as BitbucketSourceAdapter,Dl as BlueGreenManager,yf as BounceComplaintHandler,df as BuildOptimizationManager,Uu as BunDockerRuntime,hg as BunDockerVolumeRuntime,fg as BunFilesystemArchiveRuntime,Ce as CDN,Jo as CHAIN_HEADER,zt as CLOUDFLARE_MANAGED_RULE_PREFIX,dl as CLOUDFRONT_FAILOVER_STATUS_CODES,LC as COMMON_CROSS_ACCOUNT_ROLES,$n as CONTENT_HASH_BINDING,We as CONTROL_PLANE_SCHEMA_VERSION,Vo as Cache,rs as CanaryManager,of as CertificateManager,OA as CloudBlockVolumeDriver,io as CloudDriverFactory,rt as CloudError,Bm as CloudFormationBuilder,A as CloudFormationClient,I as CloudFrontClient,wl as CloudTrailManager,we as CloudWatchLogsClient,dd as CloudflarePagesProvider,H as CloudflareProvider,Vy as CommandHistory,ee as Communication,Yr as ComposeApplicationService,or as ComposeApplicationStore,Ht as ComprehendClient,a as Compute,hm as ComputeSpendTransport,zo as ConfigurationError,uc as ConfigurationService,ac as ConfigurationStore,Mn as ConnectClient,_a as ContainerDataAdapter,Ol as ContainerRegistryManager,sc as ControlPlaneBackupSource,Wa as ControlPlaneCleanupDriver,Li as ControlPlaneStore,Do as CounterTracker,xt as CredentialError,zm as CrossRegionReferenceManager,dy as DASHBOARD_ENTRY,ly as DASHBOARD_PORT_BASE,uy as DASHBOARD_PORT_SPAN,cy as DASHBOARD_STATE_DIR,sa as DEFAULT_ATTACK_MODE_HOURS,no as DEFAULT_COMPATIBILITY_DATE,Yd as DEFAULT_DDOS_THRESHOLDS,Im as DEFAULT_FAILOVER_STATUS_CODES,xd as DEFAULT_METER_MAPPINGS,Nd as DEFAULT_PRICE_BOOK,mn as DEFAULT_RECURSION_LIMITS,uo as DEFAULT_RPX_CERTS_DIR,te as DEFAULT_SERVICE_LIMITS,rl as DEFAULT_STATE_DIR,Pg as DEFAULT_STATIC_ASSET_EXTENSIONS,iy as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,zA as DEFAULT_TELEMETRY_POLICY,Zp as DEFAULT_THRESHOLDS,PA as DEPLOYMENT_QUEUE_KINDS,Wo as DEPTH_HEADER,tn as DETECTABLE_SIGNALS,_u as DIAGNOSTIC_PRESETS,Rf as DLQMonitoringManager,W as DNS,hf as DNSSECManager,ys as DataServiceLifecycle,ka as DataServiceStore,ur as Database,nf as DatabaseUserManager,q as DebugLogger,ny as DependencyGraph,Z as Deployment,Cy as DeploymentError,vl as DisasterRecoveryManager,Jn as DnsProviderFactory,Ir as DockerDataTransport,va as DockerDiscoveryAdapter,Xr as DockerNamedVolumeDriver,ic as DockerVolumeBackupSource,c as DurableOperationQueue,bo as DurableQueueWorker,Ue as DynamoDBClient,Vr as EC2Client,He as ECRClient,lt as ECSClient,Pr as EFSClient,Ic as ELBv2Client,LA as ENFORCEMENT_ACTIONS,Qi as ENFORCEMENT_DESCRIPTIONS,O as ENFORCEMENT_SEVERITY,Rp as ENVIRONMENT_LABEL,xu as EcsRuntimeAdapter,ia as EdgeRateLimiter,gt as ElastiCacheClient,f as Email,Cf as EmailAdvanced,Sf as EmailAnalyticsManager,jn as EmailClient,Ef as EmailHandlers,bf as EmailTemplateManager,Fa as EncryptedDataSecretStore,vy as ErrorCodes,Rr as EventBridgeClient,dh as EventBridgeJobAdapter,lc as ExternalConfigurationBackend,Go as FAILOVER_REPLICA_POLICY_SID,wf as FIFOQueueManager,Gh as FLY_MACHINES_API,am as FOCUS_VERSION,Al as FileCache,et as FileSystem,rc as FilesystemBackupSource,Qa as FleetService,Ua as FleetStore,$s as FlyApiError,fp as FlyClient,e as Fn,Su as GiteaSourceAdapter,hu as GithubSourceAdapter,Au as GitlabSourceAdapter,Km as GlobalResourceManager,Ge as GoDaddyProvider,Rl as GuardDutyManager,vt as HOST_SITES_DIR,Dy as HashCache,Uf as HealthCheckManager,Xe as HealthCheckRunner,Qr as HetznerClient,Pe as HetznerDriver,Re as IAMClient,Oc as IPV6_EXCLUDED_HOST_LABELS,cf as ImageScanningManager,vp as InfrastructureGenerator,Id as InvalidOperationTransitionError,Nt as JobLoader,lh as JobProviderReconciler,Da as JobService,Pa as JobStore,wr as KendraClient,Mf as LARAVEL_SERVERLESS_BUILD_STEPS,T as LambdaClient,gf as LambdaConcurrencyManager,ff as LambdaDLQManager,pf as LambdaDestinationsManager,lf as LambdaLayersManager,Ou as LambdaRuntimeAdapter,mf as LambdaVPCManager,uf as LambdaVersionsManager,xn as LocalEncryptedConfigurationBackend,nc as LogicalDatabaseBackupSource,Nl as LogsManager,uS as MANAGED_NODE_VERSIONS,id as MANAGEMENT_DASHBOARD_SITE,xm as MANAGEMENT_DASHBOARD_SITE_PREFIX,as as MAX_CONTROL_HOURS,bd as MAX_CONTROL_PLANE_ERROR_BYTES,Kp as MAX_CONTROL_PLANE_JSON_BYTES,To as METERS,_A as METER_KEYS,$A as MICRO_CENTS,em as MIN_PROJECTION_CONFIDENCE,Og as MTA_STS_PORT,Ka as MaintenanceService,za as MaintenanceStore,le as Messaging,ef as MetricsManager,tf as MigrationManager,Hm as MockCloudFormation,Vm as MockDynamoDB,Gm as MockS3,qo as Monitoring,Xm as MultiAccountManager,jm as MultiRegionManager,My as MultiStepProgress,S as Network,Qf as NetworkSecurityManager,Vi as NotificationRouter,Em as ORIGIN_CONNECTION_ATTEMPTS,vm as ORIGIN_CONNECTION_TIMEOUT,bm as ORIGIN_GROUP_ALLOWED_METHODS,zI as ORIGIN_GROUP_ID_SUFFIX,Cm as ORIGIN_GROUP_SELECTION_CRITERIA,bc as OpenSearchClient,Tt as OptimisticConcurrencyError,Ym as OrganizationManager,Hg as PAGES_MAX_FILE_BYTES,bS as PHP_DEFAULT_EXCLUDES,gS as PHP_LAYER_EXTENSIONS,wp as PROJECT_LABEL,mt as PROXIABLE_RECORD_TYPES,D as ParameterStore,rf as PerformanceManager,de as Permissions,Cc as PersonalizeClient,tt as Phone,vf as PhoneAdvanced,km as PhoneHandlers,Ga as PlacementService,Ha as PlacementStore,Gn as PollyClient,he as PorkbunProvider,Cn as PreDeployScanner,bl as PreviewEnvironmentManager,Jr as PreviewEnvironmentService,Je as PreviewEnvironmentStore,Cl as PreviewNotificationService,$y as ProgressBar,kl as ProgressiveDeploymentManager,oa as ProtectionControlStore,ry as Pseudo,J as Queue,$i as QueueCancellationError,Pf as QueueManagementManager,LI as QueuePresets,Io as QueueTimeoutError,Fn as R2ApiError,hn as R2NotEnabledError,ai as R2Provider,rp as R2_NOT_ENABLED_ERROR_CODE,Jl as RATE_LIMIT_KEY_SEPARATOR,ne as RDSClient,jy as RECOMMENDED_ACCOUNT_STRUCTURES,_C as RECOMMENDED_SCPS,Wf as RELEASE_QUEUE_KINDS,Qy as REPL,Gy as REPLCommandBuilder,Hy as REPLContext,Dp as ROLE_LABEL,Py as RateLimiter,$I as RealtimePresets,cm as RecordingSpendTransport,is as RecursionGuard,Bt as Redirects,Wm as RegionPairManager,qa as RegionService,Va as RegionStore,Ze as Registry,Gt as RekognitionClient,Ot as ReleaseService,fa as ReleaseStore,uh as RemoteBuildService,Bl as ReplicaManager,Hf as ResourceManagementManager,ae as RetryableOperationError,b as Route53Client,Sc as Route53DomainsClient,ie as Route53Provider,Af as Route53ResolverManager,Ll as Route53RoutingManager,ve as RuntimeOperationService,wa as RuntimeStreamRegistry,ec as S3BackupDestinationAdapter,o as S3Client,V as S3Error,Cu as SECRET_PATTERNS,sm as SENSITIVITY_THRESHOLDS,pt as SESClient,X as SMS,ut as SNSClient,mm as SPEND_CYCLE_SECONDS,jd as SPEND_GATE_SETTING,XA as SPEND_LEASE_SETTING,pe as SQSClient,ke as SSH_BOOTSTRAP_VERSION,hi as SSH_PREFLIGHT_SCRIPT,Be as SSMClient,ym as STATE_DIR_ENV_VAR,wi as STATIC_SITE_ZONE_SETTINGS,ul as STORAGE_FAILOVER_METADATA_KEY,Te as STSClient,Vn as SchedulerClient,gr as Search,En as SecretFindingScanner,Yi as Secrets,xl as SecretsManager,re as SecretsManagerClient,sf as SecretsRotationManager,E as Security,fr as SecurityHubManager,bn as SecurityPostureStore,_t as SecurityScannerRunner,af as SecurityScanningManager,If as SenderReputationManager,ch as ServerCronJobAdapter,Oa as ServerDataAdapter,vo as ServerPathVolumeDriver,_l as ServiceMeshManager,pl as Sftp,xo as SignalSource,Tf as SmsAdvanced,qt as SmsClient,Nm as SmsHandlers,Rc as SmsVoiceClient,ha as SourceConnectionStore,yr as SourceProviderError,zd as SpendCapError,rn as SpendGate,gm as SpendLoopLease,Mo as SpendNotificationRouter,pm as SpendRunner,cr as SpendService,Fi as SpendStore,Fy as Spinner,Hr as SshDriver,wn as SshFleetDriver,Jm as StackDependencyManager,WI as StacksIntegration,Ff as StaticSiteManager,xe as Storage,zl as StorageAdvancedManager,qn as SupportClient,hr as SyntheticsManager,Qu as SystemFleetSshTransport,It as SystemSshTransport,Ta as SystemdDiscoveryAdapter,Xo as TRACE_HEADER,Uy as TaskList,Dt as TelemetryStore,al as TemplateBuilder,yl as TemplateCache,Vt as TextractClient,Un as TranscribeClient,Tr as TranslateClient,fh as TransportDisasterRecoveryDriver,mh as TransportPlatformMaintenanceDriver,Ss as TransportRemoteBuildDriver,Ca as TrivyImageScanner,ma as TsCloudApiError,gu as TsCloudClient,JA as URGENT_SPEND_EVENTS,tm as USER_VISIBLE_ACTIONS,ja as UnavailableRegionalDriver,Ae as UnifiedDnsValidator,Ao as UnsupportedSchemaVersionError,$m as ValidationError,Dr as VoiceClient,Eo as VolumeService,sr as VolumeStore,Zc as WORKER_MODULE_TYPE,li as WorkersApiError,Bs as WorkersPermissionError,Zs as WorkersProvider,ay as Workflow,Zm as XRayManager,tS as abTestManager,pu as activateImmutableRelease,Ig as addDns01ChallengeRecord,Dn as addSiteToCloudConfig,$t as ageSeconds,_d as aggregateDeltas,qp as allocateSitePorts,Pm as amazonLinuxImageId,oy as amazonLinuxImageParameter,qI as analyzeStackDiff,Hi as anomalyOptionsForSignal,aa as applyControlsToDdos,tu as applyControlsToRateLimits,Vs as applyDeclaredZoneSettings,gi as applyHetznerVolumes,an as applyMitigationFactor,lA as applyPlan,Ks as applyZoneMigration,$l as artifactKey,Pt as assertOriginGroupMethods,us as assertReleaseStrategy,jA as assertSpendAllows,fA as attachConflicts,hA as attachIsViable,mA as attachPreconditions,Ru as attachProvenanceToRelease,Ea as attachSbomToRelease,Tu as attachVulnerabilitySummary,zf as authEncryptionKeyFile,x as authorizeOrganization,oh as authorizeRuntimePath,uC as autocomplete,Wy as awsConfigManager,pg as backupCredentialStatus,zy as backupManager,Lb as batch,wE as batchProcessingManager,ga as beginOidcAuthorization,Zy as blueGreenManager,IE as bounceComplaintHandler,wt as budgetWindow,hc as buildAndPushServerlessImage,PE as buildBunRuntimeLayerZip,CA as buildCertificatePackScript,SA as buildCertificateStateScript,EA as buildCertificateUnpackScript,fl as buildCloudFormationTemplate,Yc as buildCloudInitFirstBoot,Td as buildComposeLogsCommand,OI as buildComposeRuntimeCommand,_I as buildComposeScaleCommand,wd as buildComposeShellCommand,ti as buildComputeStorageInstallScript,$r as buildComputeStorageSiteScript,Hp as buildDrainSourceScript,tA as buildDrainedSiteScanScript,gl as buildFailoverReplicaPolicyStatement,Cr as buildFunctionEnv,Qp as buildHealthGateScript,ni as buildHostCleanupDeployScript,to as buildHostCleanupInstallScript,ri as buildHostCleanupScript,Oi as buildHostSitePortsScript,Ji as buildMailEnv,ao as buildManagementDashboardArtifact,qS as buildMediaCdnPlan,xg as buildMtaStsPolicy,Mh as buildMtaStsServer,DE as buildNodeRuntimeLayerZip,uE as buildOptimizationManager,ll as buildOriginGroup,ln as buildOriginGroups,kc as buildOriginGuardRule,Op as buildPauseWorkersScript,xE as buildPhpRuntimeLayerZip,Dm as buildReplicationConfiguration,Rm as buildReplicationRole,Mp as buildRestoreScript,B as buildRpxConfig,Ne as buildRpxFragmentRefreshScript,gA as buildSetHostnameScript,si as buildSiteDeployScript,$p as buildSnapshotScript,Gp as buildSourceStateScript,ci as buildSshArgs,mi as buildSshBootstrapScript,Pc as buildStaticSiteCacheRules,oi as buildStaticSiteDeployScript,Fp as buildTargetStateScript,lp as buildUploadForm,_p as buildWorkersStateScript,Jc as bundleWorker,Pu as bytes,ip as cacheRuleParameters,eS as canaryManager,Rn as canonicalJson,Lt as capabilities,br as capacity,qb as categorizeChanges,cE as certificateManager,bA as certificatesMatch,wb as checkIAMPermissions,Of as checkInvocation,Db as checkServiceQuotas,ky as chunk,pR as cleanupDns01Challenge,DS as clearSigningKeyCache,ya as cloneSourceBinding,Ny as cloudConfigSchema,op as cloudDrivers,Jy as cloudTrailManager,gd as collectAssets,ta as collectPhpAppEntries,kg as collectServerDnsDomains,Wp as completeComposeVolumeDeletion,pa as completeOidcAuthorization,mb as composePresets,So as composeProjectName,Fl as composeServerlessAppTemplate,ZA as compositeSpendTransport,Qt as compressBackup,_S as config,Dc as configOrigins,Mu as connectionGuidance,aS as containerRegistryManager,RA as controlPlaneDatabaseFile,yd as controlPlaneMigrations,rb as createApiBackendPreset,ba as createApiV1Handler,VS as createAsgBuildDriver,mg as createBackupQueueHandlers,IS as createCliHandler,F as createCloudDriver,ed as createCloudFrontPolicy,Cb as createCredentialProvider,gb as createDashboardSite,ab as createDataPipelinePreset,Fu as createDataServiceQueueHandlers,Rd as createDeploymentQueueHandlers,N as createDnsProvider,GS as createEcsBuildDriver,Kd as createEnforcementHandlers,Mm as createError,hl as createExistingStaticFullStackPreset,Hu as createFleetQueueHandlers,tb as createFullStackAppPreset,Xs as createGoDaddyValidator,BE as createHandlers,yS as createHttpHandler,ib as createJamstackPreset,$u as createJobQueueHandlers,lb as createLaravelPreset,cb as createMLApiPreset,Wu as createMaintenanceQueueHandlers,zS as createMediaAccessToken,sb as createMicroservicesPreset,Zb as createMockAWS,YI as createNodeJsServerPreset,ZI as createNodeJsServerlessPreset,Ls as createObjectStorageClient,Js as createPorkbunValidator,fb as createPreset,ra as createPresignedUrl,ES as createPresignedUrlAsync,SS as createQueueHandler,ob as createRealtimeAppPreset,Vu as createRegionQueueHandlers,wu as createReleaseProvenance,fu as createReleaseQueueHandlers,QS as createRemoteBuildQueueHandlers,Ys as createRoute53Validator,sh as createRuntimeAdapters,by as createS3Client,HS as createServerBuildDriver,ub as createServerlessLaravelPreset,eb as createServerlessNodePreset,Dg as createSmsInfrastructure,at as createSourceAdapter,XI as createStaticSitePreset,db as createTraditionalWebAppPreset,Dd as createVolumeQueueHandlers,nb as createWordPressPreset,nt as createZip,SC as crossRegionReferenceManager,On as dashboardActions,oo as dashboardCredentialsFile,Tn as dataServiceCapabilities,oE as databaseUserManager,nu as decodeBase32,Fe as decompressBackup,Th as decryptBackup,ca as defaultConfig,Qm as defaultLocalConfig,Yl as defaultRateLimitRules,Br as delegateZone,Hs as delegateZoneFromConfig,dg as deleteFailoverReplicaBuckets,mc as deleteStaticSite,od as deployAllComputeSites,Xa as deployServerlessApp,lg as deploySite,co as deploySiteRelease,Ps as deployStaticSite,fc as deployStaticSiteFull,_n as deployStaticSiteWithExternalDns,Ln as deployStaticSiteWithExternalDnsFull,Zh as deployToFly,ol as deploymentCoexistenceError,gy as deriveManagementDashboardPort,Gs as describeDelegation,eu as describePosture,qs as describeZoneSettings,ah as desiredJobProviderState,im as detectAnomalies,Sm as detectDeploymentTargets,Nc as detectDnsProvider,Gd as detectLatestAnomaly,vb as detectMisconfigurations,Kl as detectServiceRegion,Ed as diffCompose,Hb as diffTemplates,Aa as discoverGitRefs,ua as discoverOidcProvider,ku as discoverRuntimeInventory,TE as dlqMonitoringManager,Bc as dnsProviders,yE as dnssecManager,rh as dockerWorkloads,Is as documentDigest,jc as domainStatus,Ky as drManager,qe as driverStatePath,Nu as ecsWorkloads,ir as effectiveCapabilities,bE as emailAnalyticsManager,EE as emailTemplateManager,cs as encodeBase32,vh as encryptBackup,Du as ensureDefaultSecurityPolicies,og as ensureFailoverReplicaBuckets,Ei as ensureFirewall,Ri as ensureManagementDashboard,vi as ensureServer,Ci as ensureSshKey,oe as escapeSecLang,$d as evaluateBudget,yi as evaluatePreflight,$o as evaluateTelemetryAlertRules,Lu as eventBridgeScheduleInput,AS as eventToRequest,GA as ewma,Cd as exportCompose,js as exportRoute53Zone,_m as extendPreset,vE as fifoQueueManager,_b as findChangedFiles,Xp as findMapping,Jp as findPriceEntry,qh as flyDeployOptions,Qc as flyIpType,yp as flyMachineConfig,UC as formatAccountStructure,AA as formatAttachPlan,nC as formatBytes,sn as formatCents,jI as formatDiff,nA as formatDrainedSiteRefusal,iC as formatDuration,pC as formatFlagSuggestions,hC as formatHistory,AC as formatHistoryStats,aA as formatInventory,oC as formatKeyValue,sC as formatList,dA as formatPlan,Ii as formatPreflightFindings,rC as formatProgressBar,qy as formatRegion,NC as formatRegionList,Yf as formatScanResults,aC as formatSuggestion,eC as formatTable,en as formatTimeToExhaustion,tC as formatTree,Ay as fromEC2Metadata,yy as fromECSMetadata,fy as fromEnvironment,hy as fromSharedCredentials,Sy as fromWebIdentity,Hl as functionFingerprint,mo as gatewayHostnames,Ql as generateAppImageDockerfile,eE as generateApprovalConfig,kf as generateBootstrap,Oy as generateCleanupWorkflow,_y as generateCostReportWorkflow,MC as generateCrossAccountRoleCF,Eu as generateCycloneDxSbom,XC as generateDeploymentConfig,jC as generateDeploymentPipeline,QC as generateDeploymentWorkflow,pc as generateExternalDnsStaticSiteTemplate,uR as generateHttpsServerCode,vu as generateImageSbom,lR as generateLetsEncryptUserData,t as generateLogicalId,JC as generateManualPipeline,qC as generateMatrixWorkflow,YC as generateMultiEnvConfig,zC as generateMultiEnvPipeline,HC as generateMultiEnvWorkflow,GC as generatePRPreviewWorkflow,tE as generateParallelConfig,$f as generatePhpFpmConfig,Nf as generatePhpLayerDockerfile,KC as generatePreviewPipeline,xy as generatePreviewWorkflow,r as generateResourceName,ZC as generateScheduledConfig,WC as generateScheduledPipeline,VC as generateScheduledWorkflow,Ds as generateStaticSiteTemplate,M as generateUbuntuAppCloudInit,Lm as getAccountId,EC as getAllRegions,DC as getClosestRegion,mC as getCommandUsage,DA as getComposeTemplate,Vf as getConfig,dC as getContextualHelp,es as getCredentials,jb as getDeploymentStrategy,zb as getDiffStats,Gb as getDiffSummary,Ty as getErrorDetails,Il as getLocalConfig,Xb as getLocalCredentials,Jb as getLocalEndpoint,Yb as getLocalEnvVars,Pb as getQuotaUsageSummary,$C as getRecommendedStructure,ts as getRegion,BC as getRegionStats,TC as getRegionsByCompliance,vC as getRegionsByLocation,wC as getRegionsByPricingTier,wy as getRequiredPermissions,PS as getSigningKeyCacheSize,Rg as getSmsInfrastructureStatus,MI as getTimestamp,na as globMatches,lo as globToRegex,IC as globalResourceManager,Ui as governingLimitCents,ag as grantFailoverReplicaAccess,Xy as guardDutyManager,Fo as handleSpendRequest,po as hasAutoWwwVariant,pr as hasManagementDashboardSite,Ad as hasProxyUpstream,Nb as hashBuffer,Bb as hashDirectory,Fm as hashFile,xb as hashManifest,Um as hashString,_E as healthCheckManager,Xn as hostAcceptsIpv6,jt as hostCondition,da as hotp,Zr as hourBucket,HA as hourBucketsBetween,lE as imageScanningManager,Es as infraEnvFromOutputs,Vl as inspectInvocation,fS as installRecursionFetch,Ns as invalidateCache,xf as invocationContext,sy as isArmInstanceType,cC as isLikelyTypo,Zn as isLocalDatabase,Wb as isLocalDevelopment,mr as isManagementDashboardSiteName,kr as isNameserverRegistrar,kS as isNodeCryptoAvailable,Hd as isOperationAllowed,Lo as isQuietHours,Ho as isS3RestEndpoint,Pi as isSafePattern,il as isStateDirConfigured,sl as isStatePath,on as isValidCidr,RC as isValidRegion,Mi as isValidTimeZone,NS as isWebCryptoAvailable,Nr as isZoneHost,vn as jobProviderCapability,_s as keyMatchesFilters,mE as lambdaConcurrencyManager,AE as lambdaDLQManager,fE as lambdaDestinationsManager,gE as lambdaLayersManager,hE as lambdaVPCManager,pE as lambdaVersionsManager,Bu as lambdaWorkloads,ql as laravelServerlessEnvDefaults,Wr as listComposeTemplates,ps as listSourceReferences,ru as loadCloudConfig,dr as loadTelemetryPolicy,nS as logsManager,Vd as lookbackHoursForSignal,ty as mailEnabled,Ye as mailFirewallPorts,dn as mailWebmailSites,ph as maintenanceWindowOpen,Gf as makeAWSRequest,TS as makeAWSRequestAsync,vS as makeAWSRequestOnce,sp as managedRuleInSync,Om as managementDashboardSiteName,qu as manifestDigest,An as matchTotpCounter,KS as mediaObjectHeaders,ko as median,rm as medianAbsoluteDeviation,Md as mergeDecisions,gn as mergeInfrastructure,UA as mergePriceBooks,Od as meterTelemetry,nE as metricsManager,Cg as migrateObjectStorage,iE as migrationManager,xC as multiAccountManager,yC as multiRegionManager,mR as needsRenewal,LE as networkSecurityManager,Mt as nextScheduleRuns,De as normalizePublicIpv6,Le as normalizeRuntimeStatus,ct as normalizeScheduleExpression,Jf as normalizeSourceEvent,Ve as normalizeSshPublicKey,dm as normalizeTelemetryPolicy,xi as occupiedHostPorts,Ia as openApiDocument,Oo as optionsForSignal,OC as organizationManager,jl as packagePhpApp,pn as packageServerlessApp,pd as pagesAssetHash,Gg as pagesDnsRecord,Sl as parallel,$b as parallelMap,Mb as parallelWithRetry,IA as parseCertificateState,Gl as parseChain,Kr as parseCompose,BI as parseComposeCatalog,th as parseDockerInspect,Ag as parseDotenv,rA as parseDrainedSites,_i as parseHostSiteFragments,RS as parseJSONResponse,Ai as parsePreflightFacts,Vp as parseSourceDrained,nh as parseSystemdRecords,Up as parseTargetReady,hd as parseUpstreamPort,Lp as parseWorkersPaused,wS as parseXMLResponse,ji as pathTemplate,md as pendingSteps,Po as percentOfLimit,sE as performanceManager,Ul as phpLayerBuildStage,pS as phpLayerPackages,fn as phpRuntimeLayerAssets,xI as planComposeTemplateUpgrade,Fd as planEnforcement,ui as planHetznerVolumes,Bp as planIsDestructive,Am as planMitigation,uA as planServerRename,vA as planSiteMove,zs as planZoneMigration,Wt as policyTag,Si as preflightFailed,By as previewManager,Ly as previewNotifications,Ft as previewSchedule,QA as previousBudgetWindow,wo as priceUsage,MA as priceUsageLines,sA as probeHostRoutes,Uc as probeOriginTls,Qb as processInChunks,Iu as processSourceWebhook,hs as productionChangeReview,rS as progressiveDeploymentManager,Ld as projectSpend,Yo as propagationHeaders,Ac as providerEndpoint,ju as publicKeyFingerprint,Kn as qualifyName,RE as queueManagementManager,Ob as quickHash,np as r2Endpoint,Jg as r2S3Credentials,Xl as rateLimitHeaders,os as rateLimitKey,je as readDriverState,oA as reconcile,Bg as reconcileAddressRecords,Wg as reconcileCloudflareCdn,Lh as reconcileCloudflareWorkers,Qs as reconcileDeclaredRecords,US as reconcileJobObservation,Qg as reconcileR2Buckets,In as reconcileSourceWebhook,fs as recordDashboardHostPosture,$S as recordPreDeploySecretScan,MS as recordSkippedSecretScan,Zo as recursionBlockedResponse,$e as redactRuntimeConfig,Xd as redactTelemetryText,qi as redactTelemetryValue,kn as redeployServerlessApp,bC as regionPairManager,Sn as releaseStrategyCapabilities,Kf as releaseTrafficPlan,Di as reloadRpxGateway,Os as remapKey,Ng as removeAddressRecords,vg as removeDns01ChallengeRecord,Pn as removeSiteFromCloudConfig,bu as removeSourceWebhook,xc as removeStaleServerAddressRecords,vd as renderComposeTemplate,Wi as renderDdosInstallScript,tl as renderNftablesRuleset,As as renderServerCron,el as renderSysctlFile,cd as renderWafConfig,ki as renderWafInstallScript,ad as renewRpxCertificates,sS as replicaManager,ey as requestHash,Vb as requiresReplacement,kE as resetRecursionRuntime,NE as resolveApp,g as resolveAppDatabase,pA as resolveAttachTarget,ot as resolveAuthEncryptionKey,be as resolveCloudProvider,zg as resolveCloudflareCdnPlan,ei as resolveComputeVolumes,jo as resolveCredentials,Rs as resolveDashboardAction,sd as resolveDashboardAuth,py as resolveDashboardDomain,my as resolveDashboardDomains,Us as resolveDeclaredRecords,VI as resolveDeployBucketName,K as resolveDeploymentMode,ii as resolveExecStart,Qo as resolveFailoverStatusCodes,Hc as resolveHetznerApiToken,Fr as resolveHostCleanupConfig,w as resolveMailProxy,C as resolveMailService,pb as resolveManagementDashboardSite,Zi as resolveManagementDashboardSites,yc as resolveObjectStorage,ce as resolveOriginConnection,cA as resolvePlan,m as resolveProjectStackName,zr as resolveProxyUpstreams,Ml as resolveQueueNames,kA as resolveQueuedDeploymentCommand,Ar as resolveQueues,mS as resolveRecursionConfig,Iy as resolveRegion,ge as resolveRuntimeInventory,lr as resolveServerlessAppStackName,cl as resolveServerlessArtifactBucketName,Xi as resolveServerlessAssetBucketName,ns as resolveServerlessRuntime,HI as resolveSiteBucketName,ho as resolveSiteDeployTarget,d as resolveSiteKind,QI as resolveSiteResourceName,UI as resolveSiteStackName,fi as resolveSshSettings,l as resolveStatePath,GI as resolveStorageBucketName,Tm as resolveStorageFailover,tr as resolveUiSource,ud as resolveZoneApex,$E as resourceManagementManager,Lf as responseToResult,nm as robustZScore,nr as roleCapabilities,mu as rollbackImmutableRelease,Nn as rollbackServerlessApp,FA as roundCents,SE as route53ResolverManager,dS as route53RoutingManager,om as routeMatches,Pp as routesFromFragments,ss as ruleMatches,lS as runBuildHooks,Ud as runEnforcement,ea as runPhpBuildHooks,dt as runRemoteCommand,Ee as runtimeId,Qe as s3OriginBucket,wm as s3RegionalDomain,xs as sameCorsRules,Fs as sameLifecycleRules,Wn as sameNameservers,ws as sanitizeCloudConfig,s as sanitizeControlPlaneValue,FI as sanitizeName,cu as sanitizeOidcReturnPath,Wd as saveTelemetryPolicy,Xf as scanForSecrets,Sd as scopeContains,Rt as scopeKey,Mc as scpUpload,lC as searchCommands,yo as searchControlPlane,oS as secretsManager,aE as secretsRotationManager,FS as secureContainerRelease,Yy as securityHubManager,dE as securityScanningManager,ue as securityScope,cg as seedFailoverReplicas,yn as sendAuthenticationEmail,CE as senderReputationManager,Fb as sequence,yg as serializeDotenv,Ti as serverPublicIpv4,cS as serviceMeshManager,rg as setAttachToInCloudConfig,Er as setMaintenance,bs as setSitePropertyInCloudConfig,nl as setStateDir,dR as setupDns01Challenge,wc as setupSmsInfrastructure,Ko as sha256,hS as sharedRecursionGuard,Bf as sharedRuntimeLoop,zp as shipsARelease,WS as signCloudFrontCookies,xS as signCloudFrontUrl,k as signRequest,Wl as signRequestAsync,Bo as signalDefinition,U as siteInstallBase,Bi as siteMoveArchivePath,yA as siteMoveCertArchivePath,fd as siteUnitGlob,um as spendNotificationText,Uo as spendOpenApiPaths,Ur as sshExec,Se as sshExecOrThrow,CC as stackDependencyManager,gc as startLocalDashboardServer,YA as startSpendLoop,cn as stateDir,Q as statePath,OE as staticSiteManager,CS as storageAdvancedManager,KI as storageFailoverReplicasFromTemplate,VA as streamFocusJsonl,Qd as strongestActiveAction,qm as suggestCommand,gC as suggestFlags,Rb as suggestIAMPolicy,kb as suggestQuotaIncrease,kC as suggestRegionPairs,PC as suggestRegions,gs as syncSourceRepositories,Pd as synchronizeComposeVolumes,Sg as synchronizeConfiguredConfiguration,Ra as synchronizeConfiguredJobs,iS as syntheticsManager,Zd as sysctlHardening,ih as systemdWorkloads,WA as telemetryBucketLabel,zi as telemetryCursor,Jd as telemetryEstimatedMonthlyCost,KA as telemetryPercentile,lm as telemetryPolicyKey,Ry as templateCache,kp as tenantsOf,Sa as testSourceConnection,kd as tieredMicroCents,ap as toApiLifecycleRule,zc as toCloudflareZoneSettings,_o as toFocusJsonl,qd as toFocusRecords,iA as toInventoryServer,qf as totp,la as totpUri,Np as unaccountedSites,eh as unsupportedCapabilities,NA as unsupportedVolumeCapabilities,Ku as updateCompatibility,Ju as updateSiteInCloudConfig,ks as uploadStaticFiles,Yp as usageDeltaKey,ar as utcInstantOfLocal,FC as validateAccountStructure,Kb as validateAgainstSchema,xA as validateAttachment,Eh as validateBackupDestination,fC as validateCommand,Eb as validateConfiguration,Tb as validateCredentials,jp as validateDeploymentConfig,BA as validateMountPath,kt as validateOriginGroups,ug as validateResourceLimits,xp as validateServerName,Ep as validateTemplate,sg as validateTemplateSize,_c as verifyAddressRecord,LS as verifyArtifactSignature,jS as verifyMediaAccessToken,jf as verifyTotp,zu as verifyUpdateSignature,Ws as verifyZoneParity,Co as volumeCapabilities,Ip as wafEventTelemetry,Fc as waitForCloudInit,ht as waitForSsh,Sr as webhookEndpoint,Ib as withCDN,Sb as withCache,up as withContentHash,yb as withDatabase,_f as withInvocation,hb as withMonitoring,bb as withQueue,Ab as withSecurity,Ub as withTimeout,dp as workerBindings,so as workerContentHash,Ja as workerInSync,se as wrapCloudInitUserData,yt as writeDriverState,rE as xrayManager,Gu as zeroCapacity,qA as zeroFill,Bd as zoneOffsetMs,Ro as zonedParts};