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