@stacksjs/ts-cloud 0.16.59 → 0.16.62
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.
- package/dist/aws/index.js +1 -1
- package/dist/bin/{chunk-x8gqdr3m.js → chunk-0ejp168p.js} +1 -1
- package/dist/bin/chunk-0v5tsfx5.js +1 -0
- package/dist/bin/{chunk-qt6rjw6v.js → chunk-2avtspqd.js} +5 -5
- package/dist/bin/{chunk-hs2r1nsg.js → chunk-38qy0dj2.js} +3 -3
- package/dist/bin/chunk-3x52axr2.js +1 -0
- package/dist/bin/{chunk-bss9yv52.js → chunk-5ad4b744.js} +2 -2
- package/dist/bin/chunk-67mww6gq.js +1 -0
- package/dist/bin/{chunk-0dmf1a2q.js → chunk-6da5c33e.js} +2 -2
- package/dist/bin/chunk-6r04kx46.js +2 -0
- package/dist/bin/{chunk-p6qa21fr.js → chunk-71b4t3d8.js} +2 -2
- package/dist/bin/chunk-7khzyn7k.js +1 -0
- package/dist/bin/{chunk-rq0wxfyp.js → chunk-8bgfn8ek.js} +3 -3
- package/dist/bin/{chunk-9t78j764.js → chunk-90ds3vw7.js} +1 -1
- package/dist/bin/chunk-97494wnx.js +1 -0
- package/dist/bin/{chunk-jvbe549p.js → chunk-9pj5r0x0.js} +1 -1
- package/dist/bin/{chunk-sy4zws71.js → chunk-aekwpste.js} +1 -1
- package/dist/bin/chunk-agmznzms.js +1 -0
- package/dist/bin/chunk-ambf5hpg.js +1 -0
- package/dist/bin/chunk-b39h9as6.js +1 -0
- package/dist/bin/{chunk-27rh6te6.js → chunk-cf2eyje1.js} +7 -7
- package/dist/bin/{chunk-z6xnegpe.js → chunk-d0q93ecd.js} +5 -5
- package/dist/bin/{chunk-yydj05nb.js → chunk-d38cyam8.js} +5 -5
- package/dist/bin/chunk-dfgzav9j.js +1 -0
- package/dist/bin/{chunk-3mhzd931.js → chunk-e51cd46z.js} +2 -2
- package/dist/bin/chunk-ekwfpppj.js +1 -0
- package/dist/bin/{chunk-acn2c3ep.js → chunk-favx96qj.js} +5 -5
- package/dist/bin/chunk-g0w0jec3.js +1 -0
- package/dist/bin/{chunk-nn1w8fvd.js → chunk-g2kjjb1a.js} +95 -95
- package/dist/bin/chunk-g514nb80.js +1 -0
- package/dist/bin/chunk-hknz7fsr.js +1 -0
- package/dist/bin/chunk-j9yq3b4d.js +2 -0
- package/dist/bin/chunk-k8qrjnyg.js +1 -0
- package/dist/bin/{chunk-dwq5vgdc.js → chunk-kmxkwznm.js} +5 -5
- package/dist/bin/chunk-kqstefmv.js +1 -0
- package/dist/bin/chunk-mk2h37pm.js +1 -0
- package/dist/bin/{chunk-8z2436dv.js → chunk-mver6psb.js} +2 -2
- package/dist/bin/{chunk-0rvg0ma7.js → chunk-n667tnf3.js} +3 -3
- package/dist/bin/{chunk-p23wfy3r.js → chunk-nn8k84cd.js} +1 -1
- package/dist/bin/chunk-nrtjmzzn.js +1 -0
- package/dist/bin/{chunk-1mb679gj.js → chunk-pe18g092.js} +3 -3
- package/dist/bin/chunk-q3rch5hc.js +1 -0
- package/dist/bin/{chunk-0xfy78nc.js → chunk-qpvydcfm.js} +5 -5
- package/dist/bin/chunk-qqb6h33k.js +1 -0
- package/dist/bin/chunk-r1p3k2tn.js +1 -0
- package/dist/bin/{chunk-c1dwwtkq.js → chunk-rgddxcrr.js} +112 -97
- package/dist/bin/{chunk-cvps1wjq.js → chunk-sbjzewvk.js} +6 -6
- package/dist/bin/chunk-t8xq3v3j.js +1 -0
- package/dist/bin/{chunk-mdcv2vw1.js → chunk-tcn6qcc4.js} +2 -2
- package/dist/bin/{chunk-gr1ra9nj.js → chunk-tg3vzzc4.js} +2 -2
- package/dist/bin/{chunk-551brgyd.js → chunk-tpttr74v.js} +5 -5
- package/dist/bin/{chunk-0f8jky3x.js → chunk-tw6z2mvh.js} +15 -15
- package/dist/bin/{chunk-hc9tnwqs.js → chunk-v3j9wgmn.js} +200 -200
- package/dist/bin/{chunk-r99jcm9t.js → chunk-v5x06h8w.js} +5 -5
- package/dist/bin/{chunk-9hb2wkkt.js → chunk-v6jm8dsa.js} +1 -1
- package/dist/bin/{chunk-06rjt80a.js → chunk-vbq4ten8.js} +3 -3
- package/dist/bin/chunk-xb48vxmk.js +1 -0
- package/dist/bin/{chunk-e19dabas.js → chunk-ya1413jw.js} +2 -2
- package/dist/bin/chunk-yehb738r.js +1 -0
- package/dist/bin/chunk-ythfx8pv.js +1 -0
- package/dist/bin/{chunk-95djv2ja.js → chunk-zesb85ra.js} +1 -1
- package/dist/bin/{chunk-rbyrd9we.js → chunk-zs0q8sh5.js} +1 -1
- package/dist/bin/chunk-zynfzzjk.js +1 -0
- package/dist/bin/cli.js +292 -292
- package/dist/bin/dashboard-server.js +1 -1
- package/dist/{chunk-b1v1301e.js → chunk-2phe49y7.js} +25 -25
- package/dist/chunk-3b08b1zx.js +1 -0
- package/dist/{chunk-pqyv47m4.js → chunk-7mw4x3ay.js} +1 -1
- package/dist/{chunk-j2bpd2v9.js → chunk-7s7w8kzc.js} +5 -5
- package/dist/{chunk-c87bg8wk.js → chunk-8jqv6wh7.js} +2 -2
- package/dist/{chunk-2pqjw8pq.js → chunk-8z3jfyk8.js} +7 -7
- package/dist/chunk-9sdkhmav.js +1 -0
- package/dist/{chunk-y9q6sv2q.js → chunk-b0s2605f.js} +6 -6
- package/dist/{chunk-tj3egckk.js → chunk-betvtvy7.js} +3 -3
- package/dist/{chunk-qb8cf1ss.js → chunk-bn3jfrg5.js} +2 -2
- package/dist/{chunk-mkvqcd3x.js → chunk-bydj8p3h.js} +2 -2
- package/dist/{chunk-95qrgpjk.js → chunk-e97qhzfe.js} +8 -8
- package/dist/{chunk-1a7ms51t.js → chunk-et77ydjb.js} +4 -4
- package/dist/{chunk-yece1kc4.js → chunk-f512g4fq.js} +5 -5
- package/dist/chunk-fc9n4dpq.js +1 -0
- package/dist/{chunk-x8fg8zg8.js → chunk-g0bh9atv.js} +2 -2
- package/dist/{chunk-6ky22rmg.js → chunk-gj4hj95p.js} +1 -1
- package/dist/{chunk-7bzyjfb1.js → chunk-h5j27a4h.js} +106 -101
- package/dist/{chunk-rxh9dkpd.js → chunk-k2bb62em.js} +4 -4
- package/dist/chunk-kfcct0jz.js +1 -0
- package/dist/{chunk-nq6cqjfv.js → chunk-mqbsnpsv.js} +1 -1
- package/dist/{chunk-dp0hvmd0.js → chunk-n0xw26th.js} +1 -1
- package/dist/{chunk-w174jbbm.js → chunk-n3sydv3m.js} +1 -1
- package/dist/{chunk-za23j2mq.js → chunk-p921pam0.js} +118 -118
- package/dist/{chunk-jg2m713e.js → chunk-pjdp30dn.js} +2 -2
- package/dist/{chunk-qdaj5yyh.js → chunk-r41cawtf.js} +5 -5
- package/dist/{chunk-z5as1fa7.js → chunk-r9ydamw0.js} +102 -102
- package/dist/{chunk-ryce2n62.js → chunk-rs8v7c67.js} +3 -3
- package/dist/{chunk-cwqqv7dx.js → chunk-sqtzajrx.js} +4 -4
- package/dist/{chunk-7md90ny0.js → chunk-t3ssg8p0.js} +2 -2
- package/dist/{chunk-3h5vgz4z.js → chunk-tt3pn05f.js} +1 -1
- package/dist/chunk-v34tdcwv.js +1 -0
- package/dist/{chunk-x6a2e5sx.js → chunk-v90w8kbz.js} +3 -3
- package/dist/chunk-xq7xs8bh.js +1 -0
- package/dist/deploy/index.js +1 -1
- package/dist/dns/index.js +1 -1
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/shared/box-converge.d.ts +46 -1
- package/dist/index.js +45 -45
- package/dist/mail/index.js +2 -2
- package/dist/operations/index.js +1 -1
- package/dist/protection/index.js +1 -1
- package/dist/spend/index.js +1 -1
- package/dist/ui/404.html +1 -1
- package/dist/ui/accept-invitation.html +1 -1
- package/dist/ui/access-denied.html +1 -1
- package/dist/ui/account/automation.html +6 -6
- package/dist/ui/account/security.html +2 -2
- package/dist/ui/applications/compose.html +6 -6
- package/dist/ui/applications/new.html +2 -2
- package/dist/ui/data/backups.html +5 -5
- package/dist/ui/data/services.html +6 -6
- package/dist/ui/data/volumes.html +6 -6
- package/dist/ui/index.html +6 -6
- package/dist/ui/infrastructure/topology.html +5 -5
- package/dist/ui/integrations.html +1 -1
- package/dist/ui/operations/alerts.html +6 -6
- package/dist/ui/operations/configuration.html +6 -6
- package/dist/ui/operations/jobs.html +5 -5
- package/dist/ui/operations/maintenance.html +6 -6
- package/dist/ui/operations/observability.html +5 -5
- package/dist/ui/operations/previews.html +5 -5
- package/dist/ui/operations/queue.html +5 -5
- package/dist/ui/operations/regions.html +6 -6
- package/dist/ui/operations/releases.html +5 -5
- package/dist/ui/operations/spend.html +5 -5
- package/dist/ui/operations/workloads.html +5 -5
- package/dist/ui/security.html +1 -1
- package/dist/ui/server/actions.html +5 -5
- package/dist/ui/server/activity.html +1 -1
- package/dist/ui/server/capacity.html +5 -5
- package/dist/ui/server/database.html +5 -5
- package/dist/ui/server/deployments.html +5 -5
- package/dist/ui/server/diagnostics.html +1 -1
- package/dist/ui/server/firewall.html +5 -5
- package/dist/ui/server/fleet.html +5 -5
- package/dist/ui/server/logs.html +5 -5
- package/dist/ui/server/metrics.html +5 -5
- package/dist/ui/server/security.html +1 -1
- package/dist/ui/server/services.html +2 -2
- package/dist/ui/server/sites.html +6 -6
- package/dist/ui/server/ssh-keys.html +6 -6
- package/dist/ui/server/team.html +6 -6
- package/dist/ui/server/terminal.html +2 -2
- package/dist/ui/serverless/alarms.html +6 -6
- package/dist/ui/serverless/assets.html +1 -1
- package/dist/ui/serverless/cost.html +2 -2
- package/dist/ui/serverless/data.html +6 -6
- package/dist/ui/serverless/deployments.html +2 -2
- package/dist/ui/serverless/firewall.html +1 -1
- package/dist/ui/serverless/functions.html +6 -6
- package/dist/ui/serverless/logs.html +6 -6
- package/dist/ui/serverless/metrics.html +2 -2
- package/dist/ui/serverless/queues.html +6 -6
- package/dist/ui/serverless/secrets.html +6 -6
- package/dist/ui/serverless/traces.html +6 -6
- package/dist/ui/serverless.html +5 -5
- package/package.json +3 -3
- package/dist/bin/chunk-1z4hxpwe.js +0 -2
- package/dist/bin/chunk-37gemrn2.js +0 -1
- package/dist/bin/chunk-40963a0r.js +0 -1
- package/dist/bin/chunk-4zsp269q.js +0 -1
- package/dist/bin/chunk-57sers7y.js +0 -1
- package/dist/bin/chunk-5cmj2m13.js +0 -1
- package/dist/bin/chunk-8vmy8yhf.js +0 -1
- package/dist/bin/chunk-apqyj6gr.js +0 -1
- package/dist/bin/chunk-at4x6wf2.js +0 -1
- package/dist/bin/chunk-bd4ppf6w.js +0 -1
- package/dist/bin/chunk-bzbah8jm.js +0 -1
- package/dist/bin/chunk-bzpeqh5z.js +0 -1
- package/dist/bin/chunk-cmkvxf6c.js +0 -1
- package/dist/bin/chunk-d2fq60kd.js +0 -1
- package/dist/bin/chunk-e0d34gcp.js +0 -1
- package/dist/bin/chunk-ed4vh6b4.js +0 -1
- package/dist/bin/chunk-fqvqqtg6.js +0 -1
- package/dist/bin/chunk-hrg9ygbz.js +0 -1
- package/dist/bin/chunk-hzc049ns.js +0 -1
- package/dist/bin/chunk-kj0eewaq.js +0 -1
- package/dist/bin/chunk-kqd186ky.js +0 -2
- package/dist/bin/chunk-mt70pxs8.js +0 -1
- package/dist/bin/chunk-n6hngvvb.js +0 -1
- package/dist/bin/chunk-n9aeark7.js +0 -1
- package/dist/bin/chunk-pntcdh4x.js +0 -1
- package/dist/bin/chunk-sfwm3wzx.js +0 -1
- package/dist/bin/chunk-zgasmfgt.js +0 -1
- package/dist/chunk-3855mx54.js +0 -1
- package/dist/chunk-92yhw6da.js +0 -1
- package/dist/chunk-9tbx7g94.js +0 -1
- package/dist/chunk-qkycmppw.js +0 -1
- package/dist/chunk-wtp36fj6.js +0 -1
- package/dist/chunk-zwckda2e.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{_I,LI,tl,Am,rl,nl,an,Q,l,il,ym,K,sl,g,ey,C,Xe,Ki,cn,w,be,ol,ty,r,t,$I,MI,p,FI,UI,QI,HI,GI,cr,al,Wi,ry,VI,qI,xe,Ye,cl,Sm,Im,jI,bm,Cm,Em,Uo,dl,ce,dn,Rt,Qo,Dt,Ce,ny,ll,Ho,vm,Tm,wm,Rm,ul,zI,W,E,iy,sy,Dm,a,S,Ze,m,Pm,et,J,Pt,KI,km,X,gl,Oe,dr,Go,de,pl,le,oy,Vo,Y,Z,_,Ji,D,lr,kt,ee,e,ln,WI,Nm,ml,JI,XI,YI,ZI,fl,eb,tb,rb,nb,ib,sb,ob,ab,cb,db,lb,ub,ay,cy,dy,ly,uy,gy,py,ur,Bm,xm,gr,Xi,gb,Om,pb,mb,un,fb,hb,Ab,yb,Sb,Ib,my,fy,hy,Ay,yy,Yi,bb,qo,Sy,_m,V,Iy,tt,jo,Nt,by,Lm,Cy,Ey,vy,$m,q,Cb,Eb,vb,Tb,Ty,wb,te,Rb,Db,Pb,hl,Al,wy,Mm,Fm,kb,Nb,Bb,xb,Ob,Ry,yl,_b,Lb,$b,Mb,Fb,Dy,Py,Ub,Qb,Hb,Gb,Vb,qb,jb,ky,zb,Um,Sl,Kb,Wb,Jb,Xb,Qm,Hm,Gm,Yb,Il,Ny,By,xy,Oy,bl,_y,Zb,eC,tC,rC,nC,iC,sC,Ly,$y,My,Fy,Vm,oC,aC,cC,dC,lC,uC,gC,pC,mC,Uy,Qy,Hy,Gy,fC,hC,qm,AC,jm,zm,Km,Wm,yC,SC,IC,bC,_e,Zi,CC,EC,vC,TC,wC,RC,DC,PC,Vy,kC,NC,Jm,Xm,BC,xC,qy,OC,_C,LC,$C,MC,FC,UC,QC,HC,GC,VC,qC,jC,zC,KC,WC,JC,XC,YC,ZC,eE,Cl,jy,El,zy,vl,Ky,Tl,Wy,wl,Jy,pr,Xy,Rl,Yy,es,Zy,Dl,eS,Pl,tS,Ym,tE,Zm,rE,kl,rS,mr,nS,ef,nE,Nl,iS,tf,iE,rf,sE,nf,oE,Bl,sS,sf,aE,of,cE,af,dE,cf,lE,xl,oS,Ol,aS,df,uE,lf,gE,uf,pE,gf,mE,pf,fE,mf,hE,_l,cS,ff,AE,hf,yE,Af,SE,yf,IE,Sf,bE,If,CE,bf,Cf,Ef,vf,Tf,EE,wf,vE,Rf,TE,Df,wE,rt,Pf,dS,zo,Ll,gn,lS,ts,fr,$l,Ml,uS,gS,Fl,kf,Ul,Nf,RE,DE,Ko,Wo,Jo,Ql,pn,Hl,Gl,rs,Xo,Yo,Bf,pS,mS,fS,PE,xf,Of,kE,hS,_f,AS,yS,SS,NE,Lf,mn,Vl,$f,BE,IS,Zo,ea,ql,Mf,xE,jl,bS,Ff,OE,Uf,_E,Qf,LE}from"./chunk-z5as1fa7.js";import{zl,k,Kl,ta,CS,Hf,ES,vS,TS,wS,RS,DS,PS,kS}from"./chunk-j2bpd2v9.js";import{aa,Gf,tu,OS,os,ru,ca,Vf,qf,hn,da,nu,it,iu,su,ou,as,An,jf,st,au,la,ua,ga,cu,du,lu,cs,pa,uu,yn,ds,ma,Bt,zf,gu,pu,Kf,mu,fa,hr,fu,hu,Au,yu,ot,Wf,Su,Ar,ha,Aa,ya,ls,us,Sn,Iu,gs,Sa,Ia,In,bu,bn,Jf,Xf,xt,Cn,ba,Yf,Cu,Eu,Ca,vu,Tu,wu,_S,ue,Ru,LS,$S,ps,ms,MS,Ee,Zf,Ot,Le,$e,_t,Du,Pu,ku,Nu,eh,th,Ea,rh,nh,va,Bu,xu,ih,ge,sh,Ou,ve,Ta,at,Lt,$t,En,fs,_u,FS,oh,ah,ch,dh,wa,Ra,Lu,Da,vn,Pa,$u,hs,Mu,ka,Na,Ba,xa,Oa,_a,La,$a,Fu,yr,Ma,Uu,Tn,Qu,Fa,Ua,Hu,Sr,Qa,Ha,lh,US,As,QS,HS,GS,Ga,Va,Gu,uh,qa,wn,Vu,ys,qu,ju,zu,ja,gh,za,Ku,ph,Ka,mh,Rn,Dn,Wu,Ss,tg,sg,og,ag,cg,dg,bs,Ir,Ja,Pn,kn,br,ct,Ch,Ya,Eh,vh,gg,Za,Es,pg,ec,Ft,Fe,mg,tc,rc,fg,nc,ic,sc,oc,hg,Ag,Bn,ac,cc,dc,lc,yg,vs,xn,Ts,uc}from"./chunk-za23j2mq.js";import{U,jr,hd,fo,d,qp,jp}from"./chunk-c87bg8wk.js";import{Ct,fd,Ni,Bi,xi,Vp}from"./chunk-x6a2e5sx.js";import{eA,tA,rA,Tp,wp,Rp,nA,Dp,Pp,iA,sA,kp,oA,aA,pd,Np,cA,dA,Bp,lA,uA,gA,pA,mA,fA,hA,ki,md,xp,Op,_p,Lp,$p,Mp,Fp,Up,Qp,Hp,Gp,AA,yA,SA,IA,bA,CA,EA}from"./chunk-95qrgpjk.js";import{Ke,Ad,Ie,tr,yd,x,rr,Et,Sd,ho,wA,zp,Id,s,Oi,Ao,zr,bd,Cd,Kr,RA,Ed,NI,BI,yo,xI,OI,vd,Td,_i,So,ae,c,Io,We,Wr,DA,PA,wd,kA,bo,NA,BA,Co,Rd,Jr,Eo,xA,nr,Dd,Kp,ir,Xr,OA,vo,_A,O,LA,Pd,Wp,To,$A,MA,FA,kd,Li,wo,Nd,sr,vt,UA,Yr,QA,Bd,Jp,Xp,Ro,xd,Od,Tt,Yp,$i,_d,Do,Zr,Zp,Mi,Ld,$d,Fi,em,Md,Fd,Ud,Qd,Po,tm,rm,HA,nm,Hd,Ui,im,sm,ko,en,No,Bo,xo,Gd,om,Vd,Oo,GA,or,VA,qd,tn,jd,qA,zd,am,Qi,rn,_o,Hi,Je,jA,cm,dm,ar,Kd,Wd,Jd,Gi,Vi,qi,zA,KA,wt,Lo,WA,nn,lm,$o,JA,um,gm,pm,XA,mm,fm,YA,i,ZA,ji,Mo,Fo}from"./chunk-b1v1301e.js";import{n}from"./chunk-1a7ms51t.js";import{Re,gt,qn}from"./chunk-ryce2n62.js";import{o}from"./chunk-tj3egckk.js";import{Te,Bs,xs,bg,hc,Ac,Os,yc,dt,re,lt,pe,T,we,$n,Sc,Ue,Ic,Mn,Un,Qn,Ut,Qt,Ht,Hn,Er,bc,vr,Tr,ut,Gn,Ec,Gt,wr,Vn,Tc,wg,Rg,wc,Rr}from"./chunk-yece1kc4.js";import{pt,he,Ge,Dg,Vt,Dc,Pc,qt,H,jn,jt,zt,zn,Ms,Fs,Dr,Pr,Kn,kr,Us,Qs,Hs,Gs,ie,Vs,qs,js,zs,Ae,Ks,Ws,Js,N,kc,Wn,Nc,ye,Nr}from"./chunk-qb8cf1ss.js";import{ne}from"./chunk-pqyv47m4.js";import{Pg,Bc,kg,De,xc,Jn,Ng,Oc,Bg,xg,$h,Yn,Ys,M,Or,Zn,ei,_r,$r,ti,Zs,ri,ni,ii,si,ai,Mr,Se,$c,Yt,Mc,Fr,Qc,Ve,se,qe,je,ht,di,li,Pe,yt,ke,gi,pi,mi,fi,hi,Ai,yi,Ur,F,no,sp,Yc,Ii,bi,Ci,Ei,nd,so,id,Zt,Ti,oo,ao,sd,wi,od}from"./chunk-7bzyjfb1.js";import{lo,go,po,B,Ne}from"./chunk-y9q6sv2q.js";import{Wl,ra,ns,is,na,Jl,Xl,ss,ia,sa,Zl,eu,oa}from"./chunk-nq6cqjfv.js";import{gc,On,_n,ws,Rs,Ds,Ps,pc,mc}from"./chunk-qdaj5yyh.js";import{fc}from"./chunk-cwqqv7dx.js";import{Rc,Qe,I}from"./chunk-jg2m713e.js";import{He}from"./chunk-dp0hvmd0.js";import{b}from"./chunk-w174jbbm.js";import{oe,Ri,co,ad,Di,Sp}from"./chunk-rxh9dkpd.js";import{Hr,Be}from"./chunk-mkvqcd3x.js";import{A}from"./chunk-3h5vgz4z.js";import{Xd,sn,Yd,Zd,el,zi,hm,on}from"./chunk-2pqjw8pq.js";import{NS,nt}from"./chunk-7md90ny0.js";var Gh="https://api.machines.dev/v1";class Is extends Error{status;path;constructor(u,f,h){super(u);this.status=f;this.path=h;this.name="FlyApiError"}}function Xc(u){let f=u.ip.includes(":");if(f&&u.ip.startsWith("fdaa:"))return"private_v6";if(u.shared)return"shared_v4";return f?"v6":"v4"}class 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,f,h={}){let y=new URL(`https://api.machines.dev/v1${f}`);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 Is(`Fly.io ${u} ${f} failed (${R.status}): ${L}`,R.status,f)}return P}getApp(u){return this.rest("GET",`/apps/${encodeURIComponent(u)}`,{notFound:"null"})}createApp(u,f){return this.rest("POST","/apps",{body:{app_name:u,org_slug:f}})}async listMachines(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines`)??[]}createMachine(u,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines`,{body:f})}updateMachine(u,f,h,y){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}`,{body:h,headers:{"fly-machine-lease-nonce":y}})}async acquireLease(u,f,h=120){let R=(await this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/lease`,{body:{ttl:h}})).data?.nonce;if(!R)throw new Is(`Fly.io gave no lease nonce for Machine ${f}`,200,`/machines/${f}/lease`);return R}async releaseLease(u,f,h){await this.rest("DELETE",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/lease`,{headers:{"fly-machine-lease-nonce":h}})}async waitForState(u,f,h,y={}){await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(f)}/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,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/volumes`,{body:{...f,encrypted:!0}})}async setSecrets(u,f){return(await this.rest("POST",`/apps/${encodeURIComponent(u)}/secrets`,{body:{values:f}})).version}async listIpAssignments(u){return(await this.rest("GET",`/apps/${encodeURIComponent(u)}/ip_assignments`)).ips??[]}async assignIp(u,f){let h=await this.rest("POST",`/apps/${encodeURIComponent(u)}/ip_assignments`,{body:{type:f}});if(!h.ip)throw new Is(`Fly.io assigned no ${f} address to ${u}`,200,`/apps/${u}/ip_assignments`);return{ip:h.ip,shared:h.shared??f==="shared_v4",region:h.region}}async requestCertificate(u,f){return this.rest("POST",`/apps/${encodeURIComponent(u)}/certificates/acme`,{body:{hostname:f}})}}function hp(u){try{return JSON.parse(u)}catch{return}}var _c="ts-cloud-role";function qh(u,f){let h=u.fly??{},y=h.app??`${u.project.slug}-${f.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:f.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:{...f.env,PORT:String(R)},secrets:f.secrets??{},hostnames:h.hostnames??[],release:f.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:{[_c]:"app","ts-cloud-release":u.release}}}async function Zh(u,f,h=()=>{}){let y=!1;if(!await u.getApp(f.app))h(`Creating Fly app ${f.app} in ${f.org}`),await u.createApp(f.app,f.org),y=!0;let R;if(Object.keys(f.secrets).length>0)R=await u.setSecrets(f.app,f.secrets),h(`Set ${Object.keys(f.secrets).length} secret(s) (version ${R})`);let v=await u.listIpAssignments(f.app),P=new Set(v.map(Xc));if(!P.has("v6"))v.push(await u.assignIp(f.app,"v6")),h("Assigned a dedicated IPv6");if(!P.has("v4")&&!P.has("shared_v4"))v.push(await u.assignIp(f.app,"shared_v4")),h("Assigned a shared IPv4");let L=yp(f),z=(await u.listMachines(f.app)).filter((Me)=>{let ze=Me.config?.metadata??{};if(ze[_c])return ze[_c]==="app";return!ze.fly_process_group||ze.fly_process_group==="app"}),fe=f.volume?await u.listVolumes(f.app):[],me=[],At=[],It=new Set;for(let Me of f.regions){let ze=z.filter((j)=>j.region===Me).sort((j,St)=>j.id.localeCompare(St.id));for(let j=0;j<f.count;j++){let St=ze[j];if(St){It.add(St.id),await Cp(u,f.app,St,L,R),At.push(St.id),h(`Updated ${St.id} (${Me}) to ${f.image}`);continue}let G=f.volume?[{volume:(await bp(u,f,Me,fe)).id,path:f.volume.path}]:void 0,ft=await u.createMachine(f.app,{region:Me,name:`${f.app}-${Me}-${j+1}`,config:{...L,...G?{mounts:G}:{}},...R!==void 0?{min_secrets_version:R}:{}});await u.waitForState(f.app,ft.id,"started",{instanceId:ft.instance_id}),me.push(ft.id),h(`Created ${ft.id} in ${Me}`)}}let mt=[];for(let Me of f.hostnames)mt.push(await u.requestCertificate(f.app,Me));return{app:f.app,url:`https://${f.app}.fly.dev`,createdApp:y,created:me,updated:At,untouched:z.filter((Me)=>!It.has(Me.id)).map((Me)=>Me.id),ips:v,certificates:mt}}async function Cp(u,f,h,y,R){let v=await u.acquireLease(f,h.id);try{let P=await u.updateMachine(f,h.id,{config:{...y,...h.config?.mounts?.length?{mounts:h.config.mounts}:{}},...R!==void 0?{min_secrets_version:R}:{}},v);await u.waitForState(f,h.id,"started",{instanceId:P.instance_id})}finally{await u.releaseLease(f,h.id,v)}}async function bp(u,f,h,y){let R=y.find((P)=>P.region===h&&P.name===f.volume.name&&!P.attached_machine_id);if(R)return R.attached_machine_id="pending",R;let v=await u.createVolume(f.app,{name:f.volume.name,region:h,size_gb:f.volume.sizeGb});return y.push({...v,attached_machine_id:"pending"}),v}import{createHmac as Yl,createSign as Ap,timingSafeEqual as Ip}from"node:crypto";function vi(u){let f=u instanceof Date?u.getTime():u;if(!Number.isFinite(f))throw TypeError("Media access timestamp must be finite");return Math.floor(f/1000)}function Zu(u){return Buffer.from(u).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function vp(u){return Buffer.from(u).toString("base64url")}function Ju(u,f=!1){if(!u||/[\r\n]/.test(u))throw TypeError("Media resource is invalid");let h=f?u.replaceAll("*","wildcard"):u,y=new URL(h);if(!["http:","https:"].includes(y.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!f&&u.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function Yu(u,f){let h=Ap("RSA-SHA1");return h.update(u),h.end(),Zu(h.sign(f))}function Xu(u){Ju(u.resource,!0);let h={DateLessThan:{"AWS:EpochTime":vi(u.expiresAt)}};if(u.activeAt!==void 0)h.DateGreaterThan={"AWS:EpochTime":vi(u.activeAt)};if(u.ipAddress)h.IpAddress={"AWS:SourceIp":u.ipAddress};return JSON.stringify({Statement:[{Resource:u.resource,Condition:h}]})}function BS(u,f,h){Ju(u);let y=vi(f),R=u.includes("?")?"&":"?",v=Xu({resource:u,expiresAt:f}),P=Yu(v,h.privateKey);return`${u}${R}Expires=${y}&Signature=${encodeURIComponent(P)}&Key-Pair-Id=${encodeURIComponent(h.keyPairId)}`}function WS(u,f){let h=Xu(u);return{"CloudFront-Key-Pair-Id":f.keyPairId,"CloudFront-Policy":Zu(Buffer.from(h)),"CloudFront-Signature":Yu(h,f.privateKey)}}function VS(u){if(!u.resource||/[\r\n]/.test(u.resource))throw TypeError("Media resource is invalid");let f=vp(Buffer.from(JSON.stringify({resource:u.resource,expiresAt:vi(u.expiresAt),...u.keyId?{keyId:u.keyId}:{},...u.audience?{audience:u.audience}:{}}))),h=Yl("sha256",u.secret).update(f).digest("base64url");return`${f}.${h}`}function zS(u,f){let[h,y,R]=u.split(".");if(!h||!y||R)return null;let v=Yl("sha256",f.secret).update(h).digest(),P;try{P=Buffer.from(y,"base64url")}catch{return null}if(v.length!==P.length||!Ip(v,P))return null;try{let L=JSON.parse(Buffer.from(h,"base64url").toString("utf8")),z=vi(f.now??Date.now());if(!L.resource||!Number.isSafeInteger(L.expiresAt)||L.expiresAt<=z)return null;if(f.resource&&L.resource!==f.resource)return null;if(f.audience&&L.audience!==f.audience)return null;return L}catch{return null}}function jS(u,f=!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":f&&(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 KS(u){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(u.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(u.region))throw TypeError("Media bucket region is invalid");let f=u.prefix?`/${u.prefix.replace(/^\/+|\/+$/g,"")}`:"",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:f,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 Ep{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(u){this.config=u.config,this.environment=u.environment,this.builder=new ol(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let f=this.config.environments[this.environment]?.infrastructure;if(!f)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...f,compute:{...this.config.infrastructure?.compute,...f.compute},storage:{...this.config.infrastructure?.storage,...f.storage},functions:{...this.config.infrastructure?.functions,...f.functions},servers:{...this.config.infrastructure?.servers,...f.servers},databases:{...this.config.infrastructure?.databases,...f.databases},cdn:{...this.config.infrastructure?.cdn,...f.cdn},sftp:f.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...f.queues},redirects:{...this.config.infrastructure?.redirects,...f.redirects},realtime:{...this.config.infrastructure?.realtime,...f.realtime},cache:{...this.config.infrastructure?.cache,...f.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...f.fileSystem},email:{...this.config.infrastructure?.email,...f.email},search:{...this.config.infrastructure?.search,...f.search},ai:{...this.config.infrastructure?.ai,...f.ai}}}}shouldDeploy(u){if(u.environments&&!u.environments.includes(this.environment))return!1;if(u.requiresFeatures){let f=this.config.features||{};if(!u.requiresFeatures.every((y)=>f[y]===!0))return!1}if(u.regions){let f=this.config.environments[this.environment]?.region||this.config.project.region;if(!u.regions.includes(f))return!1}if(u.condition&&typeof u.condition==="function")return u.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let u=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,f=Number(u||3008);return Number.isFinite(f)&&f>0?f:3008}defaultComputeCachePathPatterns(){return["/api/*","/auth/*","/publisher/api/*","/publisher/*","/publish","/publish/*","/analytics/*","/packages/*","/npm/*","/zig/*","/php/*","/commits/*","/health","/dashboard/*","/search","/login","/logout","/signup","/account","/account/*"]}shouldRouteStorageBucketToCompute(u,f){return u==="public"||f.routeCompute===!0}storageBucketName(u,f,h){return this.mergedConfig.infrastructure?.storage?.[h]?.bucket??`${u}-${f}-${h}`}fileSystemLogicalId(u,f,h){return t(r({slug:`${u}-${h}`,environment:f,resourceType:"efs"}))}resolveSftpStorage(u,f,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(f,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(f,h,y.storageBucket)}}return}resolveComputeCachePathPatterns(u){if(u&&u.length>0)return u;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(u,f){return{PathPattern:u,TargetOriginId:f,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",OriginRequestPolicyId:"b689b0a8-53d0-40ab-baf2-68738e2966ac"}}appendComputeAppOrigin(u,f,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`,At={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:P}]}]},me]]},It=this.resolveApiOriginPort();if(u.push({Id:z,DomainName:At,CustomOriginConfig:{HTTPPort:It,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),h.push(P),L)h.push(L);for(let mt of v)f.push(this.createComputeCacheBehavior(mt,z))}buildCaddyfile(u){let f=u.filter(([,R])=>typeof R.domain==="string"&&R.domain&&typeof R.port==="number");if(f.length===0)return;let h=new Map;for(let[,R]of f){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==="/",At=!fe.path||fe.path==="/";if(me&&!At)return 1;if(!me&&At)return-1;return(fe.path?.length??0)-(z.path?.length??0)}).map((z)=>{let fe=!z.path||z.path==="/",me=`reverse_proxy localhost:${z.port}`;return fe?` handle {
|
|
1
|
+
import{_I,LI,rl,Am,nl,il,cn,Q,l,sl,ym,K,ol,g,ey,C,Xe,Ji,dn,w,be,al,ty,r,t,$I,MI,m,FI,UI,QI,HI,GI,dr,cl,Xi,ry,VI,qI,xe,Ye,dl,Sm,Im,jI,bm,Cm,Em,Qo,ll,ce,ln,Dt,Ho,Pt,Ce,ny,ul,Go,vm,Tm,wm,Rm,gl,zI,W,E,iy,sy,Dm,a,S,Ze,f,Pm,et,J,kt,KI,km,X,pl,Oe,lr,Vo,de,ml,le,oy,qo,Y,Z,_,Yi,D,ur,Nt,ee,e,un,WI,Nm,fl,JI,XI,YI,ZI,hl,eb,tb,rb,nb,ib,sb,ob,ab,cb,db,lb,ub,ay,cy,dy,ly,uy,gy,py,gr,Bm,xm,pr,Zi,gb,Om,pb,mb,gn,fb,hb,Ab,yb,Sb,Ib,my,fy,hy,Ay,yy,es,bb,jo,Sy,_m,V,Iy,tt,zo,Bt,by,Lm,Cy,Ey,vy,$m,q,Cb,Eb,vb,Tb,Ty,wb,te,Rb,Db,Pb,Al,yl,wy,Mm,Fm,kb,Nb,Bb,xb,Ob,Ry,Sl,_b,Lb,$b,Mb,Fb,Dy,Py,Ub,Qb,Hb,Gb,Vb,qb,jb,ky,zb,Um,Il,Kb,Wb,Jb,Xb,Qm,Hm,Gm,Yb,bl,Ny,By,xy,Oy,Cl,_y,Zb,eC,tC,rC,nC,iC,sC,Ly,$y,My,Fy,Vm,oC,aC,cC,dC,lC,uC,gC,pC,mC,Uy,Qy,Hy,Gy,fC,hC,qm,AC,jm,zm,Km,Wm,yC,SC,IC,bC,_e,ts,CC,EC,vC,TC,wC,RC,DC,PC,Vy,kC,NC,Jm,Xm,BC,xC,qy,OC,_C,LC,$C,MC,FC,UC,QC,HC,GC,VC,qC,jC,zC,KC,WC,JC,XC,YC,ZC,eE,El,jy,vl,zy,Tl,Ky,wl,Wy,Rl,Jy,mr,Xy,Dl,Yy,rs,Zy,Pl,eS,kl,tS,Ym,tE,Zm,rE,Nl,rS,fr,nS,ef,nE,Bl,iS,tf,iE,rf,sE,nf,oE,xl,sS,sf,aE,of,cE,af,dE,cf,lE,Ol,oS,_l,aS,df,uE,lf,gE,uf,pE,gf,mE,pf,fE,mf,hE,Ll,cS,ff,AE,hf,yE,Af,SE,yf,IE,Sf,bE,If,CE,bf,Cf,Ef,vf,Tf,EE,wf,vE,Rf,TE,Df,wE,rt,Pf,dS,Ko,$l,pn,lS,ns,hr,Ml,Fl,uS,gS,Ul,kf,Ql,Nf,RE,DE,Wo,Jo,Xo,Hl,mn,Gl,Vl,is,Yo,Zo,Bf,pS,mS,fS,PE,xf,Of,kE,hS,_f,AS,yS,SS,NE,Lf,fn,ql,$f,BE,IS,ea,ta,jl,Mf,xE,zl,bS,Ff,OE,Uf,_E,Qf,LE}from"./chunk-r9ydamw0.js";import{Kl,k,Wl,ra,CS,Hf,ES,vS,TS,wS,RS,DS,PS,kS}from"./chunk-7s7w8kzc.js";import{ca,Gf,ru,OS,cs,nu,da,Vf,qf,An,la,iu,it,su,ou,au,ds,yn,jf,st,cu,ua,ga,pa,du,lu,uu,ls,ma,gu,Sn,us,fa,xt,zf,pu,mu,Kf,fu,ha,Ar,hu,Au,yu,Su,ot,Wf,Iu,yr,Aa,ya,Sa,gs,ps,In,bu,ms,Ia,ba,bn,Cu,Cn,Jf,Xf,Ot,En,Ca,Yf,Eu,vu,Ea,Tu,wu,Ru,_S,ue,Du,LS,$S,fs,hs,MS,Ee,Zf,_t,Le,$e,Lt,Pu,ku,Nu,Bu,eh,th,va,rh,nh,Ta,xu,Ou,ih,ge,sh,_u,ve,wa,at,$t,Mt,vn,As,Lu,FS,oh,ah,ch,dh,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,lh,US,Ss,QS,HS,GS,Va,qa,Vu,uh,ja,Rn,qu,Is,ju,zu,Ku,za,gh,Ka,Wu,ph,Wa,mh,Dn,Pn,Ju,bs,rg,og,ag,cg,dg,lg,Es,br,Xa,kn,Nn,Cr,ct,Ch,Za,Eh,vh,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-p921pam0.js";import{U,zr,Ad,ho,d,qp,jp}from"./chunk-8jqv6wh7.js";import{Et,hd,xi,Oi,_i,Vp}from"./chunk-v90w8kbz.js";import{eA,tA,rA,Tp,wp,Rp,nA,Dp,Pp,iA,sA,kp,oA,aA,md,Np,cA,dA,Bp,lA,uA,gA,pA,mA,fA,hA,Bi,fd,xp,Op,_p,Lp,$p,Mp,Fp,Up,Qp,Hp,Gp,AA,yA,SA,IA,bA,CA,EA}from"./chunk-e97qhzfe.js";import{Ke,yd,Ie,rr,Sd,x,nr,vt,Id,Ao,wA,zp,bd,s,Li,yo,Kr,Cd,Ed,Wr,RA,vd,NI,BI,So,xI,OI,Td,wd,$i,Io,ae,c,bo,We,Jr,DA,PA,Rd,kA,Co,NA,BA,Eo,Dd,Xr,vo,xA,ir,Pd,Kp,sr,Yr,OA,To,_A,O,LA,kd,Wp,wo,$A,MA,FA,Nd,Mi,Ro,Bd,or,Tt,UA,Zr,QA,xd,Jp,Xp,Do,Od,_d,wt,Yp,Fi,Ld,Po,en,Zp,Ui,$d,Md,Qi,em,Fd,Ud,Qd,Hd,ko,tm,rm,HA,nm,Gd,Hi,im,sm,No,tn,Bo,xo,Oo,Vd,om,qd,_o,GA,ar,VA,jd,rn,zd,qA,Kd,am,Gi,nn,Lo,Vi,Je,jA,cm,dm,cr,Wd,Jd,Xd,qi,ji,zi,zA,KA,Rt,$o,WA,sn,lm,Mo,JA,um,gm,pm,XA,mm,fm,YA,i,ZA,Ki,Fo,Uo}from"./chunk-2phe49y7.js";import{n}from"./chunk-et77ydjb.js";import{Re,gt,jn}from"./chunk-rs8v7c67.js";import{o}from"./chunk-betvtvy7.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-f512g4fq.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-bn3jfrg5.js";import{ne}from"./chunk-7mw4x3ay.js";import{kg,xc,Ng,De,Oc,Xn,Bg,_c,xg,Og,$h,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-h5j27a4h.js";import{uo,po,mo,B,Ne}from"./chunk-b0s2605f.js";import{Jl,na,ss,os,ia,Xl,Yl,as,sa,oa,eu,tu,aa}from"./chunk-mqbsnpsv.js";import{pc,_n,Ln,Ds,Ps,ks,Ns,mc,fc}from"./chunk-r41cawtf.js";import{hc}from"./chunk-sqtzajrx.js";import{Dc,Qe,I}from"./chunk-pjdp30dn.js";import{He}from"./chunk-n0xw26th.js";import{b}from"./chunk-n3sydv3m.js";import{oe,Pi,lo,cd,ki,Sp}from"./chunk-k2bb62em.js";import{Gr,Be}from"./chunk-bydj8p3h.js";import{A}from"./chunk-tt3pn05f.js";import{Yd,on,Zd,el,tl,Wi,hm,an}from"./chunk-8z3jfyk8.js";import{NS,nt}from"./chunk-t3ssg8p0.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 bp(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 bp(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 Ap,timingSafeEqual as Ip}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 vp(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=Ap("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 BS(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 VS(u){if(!u.resource||/[\r\n]/.test(u.resource))throw TypeError("Media resource is invalid");let p=vp(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 zS(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||!Ip(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 jS(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 KS(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 Ep{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 {
|
|
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 f=u?.mountPath||u?.path;if(!f||f==="/")return;let h=`/${f}`.replace(/\/+/g,"/").replace(/\/$/,"");return h==="/"?void 0:h}storageBucketLogicalId(u,f,h){return`${u}-${f}-s3-${h}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((y)=>y.charAt(0).toUpperCase()+y.slice(1)).join("")}pathMountRewriteFunctionCode(u,f="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(u)}; var rewriteStyle = ${JSON.stringify(f)}; var uri = request.uri; if (uri === prefix) { uri = '/'; } else if (uri.indexOf(prefix + '/') === 0) { uri = uri.substring(prefix.length); } if (uri === '' || uri === '/') { request.uri = '/index.html'; return request; } if (uri.endsWith('/')) { request.uri = uri + 'index.html'; return request; } var lastSegment = uri.substring(uri.lastIndexOf('/') + 1); if (lastSegment.indexOf('.') === -1) { request.uri = rewriteStyle === 'flat' ? uri + '.html' : uri + '/index.html'; return request; } request.uri = uri; return request; }`}generate(){let u=this.mergedConfig.project.slug,f=this.environment,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,f),this.generateContainerInfrastructure(u,f);if(h)this.generateServerless(u,f);if(y)this.generateServer(u,f);if(R)this.generateComputeApp(u,f);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(u,f);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(u,f),this.storageFailoverReplicas.length>0)this.builder.addMetadata(ll,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(u){}generateNetworkInfrastructure(u,f){if(this.builder.hasResource("VPC"))return;let y=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:R,logicalId:v}=S.createVpc({slug:u,environment:f,cidr:y,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",R);let P=`${u}${f}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${u}-${f}-igw`},{Key:"Environment",Value:f}]}});let L=`${u}${f}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(L,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:P}}});let z=`${u}${f}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${u}-${f}-public-rt`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${u}${f}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:z},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:P}},DependsOn:L});let fe=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",me=["a","b"];for(let At=0;At<2;At++){let It=`PublicSubnet${At+1}`;this.builder.addResource(It,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${At}.0/24`,AvailabilityZone:`${fe}${me[At]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${u}-${f}-public-${me[At]}`},{Key:"Environment",Value:f}]}}),this.builder.addResource(`${It}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:It},RouteTableId:{Ref:z}}})}}generateContainerInfrastructure(u,f){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],At=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:At,slug:u,environment:f,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}-${f}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${u}-${f}`},{Key:"Environment",Value:f}]}});let z=`${u}${f}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(z,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${u}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0",Description:"HTTP"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${f}-alb-sg`},{Key:"Environment",Value:f}]}});let fe=`${u}${f}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[me,At]of Object.entries(h)){let It=At.port||3000;this.builder.addResource(fe,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${u}-${f}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort: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}-${f}-ecs-sg`},{Key:"Environment",Value:f}]}});let mt=`${u}${f}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(mt,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-ecs-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"],Policies:[{PolicyName:"ECRPullPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"}]}}]}});let Me=`${u}${f}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-ecs-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"}]}}]}});let ze=`${u}${f}${me}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),j=`/ecs/${u}-${f}-${me}`;this.builder.addResource(ze,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:j,RetentionInDays:30}});let St=`${u}${f}${me}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),G=String(At.cpu||512),ft=String(At.memory||1024);this.builder.addResource(St,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${f}-${me}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:G,Memory:ft,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}${At.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[mt,Me,ze]});let bt=`${u}${f}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(y?.enabled!==!1){this.builder.addResource(bt,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${u}-${f}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:z}],Tags:[{Key:"Name",Value:`${u}-${f}-alb`},{Key:"Environment",Value:f}]}});let Mt=`${u}${f}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),Wt=y?.healthCheck?.path||At.healthCheck||"/health";this.builder.addResource(Mt,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${u}-${f}-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}-${f}-tg`},{Key:"Environment",Value:f}]}});let Kt=`${u}${f}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(R?.enabled&&R?.redirectHttp)this.builder.addResource(Kt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:bt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(Kt,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:bt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Mt}}]}});if(R?.enabled){let Xt=R.certificateArn||(P?{Ref:P}:void 0);if(Xt){let Cr=`${u}${f}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Cr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:bt},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Xt}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Mt}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Jt=`${u}${f}${me}Service`.replace(/[^a-zA-Z0-9]/g,""),er=At.desiredCount||1;this.builder.addResource(Jt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${f}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:St},DesiredCount:er,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:me,ContainerPort:It,TargetGroupArn:{Ref:Mt}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[St,Kt,Mt]});let Lr=At.autoScaling;if(Lr){let Xt=`${u}${f}${me}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Xt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:Lr.max||10,MinCapacity:Lr.min||1,ResourceId:{"Fn::Sub":`service/\${${L}}/${u}-${f}-${me}`},ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs",RoleARN:{"Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"}},DependsOn:Jt}),Lr.targetCpuUtilization)this.builder.addResource(`${u}${f}${me}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${f}-${me}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Xt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:Lr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(Lr.targetMemoryUtilization)this.builder.addResource(`${u}${f}${me}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${f}-${me}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Xt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:Lr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(v?.domain&&v?.hostedZoneId)this.builder.addResource(`${u}${f}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":[bt,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[bt,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[L,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${u}-${f}-${me}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[bt,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let Mt=`${u}${f}${me}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Mt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${f}-${me}`,Cluster:{Ref:L},TaskDefinition:{Ref:St},DesiredCount:At.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:fe}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${u}-${f}-${me}`},{Key:"Environment",Value:f}]},DependsOn:[St]})}break}}generateServerless(u,f){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:f,roleName:`${u}-${f}-${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:f,functionName:`${u}-${f}-${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}=pl.createRestApi({slug:u,environment:f,apiName:`${u}-${f}-api`});this.builder.addResource(y,h)}}generateServer(u,f){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,f);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",At=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:At==="cache",installDatabaseClients:!!L.database});let mt=L.privateNetwork&&L.privateNetwork!=="create"?L.privateNetwork:{Ref:"VPC"},Me=L.subnet||{Ref:"PublicSubnet1"},j=!!this.mergedConfig.infrastructure?.email?.server?.enabled,St=[22,80,443,this.resolveApiOriginPort()];if(j)St.push(25,465,587,143,993);let G=a.createServerModeStack({slug:`${u}-${P}`,environment:f,vpcId:mt,subnetId:Me,instanceType:me,keyName:L.keyName||`${u}-${f}`,domain:L.domain,userData:It,volumeSize:L.diskSize||20,imageId:L.image,allowedPorts:St});for(let[ft,bt]of Object.entries(G.resources))this.builder.addResource(ft,bt);this.serverEipLogicalIds.set(P,G.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${P}Instance`,G.outputs.instanceLogicalId),this.builder.addOutput(`${P}InstanceId`,{Value:{Ref:G.outputs.instanceLogicalId},Description:`Instance ID for ${P} server`}),this.builder.addOutput(`${P}PublicIp`,{Value:{Ref:G.outputs.eipLogicalId},Description:`Public IP for ${P} server`})}}generateComputeApp(u,f){let 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,f);let At=this.buildCaddyfile(R),It=a.UserData.generateBunAppScript({runtime:h.runtime||"bun",runtimeVersion:h.runtimeVersion||"latest",systemPackages:h.systemPackages,database:L,caddyfile:At}),mt=Ys(h.appUpdates),Me=mt.length>0?`${It}
|
|
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
11
|
${mt.join(`
|
|
12
12
|
`)}
|
|
13
|
-
`:It,ze=R.map(([,Wt])=>Wt.port).filter((Wt)=>typeof Wt==="number"&&![80,443].includes(Wt)),j=this.resolveApiOriginPort(),
|
|
14
|
-
else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`}});let Pi=[{Id:Xn,DomainName:{"Fn::Sub":`\${${Kt}}.s3.${Cc}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}],mo=[],vc=[];if(this.shouldRouteStorageBucketToCompute(G,ft)){this.appendComputeAppOrigin(Pi,mo,vc,u,f,this.resolveComputeCachePathPatterns(ft.computeRoutes));for(let xr of St){let $s=`S3-${u}-${f}-${xr.name}`,Fc=`${u}${f}${xr.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Fc,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${f}-${xr.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${u} ${f} ${xr.name} at ${xr.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(xr.mountPath,xr.rewriteStyle)}}),Pi.push({Id:$s,DomainName:{"Fn::Sub":`\${${xr.logicalId}}.s3.${Cc}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),vc.push(xr.logicalId,Fc);for(let gp of[xr.mountPath,`${xr.mountPath}/*`])mo.push({PathPattern:gp,TargetOriginId:$s,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":[Fc,"FunctionARN"]}}]})}}let Cs,Jc=Xn;if(er){let xr=`${Xn}-failover`;Object.assign(Pi[0],er.primaryConnection),Pi.push({Id:xr,DomainName:Tm(er.replicaBucket,er.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:j}}),Cs=dn({primaryOriginId:Xn,secondaryOriginId:xr,statusCodes:er.statusCodes}),Jc=Cs.Items[0].Id}let Lc={Type:"AWS::CloudFront::Distribution",DependsOn:[Kt,j,...oi?[oi]:[],...vc],Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${f} ${G} site`,DefaultRootObject:"index.html",Origins:Pi,...Cs?{OriginGroups:Cs}:{},DefaultCacheBehavior:{TargetOriginId:Jc,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...oi?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[oi,"FunctionARN"]}}]}:{}},...mo.length>0?{CacheBehaviors:mo}:{},...Cr.length>0?{Aliases:Cr}:{},ViewerCertificate:fn,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:Br}}};if(L)Lc.DependsOn.push(L);if(er)Dt(Lc.Properties.DistributionConfig,`infrastructure.storage.${G}`),this.storageFailoverReplicas.push({name:G,primaryBucket:Mt,primaryRegion:Cc,replicaBucket:er.replicaBucket,replicaRegion:er.replicaRegion,replicate:er.replicate,distributionArnOutput:`${G}CloudFrontDistributionArn`}),this.builder.addOutput(`${G}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`},Description:`CloudFront distribution ARN for ${G} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${G}FailoverBucketName`,{Value:er.replicaBucket,Description:`Failover replica bucket for ${G} (${er.replicaRegion}), outside this stack`});this.builder.addResource(Xt,Lc);let mp=`${Kt}CloudFrontPolicy`;if(this.builder.addResource(mp,{Type:"AWS::S3::BucketPolicy",DependsOn:[Kt,Xt],Properties:{Bucket:{Ref:Kt},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${Kt}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(G,ft))for(let xr of St){let $s=`${xr.logicalId}CloudFrontPolicy`;this.builder.addResource($s,{Type:"AWS::S3::BucketPolicy",DependsOn:[xr.logicalId,Xt],Properties:{Bucket:{Ref:xr.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:::\${${xr.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Xt}}`}}}}]}}})}if(Cr.length>0)P.push({name:G,bucketLogicalId:Kt,distLogicalId:Xt,oacLogicalId:j,aliases:Cr});this.builder.addOutput(`${G}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Xt,"DomainName"]},Description:`CloudFront domain for ${G}`}),this.builder.addOutput(`${G}CloudFrontDistributionId`,{Value:{Ref:Xt},Description:`CloudFront distribution ID for ${G}`})}if(this.builder.addOutput(`${G}BucketName`,{Value:{Ref:Kt},Description:`S3 bucket name for ${G}`}),G==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:Kt},Description:"Frontend S3 bucket name"});if(G==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:Kt},Description:"Documentation S3 bucket name"});if(G==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:Kt},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let ze=this.mergedConfig.infrastructure.sftp,j=gl.create({...ze,storage:this.resolveSftpStorage(ze,u,f)??ze.storage,slug:u,environment:f});for(let[St,G]of Object.entries(j.resources))this.builder.addResource(St,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:St}of P)for(let G of St){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:St,logicalId:G}=dr.createTable({slug:u,environment:f,tableName:`${u}-${f}-${ze}`,partitionKey:j.partitionKey||{name:"id",type:"S"},sortKey:j.sortKey});this.builder.addResource(G,St)}else if(j.engine==="postgres"){let{dbInstance:St,logicalId:G}=dr.createPostgres({slug:u,environment:f,dbInstanceIdentifier:`${u}-${f}-${ze}`,masterUsername:j.username||"admin",masterUserPassword:j.password||"changeme123",allocatedStorage:j.storage||20,dbInstanceClass:j.instanceClass||"db.t3.micro"});this.builder.addResource(G,St)}else if(j.engine==="mysql"){let{dbInstance:St,logicalId:G}=dr.createMysql({slug:u,environment:f,dbInstanceIdentifier:`${u}-${f}-${ze}`,masterUsername:j.username||"admin",masterUserPassword:j.password||"changeme123",allocatedStorage:j.storage||20,dbInstanceClass:j.instanceClass||"db.t3.micro"});this.builder.addResource(G,St)}}if(this.mergedConfig.infrastructure?.cdn)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!j.origin)continue;let St=typeof j.customDomain==="string"?j.customDomain:j.customDomain?.domain||j.domain,G=typeof j.customDomain==="object"?j.customDomain?.certificateArn:j.certificateArn,ft=G||z,bt=`${u}${f}${ze}CDN`.replace(/[^a-zA-Z0-9]/g,""),Mt=`S3-${u}-${f}-${ze}-cdn`,Wt=[{Id:Mt,DomainName:j.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:j.originShield?{Enabled:!0,OriginShieldRegion:j.originShieldRegion||this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...ce(j,`infrastructure.cdn.${ze}`)}],Kt=[],Jt=[],er=["GET","HEAD","OPTIONS"],Lr=Mt,Xt;if(j.failoverOrigin){Rt(er,`the default cache behavior of infrastructure.cdn.${ze}`);let Gr=`${Mt}-failover`,Br=typeof j.failoverOrigin==="string"?{domain:j.failoverOrigin}:j.failoverOrigin;if(!Br.domain)throw Error(`infrastructure.cdn.${ze}.failoverOrigin.domain is required`);if(Br.domain===j.origin)throw Error(`infrastructure.cdn.${ze}: failoverOrigin must differ from origin (both are ${j.origin})`);Wt.push({Id:Gr,DomainName:Br.domain,OriginPath:Br.originPath||"",...Qo(Br.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...ce(Br,`infrastructure.cdn.${ze}.failoverOrigin`)}),Xt=dn({primaryOriginId:Mt,secondaryOriginId:Gr,statusCodes:j.failoverStatusCodes}),Lr=Xt.Items[0].Id}else if(j.failoverStatusCodes)throw Error(`infrastructure.cdn.${ze}: failoverStatusCodes needs failoverOrigin to fail over to`);if(j.routeCompute)this.appendComputeAppOrigin(Wt,Kt,Jt,u,f,this.resolveComputeCachePathPatterns(j.computeRoutes));let Cr=ft&&St?{AcmCertificateArn:L&&!G?{Ref:L}:ft,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Vr=[...Jt];if(L&&!G&&St)Vr.push(L);let Qr={Type:"AWS::CloudFront::Distribution",...Vr.length>0?{DependsOn:Vr}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${f} ${ze} CDN`,DefaultRootObject:"index.html",Origins:Wt,...Xt?{OriginGroups:Xt}:{},DefaultCacheBehavior:{TargetOriginId:Lr,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:er,CachedMethods:["GET","HEAD","OPTIONS"],Compress:j.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...Kt.length>0?{CacheBehaviors:Kt}:{},...St&&ft?{Aliases:[St]}:{},ViewerCertificate:Cr,PriceClass:"PriceClass_100",HttpVersion:j.http3?"http2and3":"http2"}}};if(Dt(Qr.Properties.DistributionConfig,`infrastructure.cdn.${ze}`),this.builder.addResource(bt,Qr),v&&St&&ft){let Gr=St.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Gr}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[bt,...L&&!G?[L]:[]],Properties:{HostedZoneId:v,Name:St,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[bt,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[ze,j]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(j))continue;let{queue:St,logicalId:G}=J.createQueue({slug:u,environment:f,name:`${u}-${f}-${ze}`,fifo:j.fifo,visibilityTimeout:j.visibilityTimeout,messageRetentionPeriod:j.messageRetentionPeriod,delaySeconds:j.delaySeconds,maxMessageSize:j.maxMessageSize,receiveMessageWaitTime:j.receiveMessageWaitTime,contentBasedDeduplication:j.contentBasedDeduplication,encrypted:j.encrypted,kmsKeyId:j.kmsKeyId});this.builder.addResource(G,St);let ft;if(j.deadLetterQueue){let{deadLetterQueue:bt,updatedSourceQueue:Mt,deadLetterLogicalId:Wt}=J.createDeadLetterQueue(G,{slug:u,environment:f,maxReceiveCount:j.maxReceiveCount});ft=Wt,this.builder.addResource(Wt,bt);let Jt=this.builder.getResources()[G];if(Jt?.Properties)Jt.Properties.RedrivePolicy=Mt.Properties?.RedrivePolicy}if(j.trigger){let bt=j.trigger,Mt=`${u}${f}${bt.functionName}`.replace(/[^a-zA-Z0-9]/g,""),Wt={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[G,"Arn"]},FunctionName:{Ref:Mt},BatchSize:bt.batchSize||10,MaximumBatchingWindowInSeconds:bt.batchWindow||0,Enabled:!0,...bt.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...bt.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:bt.maxConcurrency}},...bt.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(bt.filterPattern)}]}}},DependsOn:[G,Mt]};this.builder.addResource(`${G}Trigger`,Wt)}if(j.alarms?.enabled){let bt=j.alarms,Mt=bt.notificationTopicArn;if(!Mt&&bt.notificationEmails?.length){let Jt=`${G}AlarmTopic`;this.builder.addResource(Jt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${f}-${ze}-alarms`,DisplayName:`${ze} Queue Alarms`}}),bt.notificationEmails.forEach((er,Lr)=>{this.builder.addResource(`${Jt}Sub${Lr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Jt},Protocol:"email",Endpoint:er}})}),Mt={Ref:Jt}}let Wt=bt.queueDepthThreshold||1000;this.builder.addResource(`${G}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${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"]}}],...Mt&&{AlarmActions:[Mt],OKActions:[Mt]}}});let Kt=bt.messageAgeThreshold||3600;if(this.builder.addResource(`${G}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${ze}-message-age`,AlarmDescription:`Queue ${ze} oldest message exceeds ${Kt} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:Kt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[G,"QueueName"]}}],...Mt&&{AlarmActions:[Mt],OKActions:[Mt]}}}),ft&&bt.dlqAlarm!==!1)this.builder.addResource(`${ft}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-${ze}-dlq-messages`,AlarmDescription:`Dead letter queue for ${ze} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[ft,"QueueName"]}}],...Mt&&{AlarmActions:[Mt]}}})}if(j.subscribe){let bt=j.subscribe,Mt=bt.topicArn;if(!Mt&&bt.topicName)Mt={Ref:bt.topicName};if(Mt){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":Mt}}}]}}});let Wt={TopicArn:Mt,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[G,"Arn"]},RawMessageDelivery:bt.rawMessageDelivery||!1};if(bt.filterPolicy)Wt.FilterPolicy=bt.filterPolicy,Wt.FilterPolicyScope=bt.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,f);else this.generateRealtimeResources(u,f);let fe=this.mergedConfig.infrastructure?.redirects;if(fe){let ze=fe.target||this.mergedConfig.infrastructure?.dns?.domain||"",j=fe.protocol||"https";if(fe.domains?.length&&ze)for(let St of fe.domains){let{bucket:G,bucketPolicy:ft,logicalId:bt,policyLogicalId:Mt}=kt.createDomainRedirectBucket({slug:u,environment:f,sourceDomain:St,targetDomain:ze,protocol:j});this.builder.addResource(bt,G),this.builder.addResource(Mt,ft)}if(fe.paths&&Object.keys(fe.paths).length>0){let St=kt.fromMapping(fe.paths,{statusCode:fe.statusCode||301}),{function:G,logicalId:ft}=kt.createPathRedirectFunction({slug:u,environment:f,rules:St});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:St,logicalId:G}=Vo.createAlarm({slug:u,environment:f,alarmName:`${u}-${f}-${ze}`,metricName:j.metricName||"Errors",namespace:j.namespace||"AWS/Lambda",threshold:j.threshold||1,comparisonOperator:j.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(G,St)}let me=this.mergedConfig.infrastructure?.cache;if(me){let ze=me.type||"redis";if(ze==="redis"){this.generateNetworkInfrastructure(u,f);let j=me.redis||{},{replicationGroup:St,subnetGroup:G,logicalId:ft,subnetGroupId:bt}=Go.createRedis({slug:u,environment:f,nodeType:j.nodeType||me.nodeType||"cache.t3.micro",engineVersion:j.engineVersion||"7.1",port:j.port||6379,numCacheClusters:j.numCacheNodes||2,automaticFailover:j.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:j.snapshotRetentionLimit||7,snapshotWindow:j.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(ft,St),G&&bt)this.builder.addResource(bt,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,f);let j=me.elasticache||{},{cluster:St,subnetGroup:G,logicalId:ft,subnetGroupId:bt}=Go.createMemcached({slug:u,environment:f,nodeType:j.nodeType||me.nodeType||"cache.t3.micro",engineVersion:j.engineVersion||"1.6.22",numCacheNodes:j.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(ft,St),G&&bt)this.builder.addResource(bt,G);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[ft,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let At=this.mergedConfig.infrastructure?.email;if(At){let ze=At.domain||this.mergedConfig.infrastructure?.dns?.domain;if(ze){let{emailIdentity:j,logicalId:St}=m.verifyDomain({domain:ze,slug:u,environment:f,enableDkim:At.enableDkim!==!1,dkimKeyLength:At.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(St,j),At.configurationSet!==!1){let{configurationSet:bt,logicalId:Mt}=m.createConfigurationSet({slug:u,environment:f});this.builder.addResource(Mt,bt)}let G=At.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(G){if(At.enableDkim!==!1)for(let Jt=1;Jt<=3;Jt++){let er=`DkimRecord${Jt}${ze.replace(/\./g,"")}`;this.builder.addResource(er,{Type:"AWS::Route53::RecordSet",DependsOn:[St],Properties:{HostedZoneId:G,Name:{"Fn::GetAtt":[St,`DkimDNSTokenName${Jt}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[St,`DkimDNSTokenValue${Jt}`]}]}})}let{record:bt,logicalId:Mt}=m.createSpfRecord(ze,G);this.builder.addResource(Mt,bt);let{record:Wt,logicalId:Kt}=m.createDmarcRecord(ze,G,{policy:"none",reportingEmail:At.dmarcReportingEmail||`dmarc-reports@${ze}`});this.builder.addResource(Kt,Wt)}this.builder.addOutput("EmailDomain",{Value:ze,Description:"SES verified email domain"});let ft=At.server;if(ft?.enabled&&G){let bt=this.mergedConfig.environments[f]?.region||this.mergedConfig.project.region||"us-east-1",Mt=`${u}-${f}-email`,{role:Wt,policy:Kt,roleLogicalId:Jt,policyLogicalId:er}=m.createEmailLambdaRole({slug:u,environment:f,s3BucketArn:`arn:aws:s3:::${Mt}`,sesIdentityArn:`arn:aws:ses:${bt}:*:identity/${ze}`});this.builder.addResource(Jt,Wt),this.builder.addResource(er,Kt);let{function:Lr,permission:Xt,logicalId:Cr,permissionLogicalId:Vr}=m.createInboundEmailLambda({slug:u,environment:f,roleArn:{"Fn::GetAtt":[Jt,"Arn"]},s3BucketName:Mt,organizedPrefix:"mailboxes/"});this.builder.addResource(Cr,Lr),this.builder.addResource(Vr,Xt);let Qr=m.createInboundEmailSetup({slug:u,environment:f,domain:ze,s3BucketName:Mt,s3KeyPrefix:"inbox/",region:bt,hostedZoneId:G,lambdaFunctionArn:{"Fn::GetAtt":[Cr,"Arn"]}});for(let[Br,fn]of Object.entries(Qr.resources)){if(fn.Type==="AWS::SES::ReceiptRule")fn.DependsOn=[Vr,Cr];this.builder.addResource(Br,fn)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:Cr},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:Mt,Description:"S3 bucket for email storage"});let Gr=this.serverEipLogicalIds.get("app");if(Gr&&G){let fn=`${ft?.subdomain||"mail"}.${ze}`,Xn=fn.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Xn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:G,Name:fn,Type:"A",TTL:"300",ResourceRecords:[{Ref:Gr}]}})}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,f);let{domain:j,logicalId:St}=lr.createDomain({slug:u,environment:f,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(St,j),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[St,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[St,"Arn"]},Description:"OpenSearch domain ARN"})}let mt=this.mergedConfig.infrastructure?.fileSystem;if(mt&&Object.keys(mt).length>0){this.generateNetworkInfrastructure(u,f);for(let[ze,j]of Object.entries(mt)){let{fileSystem:St,logicalId:G}=Ze.createFileSystem({slug:`${u}-${ze}`,environment:f,encrypted:j.encrypted!==!1,performanceMode:j.performanceMode||"generalPurpose",throughputMode:j.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(G,St);let{securityGroup:ft,logicalId:bt}=Ze.createEfsSecurityGroup({slug:`${u}-${ze}`,environment:f,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(bt,ft);let{mountTargets:Mt,logicalIds:Wt}=Ze.createMultiAzMountTargets(G,{slug:`${u}-${ze}`,environment:f,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:bt}});for(let Kt=0;Kt<Mt.length;Kt++)this.builder.addResource(Wt[Kt],Mt[Kt]);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||["*"],St=Me.allowStreaming!==!1,G;if(ze==="ecs")G=Oe.enableBedrockForEcs({slug:u,environment:f,models:j,allowStreaming:St});else if(ze==="ec2")G=Oe.enableBedrockForEc2({slug:u,environment:f,models:j,allowStreaming:St});else if(ze==="lambda")G=Oe.enableBedrockForLambda({slug:u,environment:f,models:j,allowStreaming:St});else G=Oe.createBedrockRole(ze,{slug:u,environment:f,models:j,allowStreaming:St});if(this.builder.addResource(G.logicalId,G.role),Me.allowAsync){let{policy:ft,logicalId:bt}=Oe.createBedrockPolicy({slug:u,environment:f,models:j,allowStreaming:St,allowAsync:!0});this.builder.addResource(bt,ft)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[G.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(u,f){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let y=h.name||`${u}-${f}-realtime`,R=h.scaling||{},v=h.storage||{type:"dynamodb"},P=R.handlerMemory||256,L=R.handlerTimeout||30,z=`${u}${f}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),fe=`${u}${f}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(v.type==="dynamodb"){let Wt=v.dynamodb||{},Kt=Wt.billingMode||"PAY_PER_REQUEST";this.builder.addResource(z,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${f}-realtime-connections`,BillingMode:Kt,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"},...Kt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Wt.readCapacity||5,WriteCapacityUnits:Wt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Kt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Wt.readCapacity||5,WriteCapacityUnits:Wt.writeCapacity||5}},...Wt.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${u}-${f}-realtime-connections`},{Key:"Environment",Value:f}]}}),this.builder.addResource(fe,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${f}-realtime-channels`,BillingMode:Kt,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"},...Kt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Wt.readCapacity||5,WriteCapacityUnits:Wt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Kt==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Wt.readCapacity||5,WriteCapacityUnits:Wt.writeCapacity||5}},Tags:[{Key:"Name",Value:`${u}-${f}-realtime-channels`},{Key:"Environment",Value:f}]}})}let me=`${u}${f}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(me,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${f}-realtime-handler-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"],Policies:[{PolicyName:"RealtimeHandlerPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:UpdateItem"],Resource:[{"Fn::GetAtt":[z,"Arn"]},{"Fn::Sub":`\${${z}.Arn}/index/*`},{"Fn::GetAtt":[fe,"Arn"]},{"Fn::Sub":`\${${fe}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let At=`${u}${f}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),It=`${u}${f}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),mt=`${u}${f}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(At,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[me,z]}),this.builder.addResource(It,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[me,z,fe]}),this.builder.addResource(mt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${f}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[me,"Arn"]},MemorySize:P,Timeout:L,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:z},CHANNELS_TABLE:{Ref:fe},ENVIRONMENT:f}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[me,z,fe]});let Me=`${u}${f}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Me,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:y,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:y,Environment:f}}});let ze=`${At}Permission`,j=`${It}Permission`,St=`${mt}Permission`;this.builder.addResource(ze,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:At},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$connect`}}}),this.builder.addResource(j,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:It},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Me}}/*/$disconnect`}}}),this.builder.addResource(St,{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`,ft=`${Me}DisconnectInteg`,bt=`${Me}MessageInteg`;this.builder.addResource(G,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Me},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${At}.Arn}/invocations`}}}),this.builder.addResource(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/\${${It}.Arn}/invocations`}}}),this.builder.addResource(bt,{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/\${${ft}}`}}}),this.builder.addResource(`${Me}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Me},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${bt}}`}}});let Mt=`${Me}Stage`;if(this.builder.addResource(Mt,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Me},StageName:f,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:R.messagesPerSecond||1000,ThrottlingRateLimit:R.messagesPerSecond||1000}}}),h.monitoring?.enabled){let Wt=h.monitoring,Kt=Wt.notificationTopicArn;if(!Kt&&Wt.notificationEmails?.length){let Jt=`${Me}AlarmTopic`;this.builder.addResource(Jt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${f}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),Wt.notificationEmails.forEach((er,Lr)=>{this.builder.addResource(`${Jt}Sub${Lr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Jt},Protocol:"email",Endpoint:er}})}),Kt={Ref:Jt}}if(Wt.connectionThreshold)this.builder.addResource(`${Me}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-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}}],...Kt&&{AlarmActions:[Kt]}}});if(Wt.errorThreshold)this.builder.addResource(`${Me}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${f}-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}}],...Kt&&{AlarmActions:[Kt]}}})}this.builder.addOutput(`${Me}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${Me}}.execute-api.\${AWS::Region}.amazonaws.com/${f}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${Me}Id`,{Description:"WebSocket API ID",Value:{Ref:Me},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
|
|
13
|
+
`: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=vm({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,wm({primaryBucket:Ft,replicaBucket:Xt.replicaBucket}));let xr=Wt.Properties;xr.VersioningConfiguration={Status:"Enabled"},xr.ReplicationConfiguration=Rm({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:Tm(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`
|
|
15
15
|
const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
|
|
16
16
|
const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb');
|
|
17
17
|
|
|
@@ -170,56 +170,56 @@ catch (error) {
|
|
|
170
170
|
return { statusCode: 500, body: JSON.stringify({ error: 'Internal error' }) };
|
|
171
171
|
}
|
|
172
172
|
};
|
|
173
|
-
`.trim()}generateRealtimeServerResources(u,
|
|
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'
|
|
174
174
|
|
|
175
175
|
export default {
|
|
176
176
|
verbose: ${this.environment!=="production"},
|
|
177
|
-
driver: '${
|
|
177
|
+
driver: '${p.driver||"bun"}',
|
|
178
178
|
default: 'bun',
|
|
179
179
|
|
|
180
180
|
connections: {
|
|
181
181
|
bun: {
|
|
182
182
|
driver: 'bun',
|
|
183
|
-
host: process.env.BROADCAST_HOST || '${
|
|
184
|
-
port: Number(process.env.BROADCAST_PORT) || ${
|
|
185
|
-
scheme: '${
|
|
183
|
+
host: process.env.BROADCAST_HOST || '${p.host||"0.0.0.0"}',
|
|
184
|
+
port: Number(process.env.BROADCAST_PORT) || ${p.port||6001},
|
|
185
|
+
scheme: '${p.scheme||"wss"}',
|
|
186
186
|
options: {
|
|
187
|
-
idleTimeout: ${
|
|
188
|
-
maxPayloadLength: ${
|
|
189
|
-
backpressureLimit: ${
|
|
190
|
-
closeOnBackpressureLimit: ${
|
|
191
|
-
sendPings: ${
|
|
192
|
-
perMessageDeflate: ${
|
|
187
|
+
idleTimeout: ${p.idleTimeout||120},
|
|
188
|
+
maxPayloadLength: ${p.maxPayloadLength||16777216},
|
|
189
|
+
backpressureLimit: ${p.backpressureLimit||1048576},
|
|
190
|
+
closeOnBackpressureLimit: ${p.closeOnBackpressureLimit||!1},
|
|
191
|
+
sendPings: ${p.sendPings!==!1},
|
|
192
|
+
perMessageDeflate: ${p.perMessageDeflate!==!1},
|
|
193
193
|
},
|
|
194
194
|
},
|
|
195
195
|
},
|
|
196
|
-
${
|
|
196
|
+
${p.redis?.enabled?`
|
|
197
197
|
redis: {
|
|
198
|
-
host: process.env.REDIS_HOST || '${
|
|
199
|
-
port: Number(process.env.REDIS_PORT) || ${
|
|
200
|
-
${
|
|
201
|
-
database: ${
|
|
202
|
-
keyPrefix: '${
|
|
198
|
+
host: process.env.REDIS_HOST || '${p.redis.host||"localhost"}',
|
|
199
|
+
port: Number(process.env.REDIS_PORT) || ${p.redis.port||6379},
|
|
200
|
+
${p.redis.password?`password: process.env.REDIS_PASSWORD || '${p.redis.password}',`:""}
|
|
201
|
+
database: ${p.redis.database||0},
|
|
202
|
+
keyPrefix: '${p.redis.keyPrefix||"broadcasting:"}',
|
|
203
203
|
},
|
|
204
204
|
`:""}
|
|
205
|
-
${
|
|
205
|
+
${p.rateLimit?.enabled?`
|
|
206
206
|
rateLimit: {
|
|
207
|
-
max: ${
|
|
208
|
-
window: ${
|
|
209
|
-
perChannel: ${
|
|
210
|
-
perUser: ${
|
|
207
|
+
max: ${p.rateLimit.max||100},
|
|
208
|
+
window: ${p.rateLimit.window||60000},
|
|
209
|
+
perChannel: ${p.rateLimit.perChannel!==!1},
|
|
210
|
+
perUser: ${p.rateLimit.perUser!==!1},
|
|
211
211
|
},
|
|
212
212
|
`:""}
|
|
213
|
-
${
|
|
213
|
+
${p.loadManagement?.enabled?`
|
|
214
214
|
loadManagement: {
|
|
215
215
|
enabled: true,
|
|
216
|
-
maxConnections: ${
|
|
217
|
-
maxSubscriptionsPerConnection: ${
|
|
218
|
-
shedLoadThreshold: ${
|
|
216
|
+
maxConnections: ${p.loadManagement.maxConnections||1e4},
|
|
217
|
+
maxSubscriptionsPerConnection: ${p.loadManagement.maxSubscriptionsPerConnection||100},
|
|
218
|
+
shedLoadThreshold: ${p.loadManagement.shedLoadThreshold||0.8},
|
|
219
219
|
},
|
|
220
220
|
`:""}
|
|
221
221
|
} satisfies BroadcastConfig
|
|
222
|
-
`}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function eg(u){let
|
|
222
|
+
`}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function eg(u){let p=[],h=[];if(!u.AWSTemplateFormatVersion)p.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(u.AWSTemplateFormatVersion!=="2010-09-09")h.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!u.Resources||Object.keys(u.Resources).length===0)p.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[y,R]of Object.entries(u.Resources))tg(y,R,p,h);if(u.Resources){let y=sg(u.Resources);if(y.length>0)p.push({path:"Resources",message:`Circular dependencies detected: ${y.join(" -> ")}`,severity:"error"})}if(u.Parameters)for(let[y,R]of Object.entries(u.Parameters))ng(y,R,p,h);if(u.Outputs)for(let[y,R]of Object.entries(u.Outputs))ig(y,R,p,h);return{valid:p.length===0,errors:p,warnings:h}}function tg(u,p,h,y){if(!p.Type)h.push({path:`Resources.${u}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(u))y.push({path:`Resources.${u}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(p.Type&&!p.Type.startsWith("AWS::")&&!p.Type.startsWith("Custom::"))h.push({path:`Resources.${u}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(p.Properties){for(let[R,v]of Object.entries(p.Properties))if(v===void 0||v===null)y.push({path:`Resources.${u}.Properties.${R}`,message:"Property has undefined or null value",severity:"warning"})}if(p.DependsOn){if(typeof p.DependsOn==="string"){if(p.DependsOn===u)h.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(p.DependsOn)){if(p.DependsOn.includes(u))h.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function ng(u,p,h,y){if(!p.Type)h.push({path:`Parameters.${u}.Type`,message:"Parameter Type is required",severity:"error"});let R=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(p.Type&&!R.includes(p.Type)&&!p.Type.startsWith("AWS::"))y.push({path:`Parameters.${u}.Type`,message:`Uncommon parameter type: ${p.Type}`,severity:"warning"});if(p.NoEcho&&p.Default)y.push({path:`Parameters.${u}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function ig(u,p,h,y){if(!p.Value)h.push({path:`Outputs.${u}.Value`,message:"Output Value is required",severity:"error"})}function sg(u){let p={};for(let[P,L]of Object.entries(u)){if(p[P]=[],L.DependsOn){if(typeof L.DependsOn==="string")p[P].push(L.DependsOn);else if(Array.isArray(L.DependsOn))p[P].push(...L.DependsOn)}let z=Wc(L);p[P].push(...z)}let h=new Set,y=new Set,R=[];function v(P,L){h.add(P),y.add(P),L.push(P);let z=p[P]||[];for(let fe of z)if(!h.has(fe)){if(v(fe,L))return!0}else if(y.has(fe)){let me=L.indexOf(fe);return R.push(...L.slice(me),fe),!0}return L.pop(),y.delete(P),!1}for(let P of Object.keys(p))if(!h.has(P)){if(v(P,[]))return R}return[]}function Wc(u,p=[]){if(typeof u!=="object"||u===null)return p;if(Array.isArray(u)){for(let h of u)Wc(h,p);return p}if(u.Ref&&typeof u.Ref==="string"&&!u.Ref.startsWith("AWS::"))p.push(u.Ref);if(u["Fn::GetAtt"]){let h=u["Fn::GetAtt"];if(Array.isArray(h)&&h.length>0)p.push(h[0])}for(let h of Object.values(u))Wc(h,p);return p}function ug(u){let p=[],h=[],y=new TextEncoder().encode(u).length,R=51200,v=460800;if(y>51200)if(y>460800)p.push({path:"template",message:`Template size (${y} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else h.push({path:"template",message:`Template size (${y} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:p.length===0,errors:p,warnings:h}}function gg(u){let p=[],h=[],y=u.Resources?Object.keys(u.Resources).length:0,R=u.Parameters?Object.keys(u.Parameters).length:0,v=u.Outputs?Object.keys(u.Outputs).length:0;if(y>500)p.push({path:"Resources",message:`Template has ${y} resources, exceeding the limit of 500`,severity:"error"});else if(y>200)h.push({path:"Resources",message:`Template has ${y} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(R>200)p.push({path:"Parameters",message:`Template has ${R} parameters, exceeding the limit of 200`,severity:"error"});if(v>200)p.push({path:"Outputs",message:`Template has ${v} outputs, exceeding the limit of 200`,severity:"error"});return{valid:p.length===0,errors:p,warnings:h}}function cR(u){let{domains:p,email:h,staging:y=!1,challengeType:R="http-01",certPath:v="/etc/letsencrypt/live",autoRenew:P=!0}=u,L=p[0],z=p.map((me)=>`-d ${me}`).join(" "),fe=y?"--staging":"";if(R==="http-01")return bg({domains:p,email:h,staging:y,certPath:v,autoRenew:P,domainFlags:z,stagingFlag:fe,primaryDomain:L});else{let me=u.dnsProvider?.provider||(u.hostedZoneId?"route53":void 0);return Tg({domains:p,email:h,staging:y,certPath:v,autoRenew:P,domainFlags:z,stagingFlag:fe,primaryDomain:L,hostedZoneId:u.hostedZoneId,dnsProvider:u.dnsProvider,dnsProviderType:me})}}function bg(u){let{email:p,certPath:h,autoRenew:y,domainFlags:R,stagingFlag:v,primaryDomain:P}=u;return`
|
|
223
223
|
# ==========================================
|
|
224
224
|
# Let's Encrypt Certificate Setup (HTTP-01)
|
|
225
225
|
# ==========================================
|
|
@@ -235,7 +235,7 @@ certbot certonly \\
|
|
|
235
235
|
--standalone \\
|
|
236
236
|
--non-interactive \\
|
|
237
237
|
--agree-tos \\
|
|
238
|
-
--email ${
|
|
238
|
+
--email ${p} \\
|
|
239
239
|
${v} \\
|
|
240
240
|
${R}
|
|
241
241
|
|
|
@@ -257,7 +257,7 @@ ${y?Vc(P):"# Auto-renewal disabled"}
|
|
|
257
257
|
|
|
258
258
|
# Restart the application
|
|
259
259
|
systemctl start stacks
|
|
260
|
-
`}function Tg(u){let{email:
|
|
260
|
+
`}function Tg(u){let{email:p,certPath:h,autoRenew:y,domainFlags:R,stagingFlag:v,primaryDomain:P,hostedZoneId:L,dnsProvider:z,dnsProviderType:fe}=u;if(fe==="route53"||L){if(!L)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
|
|
261
261
|
# ==========================================
|
|
262
262
|
# Let's Encrypt Certificate Setup (DNS-01 via Route53)
|
|
263
263
|
# ==========================================
|
|
@@ -270,7 +270,7 @@ certbot certonly \\
|
|
|
270
270
|
--dns-route53 \\
|
|
271
271
|
--non-interactive \\
|
|
272
272
|
--agree-tos \\
|
|
273
|
-
--email ${
|
|
273
|
+
--email ${p} \\
|
|
274
274
|
${v} \\
|
|
275
275
|
${R}
|
|
276
276
|
|
|
@@ -289,7 +289,7 @@ else
|
|
|
289
289
|
fi
|
|
290
290
|
|
|
291
291
|
${y?Vc(P):"# Auto-renewal disabled"}
|
|
292
|
-
`}if(!z)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let me=z.provider.toUpperCase(),
|
|
292
|
+
`}if(!z)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let me=z.provider.toUpperCase(),bt=$g(z);return`
|
|
293
293
|
# ==========================================
|
|
294
294
|
# Let's Encrypt Certificate Setup (DNS-01 via ${me})
|
|
295
295
|
# ==========================================
|
|
@@ -297,7 +297,7 @@ ${y?Vc(P):"# Auto-renewal disabled"}
|
|
|
297
297
|
# Install certbot
|
|
298
298
|
dnf install -y certbot jq curl
|
|
299
299
|
|
|
300
|
-
${
|
|
300
|
+
${bt}
|
|
301
301
|
|
|
302
302
|
# Create DNS challenge hook scripts directory
|
|
303
303
|
mkdir -p /etc/letsencrypt/hooks
|
|
@@ -312,7 +312,7 @@ DOMAIN="$CERTBOT_DOMAIN"
|
|
|
312
312
|
VALIDATION="$CERTBOT_VALIDATION"
|
|
313
313
|
RECORD_NAME="_acme-challenge.$DOMAIN"
|
|
314
314
|
|
|
315
|
-
${
|
|
315
|
+
${wg(z)}
|
|
316
316
|
|
|
317
317
|
# Wait for DNS propagation
|
|
318
318
|
echo "Waiting 60 seconds for DNS propagation..."
|
|
@@ -331,7 +331,7 @@ DOMAIN="$CERTBOT_DOMAIN"
|
|
|
331
331
|
VALIDATION="$CERTBOT_VALIDATION"
|
|
332
332
|
RECORD_NAME="_acme-challenge.$DOMAIN"
|
|
333
333
|
|
|
334
|
-
${
|
|
334
|
+
${Ig(z)}
|
|
335
335
|
CLEANUPHOOK
|
|
336
336
|
|
|
337
337
|
chmod +x /etc/letsencrypt/hooks/cleanup-hook.sh
|
|
@@ -344,7 +344,7 @@ certbot certonly \\
|
|
|
344
344
|
--manual-cleanup-hook /etc/letsencrypt/hooks/cleanup-hook.sh \\
|
|
345
345
|
--non-interactive \\
|
|
346
346
|
--agree-tos \\
|
|
347
|
-
--email ${
|
|
347
|
+
--email ${p} \\
|
|
348
348
|
${v} \\
|
|
349
349
|
${R}
|
|
350
350
|
|
|
@@ -374,7 +374,7 @@ export GODADDY_API_SECRET="${u.apiSecret}"
|
|
|
374
374
|
export GODADDY_ENV="${u.environment||"production"}"
|
|
375
375
|
`;case"route53":return`
|
|
376
376
|
# Route53 uses IAM role credentials
|
|
377
|
-
`;default:return""}}function
|
|
377
|
+
`;default:return""}}function wg(u){switch(u.provider){case"porkbun":return`
|
|
378
378
|
# Extract root domain (last two parts)
|
|
379
379
|
ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
|
|
380
380
|
SUBDOMAIN="_acme-challenge"
|
|
@@ -418,7 +418,7 @@ curl -s -X PATCH "$API_URL/v1/domains/$ROOT_DOMAIN/records" \\
|
|
|
418
418
|
"data": "'"$VALIDATION"'",
|
|
419
419
|
"ttl": 600
|
|
420
420
|
}]'
|
|
421
|
-
`;default:return'echo "Unsupported DNS provider"'}}function
|
|
421
|
+
`;default:return'echo "Unsupported DNS provider"'}}function Ig(u){switch(u.provider){case"porkbun":return`
|
|
422
422
|
# Extract root domain, and the challenge's subdomain the way the auth hook did
|
|
423
423
|
ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
|
|
424
424
|
SUBDOMAIN="_acme-challenge"
|
|
@@ -515,12 +515,12 @@ systemctl enable certbot-renewal.timer
|
|
|
515
515
|
systemctl start certbot-renewal.timer
|
|
516
516
|
|
|
517
517
|
echo "Certificate auto-renewal configured"
|
|
518
|
-
`}function lR(u){let{httpPort:
|
|
518
|
+
`}function lR(u){let{httpPort:p=80,httpsPort:h=443,certPath:y="/etc/ssl/stacks",redirectHttp:R=!0}=u;return`
|
|
519
519
|
// HTTPS Server with Let's Encrypt certificates
|
|
520
520
|
import { existsSync } from 'node:fs'
|
|
521
521
|
|
|
522
522
|
const CERT_PATH = '${y}'
|
|
523
|
-
const HTTP_PORT = ${
|
|
523
|
+
const HTTP_PORT = ${p}
|
|
524
524
|
const HTTPS_PORT = ${h}
|
|
525
525
|
|
|
526
526
|
// Check if certificates exist
|
|
@@ -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
|
|
605
|
-
`).filter((v)=>!v.startsWith("-----")).join(""),f=Buffer.from(u,"base64"),h=f.length-65,y=f.subarray(h+1,h+33),R=f.subarray(h+33,h+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(y),y:this.base64UrlEncode(R)}}getJwkThumbprint(){let u=this.getJwk(),f=JSON.stringify({crv:u.crv,kty:u.kty,x:u.x,y:u.y}),h=td("sha256").update(f).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,f){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=f===""?"":this.base64UrlEncode(JSON.stringify(f)),L=`${v}.${P}`,z=Fg("SHA256");z.update(L);let fe=z.sign(this.accountKey),me=fe.subarray(4,4+fe[3]),At=4+fe[3]+2,It=fe.subarray(At,At+fe[At-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,f){let h=await this.signPayload(u,f),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:f,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 f=await this.getDirectory(),{body:h,headers:y}=await this.acmeRequest(f.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:f}=await this.acmeRequest(u,""),h=f.identifier.value,y=this.getJwkThumbprint(),R=f.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(td("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,f=30){for(let h=0;h<f;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:f}=rd("rsa",{modulusLength:2048}),h=f.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(u,f),privateKey:h}}createSimpleCsr(u,f){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(u,f){let{csr:h,privateKey:y}=this.generateCsr(f),{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 qr=(u)=>u===void 0?void 0:u?"on":"off";function zc(u){let f={ssl:u.ssl,always_use_https:qr(u.alwaysUseHttps),automatic_https_rewrites:qr(u.automaticHttpsRewrites),min_tls_version:u.minTlsVersion,tls_1_3:qr(u.tls13),brotli:qr(u.brotli),http3:qr(u.http3),"0rtt":qr(u.zeroRtt),early_hints:qr(u.earlyHints),browser_cache_ttl:u.browserCacheTtl,always_online:qr(u.alwaysOnline),websockets:qr(u.websockets),email_obfuscation:qr(u.emailObfuscation)};if(u.hsts)f.security_header={strict_transport_security:{enabled:u.hsts.enabled,max_age:u.hsts.maxAge??31536000,include_subdomains:u.hsts.includeSubdomains??!1,preload:u.hsts.preload??!1,nosniff:u.hsts.noSniff??!0}};for(let h of Object.keys(f))if(f[h]===void 0)delete f[h];return{...f,...u.raw??{}}}var eo={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 Mg}from"node:tls";async function Hc(u){let{address:f,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=Mg({host:f,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 Wg(u,f){let h=f.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 Vg(u){let{provider:f,zone:h,hosts:y,ipv4:R,ipv6:v,proxied:P=!0,settings:L=eo,cache:z,originGuard:fe,purge:me=!0,ttl:At=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 f.listEdgeCertificateHosts(h):null;for(let G of y){let ft=P;if(ft&&j&&!Wg(j,G)){ft=!1;let Mt=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:Mt}),Me.warnings.push(`${G}: publishing DNS-only — ${Mt}. 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&&!It){let Mt=await Hc({address:R,serverName:G});if(!Mt.trusted){ft=!1;let Wt=Mt.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(ft)ze.push(G);let bt=[{type:"A",content:R}];if(v&&Jn(G))bt.push({type:"AAAA",content:v});for(let{type:Mt,content:Wt}of bt){let Kt=await f.upsertRecord(h,{name:G,type:Mt,content:Wt,ttl:At,proxied:ft});if(Kt.success)Me.records.push({host:G,type:Mt,content:Wt,proxied:ft});else Me.warnings.push(`${G} ${Mt} → ${Wt} failed: ${Kt.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 f.applyZoneSettings(h,G);Me.settingsChanged=ft.changed;for(let bt of ft.failed)Me.warnings.push(`zone setting '${bt.id}' could not be applied: ${bt.error}`)}catch(G){Me.warnings.push(`zone settings could not be read: ${G instanceof Error?G.message:String(G)}`)}let St=Dc(ze,z);if(St.length>0){let G=await f.putManagedPhaseRules(h,"http_request_cache_settings",St);if(G.success)Me.cacheRules=St.length;else Me.warnings.push(`cache rules could not be written: ${G.message}`)}if(fe){let G=Pc(ze,fe.header,fe.value);if(G.length>0){let ft=await f.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 f.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 zg=(u)=>process.env[u];function ld(u,f){let h=u.replace(/\.$/,"").toLowerCase();if(f){let y=f.replace(/\.$/,"").toLowerCase();if(h===y||h.endsWith(`.${y}`))return y}return h.split(".").slice(-2).join(".")}function Hg(u,f={}){let h=f.env??zg,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()))]:po(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)=>ld(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??{},At=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??eo,cache:me.cache,originGuard:At,purge:me.purgeOnDeploy!==!1,skipOriginProbe:me.skipOriginProbe===!0},errors:R}}var Ug=26214400;var Gg=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class ud{name="cloudflare-pages";apiToken;accountId;constructor(u){if(!u.apiToken)throw Error("Cloudflare Pages needs an API token");if(!u.accountId)throw Error("Cloudflare Pages needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId}async request(u,f,h){return ks(u,`/accounts/${this.accountId}${f}`,`Bearer ${this.apiToken}`,h)}async getProject(u){try{return await this.request("GET",`/pages/projects/${u}`)}catch(f){if(f instanceof Error&&/\b8000007\b|not found/i.test(f.message))return null;throw f}}async ensureProject(u,f="main"){let h=await this.getProject(u);if(h)return h;return this.request("POST","/pages/projects",{name:u,production_branch:f})}async uploadToken(u){return(await this.request("GET",`/pages/projects/${u}/upload-token`)).jwt}async missingHashes(u,f){let h=await ks("POST","/pages/assets/check-missing",`Bearer ${u}`,{hashes:f});return new Set(h)}async upsertHashes(u,f){await ks("POST","/pages/assets/upsert-hashes",`Bearer ${u}`,{hashes:f})}async uploadBatch(u,f){let h=f.map((y)=>({key:y.hash,value:y.base64,metadata:{contentType:Kg(y.extension)},base64:!0}));await ks("POST","/pages/assets/upload",`Bearer ${u}`,h)}async createDeployment(u,f,h){let y={};for(let v of f)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 f=await gd(u.directory);if(f.length===0)throw Error(`No files to deploy in ${u.directory}`);let h=await this.uploadToken(u.project),y=await this.missingHashes(h,f.map((z)=>z.hash)),R=f.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,At)=>me+At.length,0),u.onProgress?.(P,R.length)}return await this.upsertHashes(h,f.map((z)=>z.hash)),{deployment:await this.createDeployment(u.project,f,u.branch),total:f.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,f){if((await this.listCustomDomains(u)).includes(f))return!1;return await this.request("POST",`/pages/projects/${u}/domains`,{name:f}),!0}}function jg(u,f){return{type:"CNAME",name:u,value:f.endsWith(".pages.dev")?f:`${f}.pages.dev`,ttl:1,proxied:!0}}async function dd(u,f){let{blake3:h}=await import("./chunk-6ky22rmg.js").then((m)=>NS(m.default,1));return(await h(u+f)).slice(0,32)}async function gd(u){let{readdir:f}=await import("node:fs/promises"),{join:h,relative:y,sep:R}=await import("node:path"),v=[];async function P(L){let z=await f(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 At=`/${y(u,me).split(R).join("/")}`;if(Gg.has(At))continue;let It=await Bun.file(me).bytes();if(It.byteLength>26214400)throw Error(`${At} 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:At,hash:await dd(mt,ze),base64:mt,extension:ze,size:It.byteLength})}}return await P(u),v.sort((L,z)=>L.path.localeCompare(z.path)),v}function Kg(u){return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",mjs:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",map:"application/json; charset=utf-8",xml:"application/xml; charset=utf-8",txt:"text/plain; charset=utf-8",svg:"image/svg+xml",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",avif:"image/avif",ico:"image/x-icon",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",pdf:"application/pdf",webmanifest:"application/manifest+json"}[u.toLowerCase()]||"application/octet-stream"}async function ks(u,f,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${f}`,{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 qg}from"node:crypto";var tp="https://api.cloudflare.com/client/v4",rp=10042,Zg=10006,Jg=10059;class Fn extends Error{status;errors;constructor(u,f,h=[]){super(u);this.name="R2ApiError",this.status=f,this.errors=h}hasCode(u){return this.errors.some((f)=>f.code===u)}}class Nn extends Fn{accountId;constructor(u,f,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.`,f,h);this.name="R2NotEnabledError",this.accountId=u}}class ci{name="cloudflare-r2";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare R2 needs an API token");if(!u.accountId)throw Error("Cloudflare R2 needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((f,h)=>fetch(f,h))}async requestEnvelope(u,f,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${f}`,{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 Nn(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} ${f}: ${fe||P.slice(0,200)}`,v.status,z)}return L}async request(u,f,h,y){return(await this.requestEnvelope(u,f,h,y)).result}bucketPath(u){return`/buckets/${encodeURIComponent(u)}`}async listBuckets(u={}){let f=[],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??[];f.push(...v),h=v.length>0?R.result_info?.cursor||void 0:void 0}while(h);return f}async getBucket(u,f={}){try{return await this.request("GET",this.bucketPath(u),void 0,f)}catch(h){if(h instanceof Nn)throw h;if(h instanceof Fn&&(h.hasCode(Zg)||h.status===404))return null;throw h}}async ensureBucket(u,f={}){let h={jurisdiction:f.jurisdiction},y=await this.getBucket(u,h);if(y)return{bucket:y,created:!1};let R={name:u};if(f.locationHint)R.locationHint=f.locationHint;let v=await this.request("POST","/buckets",R,h);return{bucket:{...v,name:v?.name||u},created:!0}}async getCors(u,f={}){try{return(await this.request("GET",`${this.bucketPath(u)}/cors`,void 0,f))?.rules??[]}catch(h){if(h instanceof Fn&&!(h instanceof Nn)&&(h.hasCode(Jg)||h.status===404))return[];throw h}}async putCors(u,f,h={}){if(f.length===0){await this.request("DELETE",`${this.bucketPath(u)}/cors`,void 0,h);return}await this.request("PUT",`${this.bucketPath(u)}/cors`,{rules:f},h)}async ensureCors(u,f,h={}){let y=await this.getCors(u,h);if(Ns(y,f))return!1;return await this.putCors(u,f,h),!0}async getLifecycle(u,f={}){return(await this.request("GET",`${this.bucketPath(u)}/lifecycle`,void 0,f))?.rules??[]}async putLifecycle(u,f,h={}){await this.request("PUT",`${this.bucketPath(u)}/lifecycle`,{rules:f},h)}async ensureLifecycle(u,f,h={}){let y=await this.getLifecycle(u,h);if(Ls(y,f))return!1;return await this.putLifecycle(u,f,h),!0}async listCustomDomains(u,f={}){return(await this.request("GET",`${this.bucketPath(u)}/domains/custom`,void 0,f))?.domains??[]}async attachCustomDomain(u,f,h={}){return this.request("POST",`${this.bucketPath(u)}/domains/custom`,{domain:f.domain,zoneId:f.zoneId,enabled:f.enabled??!0,minTLS:f.minTLS??"1.2"},h)}async updateCustomDomain(u,f,h,y={}){return this.request("PUT",`${this.bucketPath(u)}/domains/custom/${encodeURIComponent(f)}`,h,y)}async ensureCustomDomain(u,f,h={},y){let R=f.minTLS??"1.2",P=(y??await this.listCustomDomains(u,h)).find((fe)=>fe.domain.toLowerCase()===f.domain.toLowerCase());if(!P){let fe=await this.attachCustomDomain(u,{...f,minTLS:R,enabled:!0},h);return{action:"attached",domain:{...fe,domain:fe?.domain||f.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,f={}){return this.request("GET",`${this.bucketPath(u)}/domains/managed`,void 0,f)}async setManagedDomain(u,f,h={}){let y=await this.getManagedDomain(u,h);if(y?.enabled===f)return{changed:!1,domain:y};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(u)}/domains/managed`,{enabled:f},h)}}}function np(u){return`https://${u}.r2.cloudflarestorage.com`}async function Yg(u){let{apiToken:f,accountId:h}=u;if(!f)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 ${f}`}}),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:qg("sha256").update(f).digest("hex"),endpoint:np(h),region:"auto"}}function to(u){if(Array.isArray(u))return`[${u.map(to).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)}:${to(y)}`).join(",")}}`;return JSON.stringify(u)}function ep(u,f){let h=(y)=>y&&y.length>0?[...y].map(String).sort():void 0;return{id:f?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 Ns(u,f){if(u.length!==f.length)return!1;return f.every((h,y)=>{let R=h.id!==void 0;return to(ep(u[y],R))===to(ep(h,R))})}function Ls(u,f){if(u.length!==f.length)return!1;let h=(y)=>to([...y].map((R)=>({...R,storageClassTransitions:R.storageClassTransitions?.length?R.storageClassTransitions:void 0})).sort((R,v)=>R.id.localeCompare(v.id)));return h(u)===h(f)}var Xg="r2 cache",Qg=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function fh(u,f={}){let h=f.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(!f.apiToken||!f.accountId){let me=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),At=`R2: ${v.length} bucket(s) declared but ${me} is not set, skipping.`;return h(At),y.warnings.push(At),y}let P=f.dryRun===!0,L=new ci({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),z=new H(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),fe=new Map;for(let[me,At]of v){let It=At?.name;if(!It||!Qg.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(At,{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,f){let{r2:h,dryRun:y,summary:R,warnings:v}=f,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=Sh(u.customDomains);await ro(f,`cors on ${P}`,async()=>{if(!u.cors)return;if(!fe){z("cors updated","set cors");return}let mt=await h.getCors(P,L);if(Ns(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(f,`lifecycle on ${P}`,async()=>{if(!u.lifecycle)return;let mt=u.lifecycle.map(ap);if(fe){let Me=await h.getLifecycle(P,L);if(Ls(Me,mt))return}if(!y)await h.putLifecycle(P,mt,L);z("lifecycle updated","update lifecycle")}),await ro(f,`r2.dev URL on ${P}`,async()=>{let mt=u.publicDevUrl===!0;if(!fe){if(mt)z("r2.dev URL enabled","enable r2.dev URL");return}if((await 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 At=[];if(me.length>0&&fe)try{At=await h.listCustomDomains(P,L)}catch(mt){if(mt instanceof Nn)throw mt;v.push(`R2: could not list custom domains on ${P}: ${jc(mt)}`)}let It=new Map;for(let{domain:mt,minTLS:Me}of me){let ze=f.claimed.get(mt);if(ze&&ze!==P){v.push(`R2: ${mt} is declared on both ${ze} and ${P}; leaving it on ${ze}.`);continue}f.claimed.set(mt,P);let j=At.find((G)=>G.domain.toLowerCase()===mt),St=Me??"1.2";if(j&&j.enabled&&(j.minTLS??"1.0")===St){if(R.domains.push({domain:mt,status:Gc(j)}),j.zoneId)It.set(mt,j.zoneId);continue}await ro(f,`custom domain ${mt} on ${P}`,async()=>{if(j){if(!y)await h.updateCustomDomain(P,j.domain,{enabled:!0,minTLS:St},L);if(z(`custom domain ${mt} updated`,`update custom domain ${mt}`),R.domains.push({domain:mt,status:Gc({...j,enabled:!0})}),j.zoneId)It.set(mt,j.zoneId);return}let G=await f.cloudflare.zoneIdFor(mt);if(It.set(mt,G),!y)await h.ensureCustomDomain(P,{domain:mt,zoneId:G,minTLS:St},L,At);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)=>f.claimed.get(mt)===P),It,f,z)}async function yh(u,f,h,y,R){let v=ip(u.cache);if(!v||f.length===0)return;let P=new Map;for(let L of f){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: ${jc(fe)}`);continue}P.set(z,[...P.get(z)??[],L])}for(let L of P.values()){let z={action:"set_cache_settings",description:`${qt} ${Xg}`,expression:`(${Vt(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(op(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 f={cache:!0};if(u.edgeTtl!==void 0)f.edge_ttl={mode:"override_origin",default:u.edgeTtl};if(u.browserTtl!==void 0)f.browser_ttl={mode:"override_origin",default:u.browserTtl};return f}function op(u,f){let h=jt(f.expression),y=jn(f.expression),R=(L)=>(L.description||"").startsWith(qt),v=(L)=>L.action===f.action&&L.description===f.description&&(L.enabled??!0)===(f.enabled??!0)&&jn(L.expression)===y&&_s(L.action_parameters)===_s(f.action_parameters),P=!1;for(let L of u){if(!R(L))continue;let z=jt(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 f={id:u.id,enabled:u.enabled??!0,conditions:{prefix:u.prefix??""}};if(u.expireAfterDays!==void 0)f.deleteObjectsTransition={condition:{type:"Age",maxAge:Uc(u.expireAfterDays)}};else if(u.expireOn!==void 0)f.deleteObjectsTransition={condition:{type:"Date",date:u.expireOn}};if(u.abortMultipartUploadsAfterDays!==void 0)f.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:Uc(u.abortMultipartUploadsAfterDays)}};if(u.infrequentAccessAfterDays!==void 0)f.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:Uc(u.infrequentAccessAfterDays)}}];return f}function Uc(u){return Math.round(u*86400)}function Sh(u){let f=new Set,h=[];for(let y of u??[]){let R=typeof y==="string"?{domain:y}:y,v=R.domain?.trim().replace(/\.$/,"").toLowerCase();if(!v||f.has(v))continue;f.add(v),h.push({domain:v,minTLS:R.minTLS})}return h}function Gc(u){if(!u.enabled)return"disabled";let f=u.status?.ownership,h=u.status?.ssl;if(f==="active"&&h==="active")return"active";for(let y of[f,h])if(y==="error"||y==="blocked"||y==="deactivated")return y;return"pending"}async function ro(u,f,h,y){try{await h()}catch(R){if(R instanceof Nn)throw R;u.warnings.push(`R2: ${f} failed: ${jc(R)}`),y?.()}}function jc(u){return u instanceof Error?u.message:String(u)}function _s(u){if(Array.isArray(u))return`[${u.map(_s).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)}:${_s(y)}`).join(",")}}`;return JSON.stringify(u)}import{basename as Ih,extname as Dh}from"node:path";import{createHash as Rh}from"node:crypto";var bh="https://api.cloudflare.com/client/v4",Ln="TS_CLOUD_CONTENT_HASH",io="2025-09-01",qc="application/javascript+module",Ah=10007,Th=[1e4,9109];class ui extends Error{status;errors;constructor(u,f,h=[]){super(u);this.name="WorkersApiError",this.status=f,this.errors=h}hasCode(u){return this.errors.some((f)=>f.code===u)}}class Xs extends ui{permission;constructor(u,f,h,y=[]){super(`The Cloudflare API token is missing the "${u}" permission (${f}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,h,y);this.name="WorkersPermissionError",this.permission=u}}class Wa{name="cloudflare-workers";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare Workers needs an API token");if(!u.accountId)throw Error("Cloudflare Workers needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((f,h)=>fetch(f,h))}async request(u,f,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(`${bh}/accounts/${this.accountId}/workers${f}`,{method:u,headers:y,body:R}),P=await v.text(),L;try{L=JSON.parse(P)}catch{throw new ui(`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 Xs(wh(f),`${u} ${f} -> ${v.status}${fe?`, ${fe}`:""}`,v.status,z);throw new ui(`Cloudflare Workers API error (${v.status}) on ${u} ${f}: ${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(f){if(f instanceof Xs)throw f;if(f instanceof ui&&(f.hasCode(Ah)||f.status===404))return null;throw f}}async getScript(u){return this.getSettings(u)}async uploadModuleScript(u,f){return this.request("PUT",this.scriptPath(u),lp(f))}async ensureModuleScript(u,f){let h=uo(f),y=await this.getSettings(u);if(y&&Xa(y,f,h))return{action:"unchanged",hash:h};return await this.uploadModuleScript(u,up(f,h)),{action:y?"updated":"created",hash:h}}async listCustomDomains(u={}){let f=new URLSearchParams;if(u.service)f.set("service",u.service);if(u.hostname)f.set("hostname",u.hostname);if(u.zoneId)f.set("zone_id",u.zoneId);let h=f.toString(),y=h?`?${h}`:"";return await this.request("GET",`/domains${y}`)??[]}async attachCustomDomain(u,f){let h={hostname:u,service:f.service,environment:f.environment??"production"};if(f.zoneId)h.zone_id=f.zoneId;return this.request("PUT","/domains",h)}async detachCustomDomain(u){await this.request("DELETE",`/domains/${encodeURIComponent(u)}`)}async ensureCustomDomain(u,f,h){let R=(h??await this.listCustomDomains({hostname:u})).find((P)=>P.hostname.toLowerCase()===u.toLowerCase());if(R&&R.service===f.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,f);return{action:"attached",domain:{...v,hostname:v?.hostname||u}}}}function Ph(u,f){if(f.some((h)=>Th.includes(h.code)))return!0;return(u===401||u===403)&&f.length===0}function wh(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 f={main_module:u.mainModule,bindings:u.bindings??[],compatibility_date:u.compatibilityDate??io,compatibility_flags:u.compatibilityFlags??[],keep_bindings:["secret_text"]},h=new FormData;h.append("metadata",JSON.stringify(f));for(let y of u.modules)h.append(y.name,new Blob([y.content],{type:y.type}),y.name);return h}function uo(u){let f={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!==Ln).sort((h,y)=>h.name.localeCompare(y.name)),compatibilityDate:u.compatibilityDate??io,compatibilityFlags:[...u.compatibilityFlags??[]].sort()};return cp(Kc(f))}function up(u,f=uo(u)){return{...u,bindings:[...(u.bindings??[]).filter((h)=>h.name!==Ln),{type:"plain_text",name:Ln,text:f}]}}function Xa(u,f,h){let y=u.bindings??[],R=y.find((v)=>v.name===Ln&&v.type==="plain_text");if(!R||R.text!==h)return!1;return(f.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 Rh("sha256").update(u).digest("hex")}function Kc(u){if(Array.isArray(u))return`[${u.map(Kc).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)}:${Kc(y)}`).join(",")}}`;return JSON.stringify(u)}async function Zc(u){if(!await Bun.file(u).exists())throw Error(`Worker entry not found: ${u}`);let f;try{f=await Bun.build({entrypoints:[u],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(R){throw Error(`Bundling Worker ${u} failed: ${kh(R)}`)}if(!f.success)throw Error(`Bundling Worker ${u} failed: ${f.logs.map((R)=>String(R.message??R)).join("; ")}`);if(f.outputs.length!==1)throw Error(`Bundling Worker ${u} produced ${f.outputs.length} files (${f.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=f.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:`${Ih(u,Dh(u))}.js`,content:y,type:qc,size:new TextEncoder().encode(y).byteLength}}function kh(u){if(u instanceof AggregateError&&u.errors.length>0)return u.errors.map((f)=>f instanceof Error?f.message:String(f?.message??f)).join("; ");return u instanceof Error?u.message:String(u)}import{isAbsolute as Oh,resolve as Nh}from"node:path";var xh="https://api.cloudflare.com/client/v4",Lh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function Fh(u,f={}){let h=f.log??(()=>{}),y={workers:[],warnings:[]},R=Object.entries(u.infrastructure?.workers??u.workers??{});if(R.length===0)return h("Workers: none declared, skipping."),y;if(!f.apiToken||!f.accountId){let L=[!f.apiToken&&"CLOUDFLARE_API_TOKEN",!f.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 Wa({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),r2:new ci({apiToken:f.apiToken,accountId:f.accountId,fetch:f.fetch}),cloudflare:new H(f.apiToken,{zoneId:f.zoneId,accountId:f.accountId}),apiToken:f.apiToken,fetch:f.fetch??((L,z)=>fetch(L,z)),projectRoot:f.projectRoot??process.cwd(),dryRun:f.dryRun===!0,warnings:y.warnings,log:h,r2ConfigDomains:zh(v),r2Buckets:v,claimed:new Map};for(let[L,z]of R){let fe=z?.name;if(!fe||!Lh.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 _h(z,me,P);for(let At of me.changes)h(`Workers: ${fe}: ${At}`)}return y}async function _h(u,f,h){let y=u.name,R=Oh(u.entry)?u.entry:Nh(h.projectRoot,u.entry),v;try{v=await Zc(R)}catch(L){throw Error(`Worker ${y}: ${Si(L)}`)}f.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??io,compatibilityFlags:u.compatibilityFlags??[]};if(h.dryRun){let L=await h.workers.getSettings(y);f.changes.push(L&&Xa(L,P,uo(P))?"unchanged":"would upload")}else{let{action:L}=await h.workers.ensureModuleScript(y,P);f.changes.push(L==="unchanged"?"unchanged":"uploaded")}for(let L of Hh(u.customDomains))await Mh(y,L,f,h)}async function Mh(u,f,h,y){let R=(mt)=>{h.domains.push({domain:f,status:mt})},v=(mt)=>{y.warnings.push(`Workers: ${mt}`),R("conflict")},P=y.claimed.get(f);if(P&&P!==u){v(`${f} is declared on both ${P} and ${u}; leaving it on ${P}.`);return}y.claimed.set(f,u);let L=y.r2ConfigDomains.get(f);if(L){v(`${f} is also declared as a custom domain of the R2 bucket '${L}' (r2.buckets). A hostname serves either a bucket or a Worker. Remove it from the bucket's customDomains and detach it in the dashboard (R2, ${L}, Settings, Custom Domains) first; to serve the bucket through the Worker, bind it with bindings.r2Buckets instead.`);return}let z=await Bh(y);if(z===null){R("error");return}let fe=z.find((mt)=>mt.hostname.toLowerCase()===f);if(fe?.service===u){R("active");return}if(fe){v(`${f} is attached to the Worker '${fe.service}'. Detach it there first (Workers & Pages, ${fe.service}, Settings, Domains & Routes); it is not moved automatically.`);return}let me=(await Wh(y))?.get(f);if(me){v(`${f} is attached to the R2 bucket '${me}' as a custom domain. Detach it first (R2, ${me}, Settings, Custom Domains, then re-run the deploy); it is not detached automatically. To serve the bucket through the Worker, bind it with bindings.r2Buckets.`);return}let At;try{At=await y.cloudflare.zoneIdFor(f)}catch(mt){y.warnings.push(`Workers: could not resolve the zone for ${f}, not attached: ${Si(mt)}`),R("error");return}let It=await Vh(y,At,f);if(It.length>0){let mt=It.map((Me)=>`${Me.type} ${Me.content}`).join(", ");v(`${f} already has a DNS record (${mt}). A Worker custom domain creates its own record, so Cloudflare will not attach over it. Delete the record first (DNS, Records), then re-run the deploy; it is not deleted automatically.`);return}if(y.dryRun){h.changes.push(`would attach custom domain ${f}`),R("not attached");return}try{await y.workers.ensureCustomDomain(f,{service:u,zoneId:At},z),h.changes.push(`custom domain ${f} attached`),z.push({id:"",hostname:f,service:u,zone_id:At}),R("pending")}catch(mt){y.warnings.push(`Workers: custom domain ${f} on ${u} failed: ${Si(mt)}`),R("error")}}async function Bh(u){if(u.attached!==void 0)return u.attached;try{u.attached=await u.workers.listCustomDomains()}catch(f){u.warnings.push(`Workers: could not list Worker custom domains, none attached: ${Si(f)}`),u.attached=null}return u.attached}async function Wh(u){if(u.r2AccountDomains!==void 0)return u.r2AccountDomains;let f=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)f.set(v.domain.toLowerCase(),y.name)}u.r2AccountDomains=f}catch(h){u.log(`Workers: could not check R2 custom domains (${Si(h)}); relying on the DNS check.`),u.r2AccountDomains=null}return u.r2AccountDomains}async function Vh(u,f,h){try{let y=await u.fetch(`${xh}/zones/${f}/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} (${Si(y)}); attaching anyway.`),[]}}function dp(u,f){let h=[],y=new Set,R=(P)=>{if(P===Ln)return f.warnings.push(`Workers: ${u.name}: binding name ${Ln} is reserved for ts-cloud, ignored.`),!1;if(y.has(P))return f.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(f.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 f=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)f.set(R,h.name)}return f}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 Si(u){return u instanceof Error?u.message:String(u)}export{Dl as ABTestManager,ye as ACMClient,Nr as ACMDnsValidator,cd as ACME_DIRECTORIES,Oe as AI,lu as API_IDEMPOTENCY_TTL_MS,cu as API_TOKEN_DEFAULT_TTL_MS,du as API_TOKEN_MAX_TTL_MS,gs as API_VERSION,Ie as AUTHORIZATION_CAPABILITIES,iu as AUTH_ACTION_TOKEN_TTL_MS,su as AUTH_MFA_CHALLENGE_TTL_MS,ou as AUTH_OIDC_TRANSACTION_TTL_MS,it as AUTH_SESSION_ABSOLUTE_TTL_MS,nu as AUTH_SESSION_IDLE_TTL_MS,Cy as AWSAPIError,n as AWSClient,A as AWSCloudFormationClient,I as AWSCloudFrontClient,vl as AWSConfigManager,WI as AWS_PSEUDO_PARAMETERS,_e as AWS_REGIONS,_g as AcmeClient,rn as AlertEvaluator,Qi as AlertStore,ko as AnomalyConfigStore,pl as ApiGateway,i as ApiServiceError,Ec as ApplicationAutoScalingClient,ln as Arn,_ as AssetHasher,Y as Auth,as as AuthenticationStore,ji as AutomationApiService,cs as AutomationIdentityStore,Na as AwsAuroraDataAdapter,La as AwsAuroraTransport,ec as AwsDatabaseBackupSource,Or as AwsDriver,Ba as AwsElastiCacheDataAdapter,$a as AwsElastiCacheTransport,Yf as AwsIamCapabilityScanner,sc as AwsInfrastructureBackupSource,ka as AwsRdsDataAdapter,_a as AwsRdsTransport,uh as AwsRegionalDriver,ac as AwsSecretsManagerConfigurationBackend,mm as AwsSpendTransport,cc as AwsSsmConfigurationBackend,Es as BackupCoordinator,Cl as BackupManager,Ya as BackupStore,Rf as BatchProcessingManager,Qn as BedrockClient,Un as BedrockRuntimeClient,Au as BitbucketSourceAdapter,Rl as BlueGreenManager,Af as BounceComplaintHandler,cf as BuildOptimizationManager,Fu as BunDockerRuntime,fg as BunDockerVolumeRuntime,mg as BunFilesystemArchiveRuntime,Ce as CDN,Wo as CHAIN_HEADER,qt as CLOUDFLARE_MANAGED_RULE_PREFIX,cl as CLOUDFRONT_FAILOVER_STATUS_CODES,_C as COMMON_CROSS_ACCOUNT_ROLES,Ln as CONTENT_HASH_BINDING,Ke as CONTROL_PLANE_SCHEMA_VERSION,Go as Cache,es as CanaryManager,sf as CertificateManager,xA as CloudBlockVolumeDriver,no as CloudDriverFactory,tt as CloudError,Nm as CloudFormationBuilder,A as CloudFormationClient,I as CloudFrontClient,Tl as CloudTrailManager,we as CloudWatchLogsClient,ud as CloudflarePagesProvider,H as CloudflareProvider,Gy as CommandHistory,ee as Communication,Xr as ComposeApplicationService,ir as ComposeApplicationStore,Ut as ComprehendClient,a as Compute,fm as ComputeSpendTransport,jo as ConfigurationError,lc as ConfigurationService,oc as ConfigurationStore,$n as ConnectClient,Oa as ContainerDataAdapter,xl as ContainerRegistryManager,ic as ControlPlaneBackupSource,Ka as ControlPlaneCleanupDriver,Oi as ControlPlaneStore,Ro as CounterTracker,Nt as CredentialError,jm as CrossRegionReferenceManager,cy as DASHBOARD_ENTRY,dy as DASHBOARD_PORT_BASE,ly as DASHBOARD_PORT_SPAN,ay as DASHBOARD_STATE_DIR,ia as DEFAULT_ATTACK_MODE_HOURS,io as DEFAULT_COMPATIBILITY_DATE,Xd as DEFAULT_DDOS_THRESHOLDS,Sm as DEFAULT_FAILOVER_STATUS_CODES,Bd as DEFAULT_METER_MAPPINGS,kd as DEFAULT_PRICE_BOOK,pn as DEFAULT_RECURSION_LIMITS,lo as DEFAULT_RPX_CERTS_DIR,te as DEFAULT_SERVICE_LIMITS,tl as DEFAULT_STATE_DIR,Dg as DEFAULT_STATIC_ASSET_EXTENSIONS,ny as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,jA as DEFAULT_TELEMETRY_POLICY,Yp as DEFAULT_THRESHOLDS,DA as DEPLOYMENT_QUEUE_KINDS,Ko as DEPTH_HEADER,en as DETECTABLE_SIGNALS,Ou as DIAGNOSTIC_PRESETS,wf as DLQMonitoringManager,W as DNS,ff as DNSSECManager,hs as DataServiceLifecycle,Pa as DataServiceStore,dr as Database,rf as DatabaseUserManager,q as DebugLogger,ry as DependencyGraph,Z as Deployment,by as DeploymentError,El as DisasterRecoveryManager,Wn as DnsProviderFactory,yr as DockerDataTransport,Ea as DockerDiscoveryAdapter,Jr as DockerNamedVolumeDriver,nc as DockerVolumeBackupSource,c as DurableOperationQueue,Io as DurableQueueWorker,Ue as DynamoDBClient,Hr as EC2Client,He as ECRClient,dt as ECSClient,Rr as EFSClient,Sc as ELBv2Client,_A as ENFORCEMENT_ACTIONS,Fi as ENFORCEMENT_DESCRIPTIONS,O as ENFORCEMENT_SEVERITY,wp as ENVIRONMENT_LABEL,Bu as EcsRuntimeAdapter,na as EdgeRateLimiter,ut as ElastiCacheClient,m as Email,bf as EmailAdvanced,yf as EmailAnalyticsManager,qn as EmailClient,Cf as EmailHandlers,If as EmailTemplateManager,Ma as EncryptedDataSecretStore,Ey as ErrorCodes,Tr as EventBridgeClient,ch as EventBridgeJobAdapter,dc as ExternalConfigurationBackend,Ho as FAILOVER_REPLICA_POLICY_SID,Tf as FIFOQueueManager,Gh as FLY_MACHINES_API,om as FOCUS_VERSION,hl as FileCache,Ze as FileSystem,tc as FilesystemBackupSource,Ua as FleetService,Fa as FleetStore,Is as FlyApiError,fp as FlyClient,e as Fn,yu as GiteaSourceAdapter,fu as GithubSourceAdapter,hu as GitlabSourceAdapter,zm as GlobalResourceManager,Ge as GoDaddyProvider,wl as GuardDutyManager,Ct as HOST_SITES_DIR,Ry as HashCache,Ff as HealthCheckManager,Je as HealthCheckRunner,Fr as HetznerClient,Pe as HetznerDriver,Re as IAMClient,xc as IPV6_EXCLUDED_HOST_LABELS,af as ImageScanningManager,Ep as InfrastructureGenerator,Sd as InvalidOperationTransitionError,Pt as JobLoader,dh as JobProviderReconciler,Ra as JobService,Da as JobStore,vr as KendraClient,$f as LARAVEL_SERVERLESS_BUILD_STEPS,T as LambdaClient,uf as LambdaConcurrencyManager,mf as LambdaDLQManager,gf as LambdaDestinationsManager,df as LambdaLayersManager,xu as LambdaRuntimeAdapter,pf as LambdaVPCManager,lf as LambdaVersionsManager,Bn as LocalEncryptedConfigurationBackend,rc as LogicalDatabaseBackupSource,kl as LogsManager,lS as MANAGED_NODE_VERSIONS,nd as MANAGEMENT_DASHBOARD_SITE,Bm as MANAGEMENT_DASHBOARD_SITE_PREFIX,ss as MAX_CONTROL_HOURS,Id as MAX_CONTROL_PLANE_ERROR_BYTES,zp as MAX_CONTROL_PLANE_JSON_BYTES,vo as METERS,OA as METER_KEYS,LA as MICRO_CENTS,Zp as MIN_PROJECTION_CONFIDENCE,xg as MTA_STS_PORT,za as MaintenanceService,ja as MaintenanceStore,le as Messaging,Zm as MetricsManager,ef as MigrationManager,Qm as MockCloudFormation,Gm as MockDynamoDB,Hm as MockS3,Vo as Monitoring,Jm as MultiAccountManager,qm as MultiRegionManager,$y as MultiStepProgress,S as Network,Uf as NetworkSecurityManager,Hi as NotificationRouter,Cm as ORIGIN_CONNECTION_ATTEMPTS,Em as ORIGIN_CONNECTION_TIMEOUT,Im as ORIGIN_GROUP_ALLOWED_METHODS,jI as ORIGIN_GROUP_ID_SUFFIX,bm as ORIGIN_GROUP_SELECTION_CRITERIA,Ic as OpenSearchClient,Et as OptimisticConcurrencyError,Xm as OrganizationManager,Ug as PAGES_MAX_FILE_BYTES,IS as PHP_DEFAULT_EXCLUDES,uS as PHP_LAYER_EXTENSIONS,Tp as PROJECT_LABEL,pt as PROXIABLE_RECORD_TYPES,D as ParameterStore,tf as PerformanceManager,de as Permissions,bc as PersonalizeClient,et as Phone,Ef as PhoneAdvanced,Pm as PhoneHandlers,Ha as PlacementService,Qa as PlacementStore,Hn as PollyClient,he as PorkbunProvider,bn as PreDeployScanner,Il as PreviewEnvironmentManager,Wr as PreviewEnvironmentService,We as PreviewEnvironmentStore,bl as PreviewNotificationService,Ly as ProgressBar,Pl as ProgressiveDeploymentManager,sa as ProtectionControlStore,ty as Pseudo,J as Queue,_i as QueueCancellationError,Df as QueueManagementManager,_I as QueuePresets,So as QueueTimeoutError,Fn as R2ApiError,Nn as R2NotEnabledError,ci as R2Provider,rp as R2_NOT_ENABLED_ERROR_CODE,Wl as RATE_LIMIT_KEY_SEPARATOR,ne as RDSClient,qy as RECOMMENDED_ACCOUNT_STRUCTURES,OC as RECOMMENDED_SCPS,Kf as RELEASE_QUEUE_KINDS,Uy as REPL,Hy as REPLCommandBuilder,Qy as REPLContext,Rp as ROLE_LABEL,Dy as RateLimiter,LI as RealtimePresets,am as RecordingSpendTransport,rs as RecursionGuard,kt as Redirects,Km as RegionPairManager,Va as RegionService,Ga as RegionStore,Ye as Registry,Qt as RekognitionClient,Bt as ReleaseService,ma as ReleaseStore,lh as RemoteBuildService,Nl as ReplicaManager,Qf as ResourceManagementManager,ae as RetryableOperationError,b as Route53Client,yc as Route53DomainsClient,ie as Route53Provider,hf as Route53ResolverManager,_l as Route53RoutingManager,ve as RuntimeOperationService,Ta as RuntimeStreamRegistry,Za as S3BackupDestinationAdapter,o as S3Client,V as S3Error,bu as SECRET_PATTERNS,im as SENSITIVITY_THRESHOLDS,gt as SESClient,X as SMS,lt as SNSClient,pm as SPEND_CYCLE_SECONDS,qd as SPEND_GATE_SETTING,JA as SPEND_LEASE_SETTING,pe as SQSClient,ke as SSH_BOOTSTRAP_VERSION,mi as SSH_PREFLIGHT_SCRIPT,Be as SSMClient,Am as STATE_DIR_ENV_VAR,eo as STATIC_SITE_ZONE_SETTINGS,ll as STORAGE_FAILOVER_METADATA_KEY,Te as STSClient,Gn as SchedulerClient,lr as Search,Cn as SecretFindingScanner,Ji as Secrets,Bl as SecretsManager,re as SecretsManagerClient,nf as SecretsRotationManager,E as Security,pr as SecurityHubManager,In as SecurityPostureStore,xt as SecurityScannerRunner,of as SecurityScanningManager,Sf as SenderReputationManager,ah as ServerCronJobAdapter,xa as ServerDataAdapter,Eo as ServerPathVolumeDriver,Ol as ServiceMeshManager,gl as Sftp,Bo as SignalSource,vf as SmsAdvanced,Gt as SmsClient,km as SmsHandlers,wc as SmsVoiceClient,fa as SourceConnectionStore,hr as SourceProviderError,jd as SpendCapError,tn as SpendGate,um as SpendLoopLease,$o as SpendNotificationRouter,gm as SpendRunner,or as SpendService,$i as SpendStore,My as Spinner,Ur as SshDriver,Tn as SshFleetDriver,Wm as StackDependencyManager,KI as StacksIntegration,Mf as StaticSiteManager,xe as Storage,jl as StorageAdvancedManager,Vn as SupportClient,mr as SyntheticsManager,Uu as SystemFleetSshTransport,yt as SystemSshTransport,va as SystemdDiscoveryAdapter,Jo as TRACE_HEADER,Fy as TaskList,wt as TelemetryStore,ol as TemplateBuilder,Al as TemplateCache,Ht as TextractClient,Mn as TranscribeClient,Er as TranslateClient,mh as TransportDisasterRecoveryDriver,ph as TransportPlatformMaintenanceDriver,As as TransportRemoteBuildDriver,ba as TrivyImageScanner,pa as TsCloudApiError,uu as TsCloudClient,WA as URGENT_SPEND_EVENTS,em as USER_VISIBLE_ACTIONS,qa as UnavailableRegionalDriver,Ae as UnifiedDnsValidator,ho as UnsupportedSchemaVersionError,Lm as ValidationError,wr as VoiceClient,Co as VolumeService,nr as VolumeStore,qc as WORKER_MODULE_TYPE,ui as WorkersApiError,Xs as WorkersPermissionError,Wa as WorkersProvider,oy as Workflow,Ym as XRayManager,eS as abTestManager,gu as activateImmutableRelease,Eg as addDns01ChallengeRecord,Rn as addSiteToCloudConfig,_t as ageSeconds,Od as aggregateDeltas,Vp as allocateSitePorts,Dm as amazonLinuxImageId,sy as amazonLinuxImageParameter,VI as analyzeStackDiff,Ui as anomalyOptionsForSignal,oa as applyControlsToDdos,eu as applyControlsToRateLimits,Hs as applyDeclaredZoneSettings,li as applyHetznerVolumes,on as applyMitigationFactor,dA as applyPlan,js as applyZoneMigration,Ll as artifactKey,Rt as assertOriginGroupMethods,ds as assertReleaseStrategy,qA as assertSpendAllows,mA as attachConflicts,fA as attachIsViable,pA as attachPreconditions,wu as attachProvenanceToRelease,Ca as attachSbomToRelease,vu as attachVulnerabilitySummary,jf as authEncryptionKeyFile,x as authorizeOrganization,sh as authorizeRuntimePath,lC as autocomplete,Ky as awsConfigManager,gg as backupCredentialStatus,jy as backupManager,_b as batch,TE as batchProcessingManager,ua as beginOidcAuthorization,Yy as blueGreenManager,SE as bounceComplaintHandler,vt as budgetWindow,fc as buildAndPushServerlessImage,DE as buildBunRuntimeLayerZip,bA as buildCertificatePackScript,yA as buildCertificateStateScript,CA as buildCertificateUnpackScript,ml as buildCloudFormationTemplate,Yc as buildCloudInitFirstBoot,vd as buildComposeLogsCommand,xI as buildComposeRuntimeCommand,OI as buildComposeScaleCommand,Td as buildComposeShellCommand,ei as buildComputeStorageInstallScript,_r as buildComputeStorageSiteScript,Qp as buildDrainSourceScript,eA as buildDrainedSiteScanScript,ul as buildFailoverReplicaPolicyStatement,Ir as buildFunctionEnv,Up as buildHealthGateScript,ri as buildHostCleanupDeployScript,Zs as buildHostCleanupInstallScript,ti as buildHostCleanupScript,Bi as buildHostSitePortsScript,Ki as buildMailEnv,oo as buildManagementDashboardArtifact,KS as buildMediaCdnPlan,Bg as buildMtaStsPolicy,$h as buildMtaStsServer,RE as buildNodeRuntimeLayerZip,lE as buildOptimizationManager,dl as buildOriginGroup,dn as buildOriginGroups,Pc as buildOriginGuardRule,xp as buildPauseWorkersScript,BE as buildPhpRuntimeLayerZip,Rm as buildReplicationConfiguration,wm as buildReplicationRole,$p as buildRestoreScript,B as buildRpxConfig,Ne as buildRpxFragmentRefreshScript,uA as buildSetHostnameScript,ii as buildSiteDeployScript,Lp as buildSnapshotScript,Hp as buildSourceStateScript,ai as buildSshArgs,gi as buildSshBootstrapScript,Dc as buildStaticSiteCacheRules,si as buildStaticSiteDeployScript,Mp as buildTargetStateScript,lp as buildUploadForm,Op as buildWorkersStateScript,Zc as bundleWorker,Du as bytes,ip as cacheRuleParameters,Zy as canaryManager,wn as canonicalJson,Ot as capabilities,Sr as capacity,Vb as categorizeChanges,aE as certificateManager,IA as certificatesMatch,Tb as checkIAMPermissions,xf as checkInvocation,Rb as checkServiceQuotas,Py as chunk,dR as cleanupDns01Challenge,RS as clearSigningKeyCache,Aa as cloneSourceBinding,ky as cloudConfigSchema,sp as cloudDrivers,Wy as cloudTrailManager,gd as collectAssets,ea as collectPhpAppEntries,Pg as collectServerDnsDomains,Kp as completeComposeVolumeDeletion,ga as completeOidcAuthorization,pb as composePresets,yo as composeProjectName,Ml as composeServerlessAppTemplate,YA as compositeSpendTransport,Ft as compressBackup,OS as config,Rc as configOrigins,$u as connectionGuidance,oS as containerRegistryManager,wA as controlPlaneDatabaseFile,Ad as controlPlaneMigrations,tb as createApiBackendPreset,Ia as createApiV1Handler,GS as createAsgBuildDriver,pg as createBackupQueueHandlers,SS as createCliHandler,F as createCloudDriver,Xu as createCloudFrontPolicy,bb as createCredentialProvider,ub as createDashboardSite,ob as createDataPipelinePreset,Mu as createDataServiceQueueHandlers,wd as createDeploymentQueueHandlers,N as createDnsProvider,HS as createEcsBuildDriver,zd as createEnforcementHandlers,$m as createError,fl as createExistingStaticFullStackPreset,Qu as createFleetQueueHandlers,eb as createFullStackAppPreset,Ws as createGoDaddyValidator,NE as createHandlers,AS as createHttpHandler,nb as createJamstackPreset,Lu as createJobQueueHandlers,db as createLaravelPreset,ab as createMLApiPreset,Ku as createMaintenanceQueueHandlers,VS as createMediaAccessToken,ib as createMicroservicesPreset,Yb as createMockAWS,XI as createNodeJsServerPreset,YI as createNodeJsServerlessPreset,Os as createObjectStorageClient,Ks as createPorkbunValidator,mb as createPreset,ta as createPresignedUrl,CS as createPresignedUrlAsync,yS as createQueueHandler,sb as createRealtimeAppPreset,Gu as createRegionQueueHandlers,Tu as createReleaseProvenance,mu as createReleaseQueueHandlers,US as createRemoteBuildQueueHandlers,Js as createRoute53Validator,ih as createRuntimeAdapters,Iy as createS3Client,QS as createServerBuildDriver,lb as createServerlessLaravelPreset,ZI as createServerlessNodePreset,Rg as createSmsInfrastructure,ot as createSourceAdapter,JI as createStaticSitePreset,cb as createTraditionalWebAppPreset,Rd as createVolumeQueueHandlers,rb as createWordPressPreset,rt as createZip,yC as crossRegionReferenceManager,xn as dashboardActions,so as dashboardCredentialsFile,vn as dataServiceCapabilities,sE as databaseUserManager,ru as decodeBase32,Fe as decompressBackup,vh as decryptBackup,aa as defaultConfig,Um as defaultLocalConfig,Xl as defaultRateLimitRules,kr as delegateZone,Us as delegateZoneFromConfig,cg as deleteFailoverReplicaBuckets,pc as deleteStaticSite,sd as deployAllComputeSites,Ja as deployServerlessApp,dg as deploySite,ao as deploySiteRelease,Rs as deployStaticSite,mc as deployStaticSiteFull,On as deployStaticSiteWithExternalDns,_n as deployStaticSiteWithExternalDnsFull,Zh as deployToFly,sl as deploymentCoexistenceError,uy as deriveManagementDashboardPort,Qs as describeDelegation,Zl as describePosture,Gs as describeZoneSettings,oh as desiredJobProviderState,nm as detectAnomalies,ym as detectDeploymentTargets,kc as detectDnsProvider,Hd as detectLatestAnomaly,Eb as detectMisconfigurations,zl as detectServiceRegion,Cd as diffCompose,Qb as diffTemplates,ha as discoverGitRefs,la as discoverOidcProvider,Pu as discoverRuntimeInventory,vE as dlqMonitoringManager,Nc as dnsProviders,AE as dnssecManager,th as dockerWorkloads,ys as documentDigest,Gc as domainStatus,zy as drManager,qe as driverStatePath,ku as ecsWorkloads,rr as effectiveCapabilities,IE as emailAnalyticsManager,CE as emailTemplateManager,os as encodeBase32,Eh as encryptBackup,Ru as ensureDefaultSecurityPolicies,sg as ensureFailoverReplicaBuckets,bi as ensureFirewall,Ti as ensureManagementDashboard,Ci as ensureServer,Ii as ensureSshKey,oe as escapeSecLang,Ld as evaluateBudget,hi as evaluatePreflight,Lo as evaluateTelemetryAlertRules,_u as eventBridgeScheduleInput,hS as eventToRequest,HA as ewma,bd as exportCompose,Vs as exportRoute53Zone,Om as extendPreset,EE as fifoQueueManager,Ob as findChangedFiles,Jp as findMapping,Wp as findPriceEntry,qh as flyDeployOptions,Xc as flyIpType,yp as flyMachineConfig,FC as formatAccountStructure,hA as formatAttachPlan,rC as formatBytes,nn as formatCents,qI as formatDiff,rA as formatDrainedSiteRefusal,nC as formatDuration,gC as formatFlagSuggestions,fC as formatHistory,hC as formatHistoryStats,oA as formatInventory,sC as formatKeyValue,iC as formatList,cA as formatPlan,yi as formatPreflightFindings,tC as formatProgressBar,Vy as formatRegion,kC as formatRegionList,Xf as formatScanResults,oC as formatSuggestion,Zb as formatTable,Zr as formatTimeToExhaustion,eC as formatTree,hy as fromEC2Metadata,Ay as fromECSMetadata,my as fromEnvironment,fy as fromSharedCredentials,yy as fromWebIdentity,Ql as functionFingerprint,po as gatewayHostnames,Ul as generateAppImageDockerfile,ZC as generateApprovalConfig,Pf as generateBootstrap,xy as generateCleanupWorkflow,Oy as generateCostReportWorkflow,$C as generateCrossAccountRoleCF,Cu as generateCycloneDxSbom,JC as generateDeploymentConfig,qC as generateDeploymentPipeline,UC as generateDeploymentWorkflow,gc as generateExternalDnsStaticSiteTemplate,lR as generateHttpsServerCode,Eu as generateImageSbom,cR as generateLetsEncryptUserData,t as generateLogicalId,WC as generateManualPipeline,VC as generateMatrixWorkflow,XC as generateMultiEnvConfig,jC as generateMultiEnvPipeline,QC as generateMultiEnvWorkflow,HC as generatePRPreviewWorkflow,eE as generateParallelConfig,Lf as generatePhpFpmConfig,kf as generatePhpLayerDockerfile,zC as generatePreviewPipeline,By as generatePreviewWorkflow,r as generateResourceName,YC as generateScheduledConfig,KC as generateScheduledPipeline,GC as generateScheduledWorkflow,ws as generateStaticSiteTemplate,M as generateUbuntuAppCloudInit,_m as getAccountId,CC as getAllRegions,RC as getClosestRegion,pC as getCommandUsage,RA as getComposeTemplate,Gf as getConfig,cC as getContextualHelp,Yi as getCredentials,qb as getDeploymentStrategy,jb as getDiffStats,Hb as getDiffSummary,vy as getErrorDetails,Sl as getLocalConfig,Jb as getLocalCredentials,Wb as getLocalEndpoint,Xb as getLocalEnvVars,Db as getQuotaUsageSummary,LC as getRecommendedStructure,Zi as getRegion,NC as getRegionStats,vC as getRegionsByCompliance,EC as getRegionsByLocation,TC as getRegionsByPricingTier,Ty as getRequiredPermissions,DS as getSigningKeyCacheSize,wg as getSmsInfrastructureStatus,$I as getTimestamp,ra as globMatches,co as globToRegex,SC as globalResourceManager,Mi as governingLimitCents,og as grantFailoverReplicaAccess,Jy as guardDutyManager,Mo as handleSpendRequest,go as hasAutoWwwVariant,ur as hasManagementDashboardSite,hd as hasProxyUpstream,kb as hashBuffer,Nb as hashDirectory,Mm as hashFile,Bb as hashManifest,Fm as hashString,OE as healthCheckManager,Jn as hostAcceptsIpv6,Vt as hostCondition,ca as hotp,Yr as hourBucket,QA as hourBucketsBetween,dE as imageScanningManager,bs as infraEnvFromOutputs,Gl as inspectInvocation,mS as installRecursionFetch,Ps as invalidateCache,Bf as invocationContext,iy as isArmInstanceType,aC as isLikelyTypo,Yn as isLocalDatabase,Kb as isLocalDevelopment,gr as isManagementDashboardSiteName,Dr as isNameserverRegistrar,PS as isNodeCryptoAvailable,Qd as isOperationAllowed,_o as isQuietHours,Qo as isS3RestEndpoint,Ri as isSafePattern,nl as isStateDirConfigured,il as isStatePath,sn as isValidCidr,wC as isValidRegion,Li as isValidTimeZone,kS as isWebCryptoAvailable,Pr as isZoneHost,En as jobProviderCapability,xs as keyMatchesFilters,pE as lambdaConcurrencyManager,hE as lambdaDLQManager,mE as lambdaDestinationsManager,uE as lambdaLayersManager,fE as lambdaVPCManager,gE as lambdaVersionsManager,Nu as lambdaWorkloads,Vl as laravelServerlessEnvDefaults,Kr as listComposeTemplates,us as listSourceReferences,tu as loadCloudConfig,ar as loadTelemetryPolicy,rS as logsManager,Gd as lookbackHoursForSignal,ey as mailEnabled,Xe as mailFirewallPorts,cn as mailWebmailSites,gh as maintenanceWindowOpen,Hf as makeAWSRequest,vS as makeAWSRequestAsync,ES as makeAWSRequestOnce,op as managedRuleInSync,xm as managementDashboardSiteName,Vu as manifestDigest,hn as matchTotpCounter,jS as mediaObjectHeaders,Po as median,tm as medianAbsoluteDeviation,$d as mergeDecisions,un as mergeInfrastructure,FA as mergePriceBooks,xd as meterTelemetry,rE as metricsManager,bg as migrateObjectStorage,nE as migrationManager,BC as multiAccountManager,AC as multiRegionManager,pR as needsRenewal,_E as networkSecurityManager,Lt as nextScheduleRuns,De as normalizePublicIpv6,Le as normalizeRuntimeStatus,at as normalizeScheduleExpression,Wf as normalizeSourceEvent,Ve as normalizeSshPublicKey,cm as normalizeTelemetryPolicy,Ni as occupiedHostPorts,Sa as openApiDocument,xo as optionsForSignal,xC as organizationManager,ql as packagePhpApp,gn as packageServerlessApp,dd as pagesAssetHash,jg as pagesDnsRecord,yl as parallel,Lb as parallelMap,$b as parallelWithRetry,SA as parseCertificateState,Hl as parseChain,zr as parseCompose,NI as parseComposeCatalog,eh as parseDockerInspect,hg as parseDotenv,tA as parseDrainedSites,xi as parseHostSiteFragments,wS as parseJSONResponse,fi as parsePreflightFacts,Gp as parseSourceDrained,rh as parseSystemdRecords,Fp as parseTargetReady,fd as parseUpstreamPort,_p as parseWorkersPaused,TS as parseXMLResponse,Vi as pathTemplate,pd as pendingSteps,Do as percentOfLimit,iE as performanceManager,Fl as phpLayerBuildStage,gS as phpLayerPackages,mn as phpRuntimeLayerAssets,BI as planComposeTemplateUpgrade,Md as planEnforcement,di as planHetznerVolumes,Np as planIsDestructive,hm as planMitigation,lA as planServerRename,EA as planSiteMove,qs as planZoneMigration,zt as policyTag,Ai as preflightFailed,Ny as previewManager,_y as previewNotifications,$t as previewSchedule,UA as previousBudgetWindow,To as priceUsage,$A as priceUsageLines,iA as probeHostRoutes,Hc as probeOriginTls,Ub as processInChunks,Su as processSourceWebhook,ms as productionChangeReview,tS as progressiveDeploymentManager,_d as projectSpend,Xo as propagationHeaders,hc as providerEndpoint,qu as publicKeyFingerprint,zn as qualifyName,wE as queueManagementManager,xb as quickHash,np as r2Endpoint,Yg as r2S3Credentials,Jl as rateLimitHeaders,is as rateLimitKey,je as readDriverState,sA as reconcile,Ng as reconcileAddressRecords,Vg as reconcileCloudflareCdn,Fh as reconcileCloudflareWorkers,Fs as reconcileDeclaredRecords,FS as reconcileJobObservation,fh as reconcileR2Buckets,Sn as reconcileSourceWebhook,ps as recordDashboardHostPosture,LS as recordPreDeploySecretScan,$S as recordSkippedSecretScan,Yo as recursionBlockedResponse,$e as redactRuntimeConfig,Jd as redactTelemetryText,Gi as redactTelemetryValue,Pn as redeployServerlessApp,IC as regionPairManager,yn as releaseStrategyCapabilities,zf as releaseTrafficPlan,wi as reloadRpxGateway,Bs as remapKey,kg as removeAddressRecords,Og as removeDns01ChallengeRecord,Dn as removeSiteFromCloudConfig,Iu as removeSourceWebhook,Bc as removeStaleServerAddressRecords,Ed as renderComposeTemplate,zi as renderDdosInstallScript,el as renderNftablesRuleset,fs as renderServerCron,Zd as renderSysctlFile,ad as renderWafConfig,Di as renderWafInstallScript,od as renewRpxCertificates,iS as replicaManager,ZA as requestHash,Gb as requiresReplacement,PE as resetRecursionRuntime,kE as resolveApp,g as resolveAppDatabase,gA as resolveAttachTarget,st as resolveAuthEncryptionKey,be as resolveCloudProvider,Hg as resolveCloudflareCdnPlan,Zn as resolveComputeVolumes,qo as resolveCredentials,Ts as resolveDashboardAction,id as resolveDashboardAuth,gy as resolveDashboardDomain,py as resolveDashboardDomains,Ms as resolveDeclaredRecords,GI as resolveDeployBucketName,K as resolveDeploymentMode,ni as resolveExecStart,Uo as resolveFailoverStatusCodes,Qc as resolveHetznerApiToken,$r as resolveHostCleanupConfig,w as resolveMailProxy,C as resolveMailService,gb as resolveManagementDashboardSite,Xi as resolveManagementDashboardSites,Ac as resolveObjectStorage,ce as resolveOriginConnection,aA as resolvePlan,p as resolveProjectStackName,jr as resolveProxyUpstreams,$l as resolveQueueNames,PA as resolveQueuedDeploymentCommand,fr as resolveQueues,pS as resolveRecursionConfig,Sy as resolveRegion,ge as resolveRuntimeInventory,cr as resolveServerlessAppStackName,al as resolveServerlessArtifactBucketName,Wi as resolveServerlessAssetBucketName,ts as resolveServerlessRuntime,QI as resolveSiteBucketName,fo as resolveSiteDeployTarget,d as resolveSiteKind,UI as resolveSiteResourceName,FI as resolveSiteStackName,pi as resolveSshSettings,l as resolveStatePath,HI as resolveStorageBucketName,vm as resolveStorageFailover,Zt as resolveUiSource,ld as resolveZoneApex,LE as resourceManagementManager,_f as responseToResult,rm as robustZScore,tr as roleCapabilities,pu as rollbackImmutableRelease,kn as rollbackServerlessApp,MA as roundCents,yE as route53ResolverManager,cS as route53RoutingManager,sm as routeMatches,Dp as routesFromFragments,ns as ruleMatches,dS as runBuildHooks,Fd as runEnforcement,Zo as runPhpBuildHooks,ct as runRemoteCommand,Ee as runtimeId,Qe as s3OriginBucket,Tm as s3RegionalDomain,Ns as sameCorsRules,Ls as sameLifecycleRules,Kn as sameNameservers,vs as sanitizeCloudConfig,s as sanitizeControlPlaneValue,MI as sanitizeName,au as sanitizeOidcReturnPath,Kd as saveTelemetryPolicy,Jf as scanForSecrets,yd as scopeContains,Tt as scopeKey,$c as scpUpload,dC as searchCommands,Ao as searchControlPlane,sS as secretsManager,oE as secretsRotationManager,MS as secureContainerRelease,Xy as securityHubManager,cE as securityScanningManager,ue as securityScope,ag as seedFailoverReplicas,An as sendAuthenticationEmail,bE as senderReputationManager,Mb as sequence,Ag as serializeDotenv,Ei as serverPublicIpv4,aS as serviceMeshManager,tg as setAttachToInCloudConfig,br as setMaintenance,Ss as setSitePropertyInCloudConfig,rl as setStateDir,uR as setupDns01Challenge,Tc as setupSmsInfrastructure,zo as sha256,fS as sharedRecursionGuard,Nf as sharedRuntimeLoop,jp as shipsARelease,WS as signCloudFrontCookies,BS as signCloudFrontUrl,k as signRequest,Kl as signRequestAsync,No as signalDefinition,U as siteInstallBase,ki as siteMoveArchivePath,AA as siteMoveCertArchivePath,md as siteUnitGlob,lm as spendNotificationText,Fo as spendOpenApiPaths,Mr as sshExec,Se as sshExecOrThrow,bC as stackDependencyManager,uc as startLocalDashboardServer,XA as startSpendLoop,an as stateDir,Q as statePath,xE as staticSiteManager,bS as storageAdvancedManager,zI as storageFailoverReplicasFromTemplate,GA as streamFocusJsonl,Ud as strongestActiveAction,Vm as suggestCommand,uC as suggestFlags,wb as suggestIAMPolicy,Pb as suggestQuotaIncrease,PC as suggestRegionPairs,DC as suggestRegions,ls as syncSourceRepositories,Dd as synchronizeComposeVolumes,yg as synchronizeConfiguredConfiguration,wa as synchronizeConfiguredJobs,nS as syntheticsManager,Yd as sysctlHardening,nh as systemdWorkloads,KA as telemetryBucketLabel,qi as telemetryCursor,Wd as telemetryEstimatedMonthlyCost,zA as telemetryPercentile,dm as telemetryPolicyKey,wy as templateCache,Pp as tenantsOf,ya as testSourceConnection,Pd as tieredMicroCents,ap as toApiLifecycleRule,zc as toCloudflareZoneSettings,Oo as toFocusJsonl,Vd as toFocusRecords,nA as toInventoryServer,Vf as totp,da as totpUri,kp as unaccountedSites,Zf as unsupportedCapabilities,kA as unsupportedVolumeCapabilities,zu as updateCompatibility,Wu as updateSiteInCloudConfig,Ds as uploadStaticFiles,Xp as usageDeltaKey,sr as utcInstantOfLocal,MC as validateAccountStructure,zb as validateAgainstSchema,BA as validateAttachment,Ch as validateBackupDestination,mC as validateCommand,Cb as validateConfiguration,vb as validateCredentials,qp as validateDeploymentConfig,NA as validateMountPath,Dt as validateOriginGroups,Cg as validateResourceLimits,Bp as validateServerName,eg as validateTemplate,ug as validateTemplateSize,Oc as verifyAddressRecord,_S as verifyArtifactSignature,zS as verifyMediaAccessToken,qf as verifyTotp,ju as verifyUpdateSignature,zs as verifyZoneParity,bo as volumeCapabilities,Sp as wafEventTelemetry,Mc as waitForCloudInit,Yt as waitForSsh,Ar as webhookEndpoint,Sb as withCDN,yb as withCache,up as withContentHash,Ab as withDatabase,Of as withInvocation,fb as withMonitoring,Ib as withQueue,hb as withSecurity,Fb as withTimeout,dp as workerBindings,uo as workerContentHash,Xa as workerInSync,se as wrapCloudInitUserData,ht as writeDriverState,tE as xrayManager,Hu as zeroCapacity,VA as zeroFill,Nd as zoneOffsetMs,wo as zonedParts};
|
|
604
|
+
`}async function vg(u,p,h){let y=`_acme-challenge.${p}`;if(await Lg(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 Eg(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 Lg(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 uR(u){await vg(td(u),u.domain,u.challengeValue)}async function dR(u){await Eg(td(u),u.domain,u.challengeValue)}function pR(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 Fg,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 _g{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=Fg("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 Mg}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=Mg({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 Wg(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 Vg(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&&!Wg(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 zg=(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 Hg(u,p={}){let h=p.env??zg,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 Ug=26214400;var Gg=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:Kg(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 jg(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-gj4hj95p.js").then((m)=>NS(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(Gg.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 Kg(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 qg}from"node:crypto";var tp="https://api.cloudflare.com/client/v4",rp=10042,Zg=10006,Jg=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(Zg)||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(Jg)||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 Yg(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:qg("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 Xg="r2 cache",Qg=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function fh(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||!Qg.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=Sh(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} ${Xg}`,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 Sh(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 Ih,extname as Dh}from"node:path";import{createHash as Rh}from"node:crypto";var bh="https://api.cloudflare.com/client/v4",$n="TS_CLOUD_CONTENT_HASH",no="2025-09-01",Zc="application/javascript+module",Ah=10007,Th=[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(`${bh}/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(wh(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(Ah)||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)=>Th.includes(h.code)))return!0;return(u===401||u===403)&&p.length===0}function wh(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 Rh("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: ${kh(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:`${Ih(u,Dh(u))}.js`,content:y,type:Zc,size:new TextEncoder().encode(y).byteLength}}function kh(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 Oh,resolve as Nh}from"node:path";var xh="https://api.cloudflare.com/client/v4",Lh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function Fh(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||!Lh.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 _h(z,me,P);for(let bt of me.changes)h(`Workers: ${fe}: ${bt}`)}return y}async function _h(u,p,h){let y=u.name,R=Oh(u.entry)?u.entry:Nh(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 Mh(y,L,p,h)}async function Mh(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(`${xh}/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,Cy as AWSAPIError,n as AWSClient,A as AWSCloudFormationClient,I as AWSCloudFrontClient,Tl as AWSConfigManager,WI as AWS_PSEUDO_PARAMETERS,_e as AWS_REGIONS,_g 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,Yf as AwsIamCapabilityScanner,oc as AwsInfrastructureBackupSource,Na as AwsRdsDataAdapter,La as AwsRdsTransport,uh as AwsRegionalDriver,cc as AwsSecretsManagerConfigurationBackend,mm as AwsSpendTransport,dc as AwsSsmConfigurationBackend,Ts as BackupCoordinator,El as BackupManager,Za as BackupStore,Rf as BatchProcessingManager,Hn as BedrockClient,Qn as BedrockRuntimeClient,yu as BitbucketSourceAdapter,Dl as BlueGreenManager,Af as BounceComplaintHandler,cf 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,_C as COMMON_CROSS_ACCOUNT_ROLES,$n as CONTENT_HASH_BINDING,Ke as CONTROL_PLANE_SCHEMA_VERSION,Vo as Cache,rs as CanaryManager,sf as CertificateManager,xA as CloudBlockVolumeDriver,io as CloudDriverFactory,tt as CloudError,Nm as CloudFormationBuilder,A as CloudFormationClient,I as CloudFrontClient,wl as CloudTrailManager,we as CloudWatchLogsClient,dd as CloudflarePagesProvider,H as CloudflareProvider,Gy as CommandHistory,ee as Communication,Yr as ComposeApplicationService,sr as ComposeApplicationStore,Qt as ComprehendClient,a as Compute,fm 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,jm as CrossRegionReferenceManager,cy as DASHBOARD_ENTRY,dy as DASHBOARD_PORT_BASE,ly as DASHBOARD_PORT_SPAN,ay as DASHBOARD_STATE_DIR,sa as DEFAULT_ATTACK_MODE_HOURS,no as DEFAULT_COMPATIBILITY_DATE,Yd as DEFAULT_DDOS_THRESHOLDS,Sm 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,ny as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,jA as DEFAULT_TELEMETRY_POLICY,Yp as DEFAULT_THRESHOLDS,DA as DEPLOYMENT_QUEUE_KINDS,Wo as DEPTH_HEADER,tn as DETECTABLE_SIGNALS,_u as DIAGNOSTIC_PRESETS,wf as DLQMonitoringManager,W as DNS,ff as DNSSECManager,ys as DataServiceLifecycle,ka as DataServiceStore,lr as Database,rf as DatabaseUserManager,q as DebugLogger,ry as DependencyGraph,Z as Deployment,by 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,_A as ENFORCEMENT_ACTIONS,Qi as ENFORCEMENT_DESCRIPTIONS,O as ENFORCEMENT_SEVERITY,wp as ENVIRONMENT_LABEL,xu as EcsRuntimeAdapter,ia as EdgeRateLimiter,ut as ElastiCacheClient,f as Email,bf as EmailAdvanced,yf as EmailAnalyticsManager,jn as EmailClient,Cf as EmailHandlers,If as EmailTemplateManager,Fa as EncryptedDataSecretStore,Ey as ErrorCodes,wr as EventBridgeClient,ch as EventBridgeJobAdapter,lc as ExternalConfigurationBackend,Go as FAILOVER_REPLICA_POLICY_SID,Tf as FIFOQueueManager,Gh as FLY_MACHINES_API,om 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,zm as GlobalResourceManager,Ge as GoDaddyProvider,Rl as GuardDutyManager,Et as HOST_SITES_DIR,Ry as HashCache,Ff as HealthCheckManager,Je as HealthCheckRunner,Ur as HetznerClient,Pe as HetznerDriver,Re as IAMClient,Oc as IPV6_EXCLUDED_HOST_LABELS,af as ImageScanningManager,Ep as InfrastructureGenerator,Id as InvalidOperationTransitionError,kt as JobLoader,dh as JobProviderReconciler,Da as JobService,Pa as JobStore,Tr as KendraClient,$f as LARAVEL_SERVERLESS_BUILD_STEPS,T as LambdaClient,uf as LambdaConcurrencyManager,mf as LambdaDLQManager,gf as LambdaDestinationsManager,df as LambdaLayersManager,Ou as LambdaRuntimeAdapter,pf as LambdaVPCManager,lf as LambdaVersionsManager,xn as LocalEncryptedConfigurationBackend,nc as LogicalDatabaseBackupSource,Nl as LogsManager,lS as MANAGED_NODE_VERSIONS,id as MANAGEMENT_DASHBOARD_SITE,Bm as MANAGEMENT_DASHBOARD_SITE_PREFIX,as as MAX_CONTROL_HOURS,bd as MAX_CONTROL_PLANE_ERROR_BYTES,zp as MAX_CONTROL_PLANE_JSON_BYTES,To as METERS,OA as METER_KEYS,LA as MICRO_CENTS,Zp as MIN_PROJECTION_CONFIDENCE,Og as MTA_STS_PORT,Ka as MaintenanceService,za as MaintenanceStore,le as Messaging,Zm as MetricsManager,ef as MigrationManager,Qm as MockCloudFormation,Gm as MockDynamoDB,Hm as MockS3,qo as Monitoring,Jm as MultiAccountManager,qm as MultiRegionManager,$y as MultiStepProgress,S as Network,Uf as NetworkSecurityManager,Vi as NotificationRouter,Cm as ORIGIN_CONNECTION_ATTEMPTS,Em as ORIGIN_CONNECTION_TIMEOUT,Im as ORIGIN_GROUP_ALLOWED_METHODS,jI as ORIGIN_GROUP_ID_SUFFIX,bm as ORIGIN_GROUP_SELECTION_CRITERIA,bc as OpenSearchClient,vt as OptimisticConcurrencyError,Xm as OrganizationManager,Ug as PAGES_MAX_FILE_BYTES,IS as PHP_DEFAULT_EXCLUDES,uS as PHP_LAYER_EXTENSIONS,Tp as PROJECT_LABEL,pt as PROXIABLE_RECORD_TYPES,D as ParameterStore,tf as PerformanceManager,de as Permissions,Cc as PersonalizeClient,et as Phone,Ef as PhoneAdvanced,Pm 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,Ly as ProgressBar,kl as ProgressiveDeploymentManager,oa as ProtectionControlStore,ty as Pseudo,J as Queue,$i as QueueCancellationError,Df as QueueManagementManager,_I 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,qy as RECOMMENDED_ACCOUNT_STRUCTURES,OC as RECOMMENDED_SCPS,Kf as RELEASE_QUEUE_KINDS,Uy as REPL,Hy as REPLCommandBuilder,Qy as REPLContext,Rp as ROLE_LABEL,Dy as RateLimiter,LI as RealtimePresets,am as RecordingSpendTransport,is as RecursionGuard,Nt as Redirects,Km as RegionPairManager,qa as RegionService,Va as RegionStore,Ye as Registry,Ht as RekognitionClient,xt as ReleaseService,fa as ReleaseStore,lh as RemoteBuildService,Bl as ReplicaManager,Qf as ResourceManagementManager,ae as RetryableOperationError,b as Route53Client,Sc as Route53DomainsClient,ie as Route53Provider,hf as Route53ResolverManager,Ll as Route53RoutingManager,ve as RuntimeOperationService,wa as RuntimeStreamRegistry,ec as S3BackupDestinationAdapter,o as S3Client,V as S3Error,Cu as SECRET_PATTERNS,im as SENSITIVITY_THRESHOLDS,gt as SESClient,X as SMS,lt as SNSClient,pm as SPEND_CYCLE_SECONDS,jd as SPEND_GATE_SETTING,JA as SPEND_LEASE_SETTING,pe as SQSClient,ke as SSH_BOOTSTRAP_VERSION,hi as SSH_PREFLIGHT_SCRIPT,Be as SSMClient,Am 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,nf as SecretsRotationManager,E as Security,mr as SecurityHubManager,bn as SecurityPostureStore,Ot as SecurityScannerRunner,of as SecurityScanningManager,Sf as SenderReputationManager,ah as ServerCronJobAdapter,Oa as ServerDataAdapter,vo as ServerPathVolumeDriver,_l as ServiceMeshManager,pl as Sftp,xo as SignalSource,vf as SmsAdvanced,Vt as SmsClient,km as SmsHandlers,Rc as SmsVoiceClient,ha as SourceConnectionStore,Ar as SourceProviderError,zd as SpendCapError,rn as SpendGate,um as SpendLoopLease,Mo as SpendNotificationRouter,gm as SpendRunner,ar as SpendService,Fi as SpendStore,My as Spinner,Qr as SshDriver,wn as SshFleetDriver,Wm as StackDependencyManager,KI as StacksIntegration,Mf 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,Fy as TaskList,Rt as TelemetryStore,al as TemplateBuilder,yl as TemplateCache,Gt as TextractClient,Un as TranscribeClient,vr as TranslateClient,mh as TransportDisasterRecoveryDriver,ph as TransportPlatformMaintenanceDriver,Ss as TransportRemoteBuildDriver,Ca as TrivyImageScanner,ma as TsCloudApiError,gu as TsCloudClient,WA as URGENT_SPEND_EVENTS,em as USER_VISIBLE_ACTIONS,ja as UnavailableRegionalDriver,Ae as UnifiedDnsValidator,Ao as UnsupportedSchemaVersionError,Lm 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,oy as Workflow,Ym as XRayManager,eS as abTestManager,pu as activateImmutableRelease,vg as addDns01ChallengeRecord,Dn as addSiteToCloudConfig,Lt as ageSeconds,_d as aggregateDeltas,Vp as allocateSitePorts,Dm as amazonLinuxImageId,sy as amazonLinuxImageParameter,VI as analyzeStackDiff,Hi as anomalyOptionsForSignal,aa as applyControlsToDdos,tu as applyControlsToRateLimits,Vs as applyDeclaredZoneSettings,gi as applyHetznerVolumes,an as applyMitigationFactor,dA as applyPlan,Ks as applyZoneMigration,$l as artifactKey,Dt as assertOriginGroupMethods,us as assertReleaseStrategy,qA as assertSpendAllows,mA as attachConflicts,fA as attachIsViable,pA as attachPreconditions,Ru as attachProvenanceToRelease,Ea as attachSbomToRelease,Tu as attachVulnerabilitySummary,jf as authEncryptionKeyFile,x as authorizeOrganization,sh as authorizeRuntimePath,lC as autocomplete,Ky as awsConfigManager,pg as backupCredentialStatus,jy as backupManager,_b as batch,TE as batchProcessingManager,ga as beginOidcAuthorization,Yy as blueGreenManager,SE as bounceComplaintHandler,Tt as budgetWindow,hc as buildAndPushServerlessImage,DE as buildBunRuntimeLayerZip,bA as buildCertificatePackScript,yA as buildCertificateStateScript,CA as buildCertificateUnpackScript,fl as buildCloudFormationTemplate,Yc as buildCloudInitFirstBoot,Td as buildComposeLogsCommand,xI as buildComposeRuntimeCommand,OI as buildComposeScaleCommand,wd as buildComposeShellCommand,ti as buildComputeStorageInstallScript,Lr as buildComputeStorageSiteScript,Qp as buildDrainSourceScript,eA as buildDrainedSiteScanScript,gl as buildFailoverReplicaPolicyStatement,br as buildFunctionEnv,Up as buildHealthGateScript,ni as buildHostCleanupDeployScript,to as buildHostCleanupInstallScript,ri as buildHostCleanupScript,Oi as buildHostSitePortsScript,Ji as buildMailEnv,ao as buildManagementDashboardArtifact,KS as buildMediaCdnPlan,xg as buildMtaStsPolicy,$h as buildMtaStsServer,RE as buildNodeRuntimeLayerZip,lE as buildOptimizationManager,ll as buildOriginGroup,ln as buildOriginGroups,kc as buildOriginGuardRule,xp as buildPauseWorkersScript,BE as buildPhpRuntimeLayerZip,Rm as buildReplicationConfiguration,wm as buildReplicationRole,$p as buildRestoreScript,B as buildRpxConfig,Ne as buildRpxFragmentRefreshScript,uA as buildSetHostnameScript,si as buildSiteDeployScript,Lp as buildSnapshotScript,Hp as buildSourceStateScript,ci as buildSshArgs,mi as buildSshBootstrapScript,Pc as buildStaticSiteCacheRules,oi as buildStaticSiteDeployScript,Mp as buildTargetStateScript,lp as buildUploadForm,Op as buildWorkersStateScript,Jc as bundleWorker,Pu as bytes,ip as cacheRuleParameters,Zy as canaryManager,Rn as canonicalJson,_t as capabilities,Ir as capacity,Vb as categorizeChanges,aE as certificateManager,IA as certificatesMatch,Tb as checkIAMPermissions,xf as checkInvocation,Rb as checkServiceQuotas,Py as chunk,dR as cleanupDns01Challenge,RS as clearSigningKeyCache,ya as cloneSourceBinding,ky as cloudConfigSchema,op as cloudDrivers,Wy as cloudTrailManager,gd as collectAssets,ta as collectPhpAppEntries,kg as collectServerDnsDomains,Kp as completeComposeVolumeDeletion,pa as completeOidcAuthorization,pb as composePresets,So as composeProjectName,Fl as composeServerlessAppTemplate,YA as compositeSpendTransport,Ut as compressBackup,OS as config,Dc as configOrigins,Mu as connectionGuidance,oS as containerRegistryManager,wA as controlPlaneDatabaseFile,yd as controlPlaneMigrations,tb as createApiBackendPreset,ba as createApiV1Handler,GS as createAsgBuildDriver,mg as createBackupQueueHandlers,SS as createCliHandler,F as createCloudDriver,ed as createCloudFrontPolicy,bb as createCredentialProvider,ub as createDashboardSite,ob as createDataPipelinePreset,Fu as createDataServiceQueueHandlers,Rd as createDeploymentQueueHandlers,N as createDnsProvider,HS as createEcsBuildDriver,Kd as createEnforcementHandlers,$m as createError,hl as createExistingStaticFullStackPreset,Hu as createFleetQueueHandlers,eb as createFullStackAppPreset,Xs as createGoDaddyValidator,NE as createHandlers,AS as createHttpHandler,nb as createJamstackPreset,$u as createJobQueueHandlers,db as createLaravelPreset,ab as createMLApiPreset,Wu as createMaintenanceQueueHandlers,VS as createMediaAccessToken,ib as createMicroservicesPreset,Yb as createMockAWS,XI as createNodeJsServerPreset,YI as createNodeJsServerlessPreset,Ls as createObjectStorageClient,Js as createPorkbunValidator,mb as createPreset,ra as createPresignedUrl,CS as createPresignedUrlAsync,yS as createQueueHandler,sb as createRealtimeAppPreset,Vu as createRegionQueueHandlers,wu as createReleaseProvenance,fu as createReleaseQueueHandlers,US as createRemoteBuildQueueHandlers,Ys as createRoute53Validator,ih as createRuntimeAdapters,Iy as createS3Client,QS as createServerBuildDriver,lb as createServerlessLaravelPreset,ZI as createServerlessNodePreset,Dg as createSmsInfrastructure,ot as createSourceAdapter,JI as createStaticSitePreset,cb as createTraditionalWebAppPreset,Dd as createVolumeQueueHandlers,rb as createWordPressPreset,rt as createZip,yC as crossRegionReferenceManager,On as dashboardActions,oo as dashboardCredentialsFile,Tn as dataServiceCapabilities,sE as databaseUserManager,nu as decodeBase32,Fe as decompressBackup,vh as decryptBackup,ca as defaultConfig,Um 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,uy as deriveManagementDashboardPort,Gs as describeDelegation,eu as describePosture,qs as describeZoneSettings,oh as desiredJobProviderState,nm as detectAnomalies,ym as detectDeploymentTargets,Nc as detectDnsProvider,Gd as detectLatestAnomaly,Eb as detectMisconfigurations,Kl as detectServiceRegion,Ed as diffCompose,Qb as diffTemplates,Aa as discoverGitRefs,ua as discoverOidcProvider,ku as discoverRuntimeInventory,vE as dlqMonitoringManager,Bc as dnsProviders,AE as dnssecManager,th as dockerWorkloads,Is as documentDigest,jc as domainStatus,zy as drManager,qe as driverStatePath,Nu as ecsWorkloads,nr as effectiveCapabilities,IE as emailAnalyticsManager,CE as emailTemplateManager,cs as encodeBase32,Eh 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,hS as eventToRequest,HA as ewma,Cd as exportCompose,js as exportRoute53Zone,Om as extendPreset,EE as fifoQueueManager,Ob as findChangedFiles,Jp as findMapping,Wp as findPriceEntry,qh as flyDeployOptions,Qc as flyIpType,yp as flyMachineConfig,FC as formatAccountStructure,hA as formatAttachPlan,rC as formatBytes,sn as formatCents,qI as formatDiff,rA as formatDrainedSiteRefusal,nC as formatDuration,gC as formatFlagSuggestions,fC as formatHistory,hC as formatHistoryStats,oA as formatInventory,sC as formatKeyValue,iC as formatList,cA as formatPlan,Ii as formatPreflightFindings,tC as formatProgressBar,Vy as formatRegion,kC as formatRegionList,Xf as formatScanResults,oC as formatSuggestion,Zb as formatTable,en as formatTimeToExhaustion,eC as formatTree,hy as fromEC2Metadata,Ay as fromECSMetadata,my as fromEnvironment,fy as fromSharedCredentials,yy as fromWebIdentity,Hl as functionFingerprint,mo as gatewayHostnames,Ql as generateAppImageDockerfile,ZC as generateApprovalConfig,Pf as generateBootstrap,xy as generateCleanupWorkflow,Oy as generateCostReportWorkflow,$C as generateCrossAccountRoleCF,Eu as generateCycloneDxSbom,JC as generateDeploymentConfig,qC as generateDeploymentPipeline,UC as generateDeploymentWorkflow,pc as generateExternalDnsStaticSiteTemplate,lR as generateHttpsServerCode,vu as generateImageSbom,cR as generateLetsEncryptUserData,t as generateLogicalId,WC as generateManualPipeline,VC as generateMatrixWorkflow,XC as generateMultiEnvConfig,jC as generateMultiEnvPipeline,QC as generateMultiEnvWorkflow,HC as generatePRPreviewWorkflow,eE as generateParallelConfig,Lf as generatePhpFpmConfig,kf as generatePhpLayerDockerfile,zC as generatePreviewPipeline,By as generatePreviewWorkflow,r as generateResourceName,YC as generateScheduledConfig,KC as generateScheduledPipeline,GC as generateScheduledWorkflow,Ds as generateStaticSiteTemplate,M as generateUbuntuAppCloudInit,_m as getAccountId,CC as getAllRegions,RC as getClosestRegion,pC as getCommandUsage,RA as getComposeTemplate,Gf as getConfig,cC as getContextualHelp,es as getCredentials,qb as getDeploymentStrategy,jb as getDiffStats,Hb as getDiffSummary,vy as getErrorDetails,Il as getLocalConfig,Jb as getLocalCredentials,Wb as getLocalEndpoint,Xb as getLocalEnvVars,Db as getQuotaUsageSummary,LC as getRecommendedStructure,ts as getRegion,NC as getRegionStats,vC as getRegionsByCompliance,EC as getRegionsByLocation,TC as getRegionsByPricingTier,Ty as getRequiredPermissions,DS as getSigningKeyCacheSize,Rg as getSmsInfrastructureStatus,$I as getTimestamp,na as globMatches,lo as globToRegex,SC as globalResourceManager,Ui as governingLimitCents,ag as grantFailoverReplicaAccess,Jy as guardDutyManager,Fo as handleSpendRequest,po as hasAutoWwwVariant,gr as hasManagementDashboardSite,Ad as hasProxyUpstream,kb as hashBuffer,Nb as hashDirectory,Mm as hashFile,Bb as hashManifest,Fm as hashString,OE as healthCheckManager,Xn as hostAcceptsIpv6,qt as hostCondition,da as hotp,Zr as hourBucket,QA as hourBucketsBetween,dE as imageScanningManager,Es as infraEnvFromOutputs,Vl as inspectInvocation,mS as installRecursionFetch,Ns as invalidateCache,Bf as invocationContext,iy as isArmInstanceType,aC as isLikelyTypo,Zn as isLocalDatabase,Kb as isLocalDevelopment,pr as isManagementDashboardSiteName,Pr as isNameserverRegistrar,PS as isNodeCryptoAvailable,Hd as isOperationAllowed,Lo as isQuietHours,Ho as isS3RestEndpoint,Pi as isSafePattern,il as isStateDirConfigured,sl as isStatePath,on as isValidCidr,wC as isValidRegion,Mi as isValidTimeZone,kS as isWebCryptoAvailable,kr as isZoneHost,vn as jobProviderCapability,_s as keyMatchesFilters,pE as lambdaConcurrencyManager,hE as lambdaDLQManager,mE as lambdaDestinationsManager,uE as lambdaLayersManager,fE as lambdaVPCManager,gE as lambdaVersionsManager,Bu as lambdaWorkloads,ql as laravelServerlessEnvDefaults,Wr as listComposeTemplates,ps as listSourceReferences,ru as loadCloudConfig,cr as loadTelemetryPolicy,rS as logsManager,Vd as lookbackHoursForSignal,ey as mailEnabled,Xe as mailFirewallPorts,dn as mailWebmailSites,gh as maintenanceWindowOpen,Hf as makeAWSRequest,vS as makeAWSRequestAsync,ES as makeAWSRequestOnce,sp as managedRuleInSync,xm as managementDashboardSiteName,qu as manifestDigest,An as matchTotpCounter,jS as mediaObjectHeaders,ko as median,tm as medianAbsoluteDeviation,Md as mergeDecisions,gn as mergeInfrastructure,FA as mergePriceBooks,Od as meterTelemetry,rE as metricsManager,Cg as migrateObjectStorage,nE as migrationManager,BC as multiAccountManager,AC as multiRegionManager,pR as needsRenewal,_E as networkSecurityManager,$t as nextScheduleRuns,De as normalizePublicIpv6,Le as normalizeRuntimeStatus,at as normalizeScheduleExpression,Wf as normalizeSourceEvent,Ve as normalizeSshPublicKey,cm as normalizeTelemetryPolicy,xi as occupiedHostPorts,Ia as openApiDocument,Oo as optionsForSignal,xC as organizationManager,jl as packagePhpApp,pn as packageServerlessApp,pd as pagesAssetHash,jg as pagesDnsRecord,Sl as parallel,Lb as parallelMap,$b as parallelWithRetry,SA as parseCertificateState,Gl as parseChain,Kr as parseCompose,NI as parseComposeCatalog,eh as parseDockerInspect,Ag as parseDotenv,tA as parseDrainedSites,_i as parseHostSiteFragments,wS as parseJSONResponse,Ai as parsePreflightFacts,Gp as parseSourceDrained,rh as parseSystemdRecords,Fp as parseTargetReady,hd as parseUpstreamPort,_p as parseWorkersPaused,TS as parseXMLResponse,ji as pathTemplate,md as pendingSteps,Po as percentOfLimit,iE as performanceManager,Ul as phpLayerBuildStage,gS as phpLayerPackages,fn as phpRuntimeLayerAssets,BI as planComposeTemplateUpgrade,Fd as planEnforcement,ui as planHetznerVolumes,Np as planIsDestructive,hm as planMitigation,lA as planServerRename,EA as planSiteMove,zs as planZoneMigration,Kt as policyTag,Si as preflightFailed,Ny as previewManager,_y as previewNotifications,Mt as previewSchedule,UA as previousBudgetWindow,wo as priceUsage,$A as priceUsageLines,iA as probeHostRoutes,Uc as probeOriginTls,Ub as processInChunks,Iu as processSourceWebhook,hs as productionChangeReview,tS as progressiveDeploymentManager,Ld as projectSpend,Yo as propagationHeaders,Ac as providerEndpoint,ju as publicKeyFingerprint,Kn as qualifyName,wE as queueManagementManager,xb as quickHash,np as r2Endpoint,Yg as r2S3Credentials,Xl as rateLimitHeaders,os as rateLimitKey,je as readDriverState,sA as reconcile,Bg as reconcileAddressRecords,Vg as reconcileCloudflareCdn,Fh as reconcileCloudflareWorkers,Qs as reconcileDeclaredRecords,FS as reconcileJobObservation,fh as reconcileR2Buckets,In as reconcileSourceWebhook,fs as recordDashboardHostPosture,LS as recordPreDeploySecretScan,$S as recordSkippedSecretScan,Zo as recursionBlockedResponse,$e as redactRuntimeConfig,Xd as redactTelemetryText,qi as redactTelemetryValue,kn as redeployServerlessApp,IC as regionPairManager,Sn as releaseStrategyCapabilities,zf as releaseTrafficPlan,Di as reloadRpxGateway,Os as remapKey,Ng as removeAddressRecords,Eg 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,iS as replicaManager,ZA as requestHash,Gb as requiresReplacement,PE as resetRecursionRuntime,kE as resolveApp,g as resolveAppDatabase,gA as resolveAttachTarget,st as resolveAuthEncryptionKey,be as resolveCloudProvider,Hg as resolveCloudflareCdnPlan,ei as resolveComputeVolumes,jo as resolveCredentials,Rs as resolveDashboardAction,sd as resolveDashboardAuth,gy as resolveDashboardDomain,py as resolveDashboardDomains,Us as resolveDeclaredRecords,GI as resolveDeployBucketName,K as resolveDeploymentMode,ii as resolveExecStart,Qo as resolveFailoverStatusCodes,Hc as resolveHetznerApiToken,Mr as resolveHostCleanupConfig,w as resolveMailProxy,C as resolveMailService,gb as resolveManagementDashboardSite,Zi as resolveManagementDashboardSites,yc as resolveObjectStorage,ce as resolveOriginConnection,aA as resolvePlan,m as resolveProjectStackName,zr as resolveProxyUpstreams,Ml as resolveQueueNames,PA as resolveQueuedDeploymentCommand,hr as resolveQueues,pS as resolveRecursionConfig,Sy as resolveRegion,ge as resolveRuntimeInventory,dr as resolveServerlessAppStackName,cl as resolveServerlessArtifactBucketName,Xi as resolveServerlessAssetBucketName,ns as resolveServerlessRuntime,QI as resolveSiteBucketName,ho as resolveSiteDeployTarget,d as resolveSiteKind,UI as resolveSiteResourceName,FI as resolveSiteStackName,fi as resolveSshSettings,l as resolveStatePath,HI as resolveStorageBucketName,vm as resolveStorageFailover,er as resolveUiSource,ud as resolveZoneApex,LE as resourceManagementManager,_f as responseToResult,rm as robustZScore,rr as roleCapabilities,mu as rollbackImmutableRelease,Nn as rollbackServerlessApp,MA as roundCents,yE as route53ResolverManager,cS as route53RoutingManager,sm as routeMatches,Dp as routesFromFragments,ss as ruleMatches,dS as runBuildHooks,Ud as runEnforcement,ea as runPhpBuildHooks,ct as runRemoteCommand,Ee as runtimeId,Qe as s3OriginBucket,Tm as s3RegionalDomain,xs as sameCorsRules,Fs as sameLifecycleRules,Wn as sameNameservers,ws as sanitizeCloudConfig,s as sanitizeControlPlaneValue,MI as sanitizeName,cu as sanitizeOidcReturnPath,Wd as saveTelemetryPolicy,Jf as scanForSecrets,Sd as scopeContains,wt as scopeKey,Mc as scpUpload,dC as searchCommands,yo as searchControlPlane,sS as secretsManager,oE as secretsRotationManager,MS as secureContainerRelease,Xy as securityHubManager,cE as securityScanningManager,ue as securityScope,cg as seedFailoverReplicas,yn as sendAuthenticationEmail,bE as senderReputationManager,Mb as sequence,yg as serializeDotenv,Ti as serverPublicIpv4,aS as serviceMeshManager,rg as setAttachToInCloudConfig,Cr as setMaintenance,bs as setSitePropertyInCloudConfig,nl as setStateDir,uR as setupDns01Challenge,wc as setupSmsInfrastructure,Ko as sha256,fS as sharedRecursionGuard,Nf as sharedRuntimeLoop,jp as shipsARelease,WS as signCloudFrontCookies,BS as signCloudFrontUrl,k as signRequest,Wl as signRequestAsync,Bo as signalDefinition,U as siteInstallBase,Bi as siteMoveArchivePath,AA as siteMoveCertArchivePath,fd as siteUnitGlob,lm as spendNotificationText,Uo as spendOpenApiPaths,Fr as sshExec,Se as sshExecOrThrow,bC as stackDependencyManager,gc as startLocalDashboardServer,XA as startSpendLoop,cn as stateDir,Q as statePath,xE as staticSiteManager,bS as storageAdvancedManager,zI as storageFailoverReplicasFromTemplate,GA as streamFocusJsonl,Qd as strongestActiveAction,Vm as suggestCommand,uC as suggestFlags,wb as suggestIAMPolicy,Pb as suggestQuotaIncrease,PC as suggestRegionPairs,DC as suggestRegions,gs as syncSourceRepositories,Pd as synchronizeComposeVolumes,Sg as synchronizeConfiguredConfiguration,Ra as synchronizeConfiguredJobs,nS as syntheticsManager,Zd as sysctlHardening,nh as systemdWorkloads,KA as telemetryBucketLabel,zi as telemetryCursor,Jd as telemetryEstimatedMonthlyCost,zA as telemetryPercentile,dm as telemetryPolicyKey,wy as templateCache,Pp as tenantsOf,Sa as testSourceConnection,kd as tieredMicroCents,ap as toApiLifecycleRule,zc as toCloudflareZoneSettings,_o as toFocusJsonl,qd as toFocusRecords,nA as toInventoryServer,Vf as totp,la as totpUri,kp as unaccountedSites,Zf as unsupportedCapabilities,kA as unsupportedVolumeCapabilities,Ku as updateCompatibility,Ju as updateSiteInCloudConfig,ks as uploadStaticFiles,Xp as usageDeltaKey,or as utcInstantOfLocal,MC as validateAccountStructure,zb as validateAgainstSchema,BA as validateAttachment,Ch as validateBackupDestination,mC as validateCommand,Cb as validateConfiguration,vb as validateCredentials,qp as validateDeploymentConfig,NA as validateMountPath,Pt as validateOriginGroups,gg as validateResourceLimits,Bp as validateServerName,eg as validateTemplate,ug as validateTemplateSize,_c as verifyAddressRecord,_S as verifyArtifactSignature,zS as verifyMediaAccessToken,qf as verifyTotp,zu as verifyUpdateSignature,Ws as verifyZoneParity,Co as volumeCapabilities,Sp as wafEventTelemetry,Fc as waitForCloudInit,ft as waitForSsh,yr as webhookEndpoint,Sb as withCDN,yb as withCache,up as withContentHash,Ab as withDatabase,Of as withInvocation,fb as withMonitoring,Ib as withQueue,hb as withSecurity,Fb as withTimeout,dp as workerBindings,so as workerContentHash,Ja as workerInSync,se as wrapCloudInitUserData,At as writeDriverState,tE as xrayManager,Gu as zeroCapacity,VA as zeroFill,Bd as zoneOffsetMs,Ro as zonedParts};
|