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