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