@stacksjs/ts-cloud 0.16.93 → 0.16.96

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/{chunk-v72zwetk.js → chunk-18c0bsep.js} +132 -121
  3. package/dist/bin/{chunk-00arzt4m.js → chunk-s2hqcbeq.js} +1 -1
  4. package/dist/bin/{chunk-eb591jvz.js → chunk-zbxfpe5p.js} +1 -1
  5. package/dist/bin/cli.js +5 -5
  6. package/dist/bin/dashboard-server.js +1 -1
  7. package/dist/{chunk-zwayp7fz.js → chunk-1kagq9vp.js} +2 -2
  8. package/dist/{chunk-72p2tdpe.js → chunk-316cbffs.js} +105 -105
  9. package/dist/{chunk-sjfc9my3.js → chunk-3t5a5gr2.js} +5 -5
  10. package/dist/{chunk-1087xz1v.js → chunk-4afz3x6w.js} +14 -14
  11. package/dist/{chunk-fne338jr.js → chunk-4bysqvjh.js} +7 -7
  12. package/dist/{chunk-hcbrgyfz.js → chunk-7y1pknej.js} +2 -2
  13. package/dist/{chunk-q7yf28cc.js → chunk-7zjf2493.js} +1 -1
  14. package/dist/chunk-92tv9xar.js +1 -0
  15. package/dist/{chunk-a77mhcs7.js → chunk-93xknw91.js} +3 -3
  16. package/dist/{chunk-xs9m0v31.js → chunk-bxq80y73.js} +4 -4
  17. package/dist/{chunk-1psh3mhm.js → chunk-byt4re1c.js} +1 -1
  18. package/dist/chunk-bzdfx427.js +138 -0
  19. package/dist/{chunk-by7hejhg.js → chunk-cjqw4ns4.js} +2 -2
  20. package/dist/chunk-cq34675f.js +1 -0
  21. package/dist/{chunk-cjm5j58y.js → chunk-jcxm737x.js} +146 -146
  22. package/dist/chunk-jntyd5zv.js +2 -0
  23. package/dist/{chunk-zy3kr4s2.js → chunk-kken64a9.js} +3 -3
  24. package/dist/chunk-m580e9rp.js +1 -0
  25. package/dist/{chunk-fe6m7wb0.js → chunk-n6tgqd7d.js} +19 -19
  26. package/dist/{chunk-tpvmpmxj.js → chunk-p1agrrnq.js} +2 -2
  27. package/dist/chunk-q1a389m2.js +1 -0
  28. package/dist/{chunk-qra9k26f.js → chunk-r2gtxb7n.js} +1 -1
  29. package/dist/{chunk-h6kptkce.js → chunk-sp0ne2ax.js} +2 -2
  30. package/dist/{chunk-c6kb5c5v.js → chunk-stqg97mh.js} +4 -4
  31. package/dist/{chunk-kcem6dzk.js → chunk-tes38y8x.js} +2 -2
  32. package/dist/{chunk-7d9ek8rc.js → chunk-vaczx33v.js} +4 -4
  33. package/dist/chunk-vpce5x9x.js +1 -0
  34. package/dist/chunk-w2gsveze.js +1 -0
  35. package/dist/{chunk-4m5gpp6w.js → chunk-wggeew90.js} +5 -5
  36. package/dist/{chunk-jz6dacx1.js → chunk-wnevarf9.js} +2 -2
  37. package/dist/{chunk-sxqe8e9c.js → chunk-x1k1sbgf.js} +7 -7
  38. package/dist/{chunk-byr76jcy.js → chunk-xa2ahxxa.js} +19 -19
  39. package/dist/{chunk-zjkxhvn0.js → chunk-ybhjh309.js} +125 -114
  40. package/dist/{chunk-9f18pebj.js → chunk-z1087cap.js} +5 -5
  41. package/dist/chunk-z5dqpsek.js +1 -0
  42. package/dist/{chunk-x7cnfn7y.js → chunk-zpkf2jt2.js} +2 -2
  43. package/dist/deploy/index.js +1 -1
  44. package/dist/dns/index.js +1 -1
  45. package/dist/drivers/index.d.ts +2 -2
  46. package/dist/drivers/index.js +1 -1
  47. package/dist/drivers/shared/compute-storage.d.ts +1 -0
  48. package/dist/drivers/shared/persistent-storage-agent.d.ts +3 -0
  49. package/dist/drivers/shared/rpx-gateway.d.ts +14 -0
  50. package/dist/index.d.ts +1 -1
  51. package/dist/index.js +37 -37
  52. package/dist/mail/index.js +2 -2
  53. package/dist/operations/index.js +1 -1
  54. package/dist/protection/index.js +1 -1
  55. package/dist/spend/index.js +1 -1
  56. package/dist/ui/404.html +1 -1
  57. package/dist/ui/accept-invitation.html +1 -1
  58. package/dist/ui/access-denied.html +1 -1
  59. package/dist/ui/account/automation.html +6 -6
  60. package/dist/ui/account/security.html +2 -2
  61. package/dist/ui/applications/compose.html +6 -6
  62. package/dist/ui/applications/new.html +2 -2
  63. package/dist/ui/data/backups.html +6 -6
  64. package/dist/ui/data/services.html +6 -6
  65. package/dist/ui/data/volumes.html +6 -6
  66. package/dist/ui/index.html +6 -6
  67. package/dist/ui/infrastructure/topology.html +5 -5
  68. package/dist/ui/integrations.html +1 -1
  69. package/dist/ui/operations/alerts.html +6 -6
  70. package/dist/ui/operations/configuration.html +6 -6
  71. package/dist/ui/operations/jobs.html +5 -5
  72. package/dist/ui/operations/maintenance.html +5 -5
  73. package/dist/ui/operations/observability.html +6 -6
  74. package/dist/ui/operations/previews.html +6 -6
  75. package/dist/ui/operations/queue.html +6 -6
  76. package/dist/ui/operations/regions.html +6 -6
  77. package/dist/ui/operations/releases.html +5 -5
  78. package/dist/ui/operations/spend.html +6 -6
  79. package/dist/ui/operations/workloads.html +6 -6
  80. package/dist/ui/security.html +1 -1
  81. package/dist/ui/server/actions.html +6 -6
  82. package/dist/ui/server/activity.html +1 -1
  83. package/dist/ui/server/capacity.html +6 -6
  84. package/dist/ui/server/database.html +6 -6
  85. package/dist/ui/server/deployments.html +5 -5
  86. package/dist/ui/server/diagnostics.html +2 -2
  87. package/dist/ui/server/firewall.html +6 -6
  88. package/dist/ui/server/fleet.html +5 -5
  89. package/dist/ui/server/logs.html +5 -5
  90. package/dist/ui/server/metrics.html +5 -5
  91. package/dist/ui/server/security.html +1 -1
  92. package/dist/ui/server/services.html +2 -2
  93. package/dist/ui/server/sites.html +6 -6
  94. package/dist/ui/server/ssh-keys.html +6 -6
  95. package/dist/ui/server/team.html +6 -6
  96. package/dist/ui/server/terminal.html +2 -2
  97. package/dist/ui/serverless/alarms.html +6 -6
  98. package/dist/ui/serverless/assets.html +2 -2
  99. package/dist/ui/serverless/cost.html +1 -1
  100. package/dist/ui/serverless/data.html +5 -5
  101. package/dist/ui/serverless/deployments.html +2 -2
  102. package/dist/ui/serverless/firewall.html +1 -1
  103. package/dist/ui/serverless/functions.html +6 -6
  104. package/dist/ui/serverless/logs.html +5 -5
  105. package/dist/ui/serverless/metrics.html +2 -2
  106. package/dist/ui/serverless/queues.html +6 -6
  107. package/dist/ui/serverless/secrets.html +6 -6
  108. package/dist/ui/serverless/traces.html +6 -6
  109. package/dist/ui/serverless.html +5 -5
  110. package/package.json +3 -3
  111. package/dist/chunk-0v77443p.js +0 -1
  112. package/dist/chunk-4khjjgd3.js +0 -1
  113. package/dist/chunk-872fdms3.js +0 -1
  114. package/dist/chunk-bazah9w0.js +0 -1
  115. package/dist/chunk-dmv3vryr.js +0 -138
  116. package/dist/chunk-qs7814ya.js +0 -1
  117. package/dist/chunk-sd5a61c6.js +0 -1
  118. package/dist/chunk-t1wq0ckc.js +0 -2
  119. package/dist/chunk-zft558kj.js +0 -1
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
- import{WI,JI,ul,Dm,gl,pl,ln,H,l,ml,Pm,W,fl,p,gy,b,tt,Yi,un,w,le,hl,py,r,t,XI,YI,m,ZI,eb,tb,rb,nb,ur,Al,Zi,my,ib,sb,_e,rt,yl,km,Nm,ob,Bm,xm,Om,Ko,Sl,ue,gn,Nt,Wo,Bt,ve,fy,Il,Jo,_m,Lm,$m,Mm,bl,ab,J,E,hy,Ay,Fm,a,S,nt,f,Um,it,X,xt,cb,Qm,Y,Cl,Le,gr,Xo,ge,El,pe,yy,Yo,Z,ee,L,es,D,pr,Ot,te,e,pn,db,Hm,vl,lb,ub,gb,pb,Tl,mb,fb,hb,Ab,yb,Sb,Ib,bb,Cb,Eb,vb,Tb,Sy,Iy,by,Cy,Ey,vy,Ty,mr,Gm,Vm,fr,ts,wb,qm,Rb,Db,mn,Pb,kb,Nb,Bb,xb,Ob,jm,k,Te,rs,Zo,fn,ns,ea,wy,_b,is,ta,Ry,Dy,Py,ky,Ny,By,ss,Lb,ra,xy,zm,q,Oy,st,na,_t,_y,Km,Ly,$y,My,Wm,j,$b,Mb,Fb,Ub,Fy,Qb,re,Hb,Gb,Vb,wl,Rl,Uy,Jm,Xm,qb,jb,zb,Kb,Wb,Qy,Dl,Jb,Xb,Yb,Zb,eC,Hy,Gy,tC,rC,nC,iC,sC,oC,aC,Vy,cC,Ym,Pl,dC,lC,uC,gC,Zm,ef,tf,pC,kl,qy,jy,zy,Ky,Nl,Wy,mC,fC,hC,AC,yC,SC,IC,Jy,Xy,Yy,Zy,rf,bC,CC,EC,vC,TC,wC,RC,DC,PC,eS,tS,rS,nS,kC,NC,nf,BC,sf,of,af,cf,xC,OC,_C,LC,$e,os,$C,MC,FC,UC,QC,HC,GC,VC,iS,qC,jC,df,lf,zC,KC,sS,WC,JC,XC,YC,ZC,eE,tE,rE,nE,iE,sE,oE,aE,cE,dE,lE,uE,gE,pE,mE,fE,Bl,oS,xl,aS,Ol,cS,_l,dS,Ll,lS,hr,uS,$l,gS,as,pS,Ml,mS,Fl,fS,uf,hE,gf,AE,Ul,hS,Ar,AS,pf,yE,Ql,yS,mf,SE,ff,IE,hf,bE,Hl,SS,Af,CE,yf,EE,Sf,vE,If,TE,Gl,IS,Vl,bS,bf,wE,Cf,RE,Ef,DE,vf,PE,Tf,kE,wf,NE,ql,CS,Rf,BE,Df,xE,Pf,OE,kf,_E,Nf,LE,Bf,$E,xf,Of,_f,Lf,$f,ME,Mf,FE,Ff,UE,Uf,QE,ot,Qf,ES,ia,jl,hn,vS,cs,yr,zl,Kl,TS,wS,Wl,Hf,Jl,Gf,HE,GE,sa,oa,aa,Xl,An,Yl,Zl,ds,ca,da,Vf,RS,DS,PS,VE,qf,jf,qE,kS,zf,NS,BS,xS,jE,Kf,yn,eu,Wf,zE,OS,la,ua,tu,Jf,KE,ru,_S,Xf,WE,Yf,JE,Zf,XE}from"./chunk-72p2tdpe.js";import{nu,N,iu,ga,MS,eh,FS,US,QS,HS,GS,VS,qS,jS}from"./chunk-sjfc9my3.js";import{ya,th,gu,KS,ms,pu,Sa,rh,nh,In,Ia,mu,at,fu,hu,Au,fs,bn,ih,ct,yu,ba,Ca,Ea,Su,Iu,bu,hs,va,Cu,Cn,As,Ta,Lt,sh,Eu,vu,oh,Tu,wa,Sr,wu,Ru,Du,Pu,dt,ah,ku,Ir,Ra,Da,Pa,ys,Ss,En,Nu,Is,ka,Na,vn,Bu,Tn,ch,dh,$t,wn,Ba,lh,xu,Ou,xa,_u,Lu,$u,WS,me,Mu,JS,XS,bs,Cs,YS,we,uh,Mt,Me,Fe,Ft,Fu,Uu,Qu,Hu,gh,ph,Oa,mh,fh,_a,Gu,Vu,hh,fe,Ah,qu,Re,La,lt,Ut,Qt,Rn,Es,ju,ZS,yh,Sh,Ih,bh,$a,Ma,zu,Fa,Dn,Ua,Ku,vs,Wu,Qa,Ha,Ga,Va,qa,ja,za,Ka,Ju,br,Wa,Xu,Pn,Yu,Ja,Xa,Zu,Cr,Ya,Za,Ch,eI,Ts,tI,rI,nI,ec,tc,eg,Eh,rc,kn,tg,ws,rg,ng,ig,nc,vh,ic,sg,Th,sc,wh,Nn,Bn,og,Rs,gg,hg,Ag,yg,Sg,Ig,Ps,Er,ac,xn,On,vr,ut,Oh,dc,_h,Lh,Eg,lc,Ns,vg,uc,Gt,Qe,Tg,gc,pc,wg,mc,fc,hc,Ac,Rg,Dg,Ln,yc,Sc,Ic,bc,Pg,Bs,$n,xs,Cc}from"./chunk-cjm5j58y.js";import{uu}from"./chunk-kcem6dzk.js";import{Q,Wr,wd,Eo,d,rm,nm}from"./chunk-x7cnfn7y.js";import{wt,Td,_i,Li,$i,tm}from"./chunk-xs9m0v31.js";import{gA,pA,mA,Lp,$p,Mp,fA,Fp,Up,hA,AA,Qp,yA,SA,Ed,Hp,IA,bA,Gp,CA,EA,vA,TA,wA,RA,DA,Oi,vd,Vp,qp,jp,zp,Kp,Wp,Jp,Xp,Yp,Zp,em,PA,kA,NA,BA,xA,OA,_A}from"./chunk-byr76jcy.js";import{Ye,Rd,Ee,ir,Dd,O,sr,Rt,Pd,vo,MA,im,kd,s,Mi,To,Jr,Nd,Bd,Xr,FA,xd,qI,jI,wo,zI,KI,Od,_d,Fi,Ro,de,c,Do,Ze,Yr,UA,QA,Ld,HA,Po,GA,VA,ko,$d,Zr,No,qA,or,Md,sm,ar,en,jA,Bo,zA,_,KA,Fd,om,xo,WA,JA,XA,Ud,Ui,Oo,Qd,cr,Dt,YA,tn,ZA,Hd,am,cm,_o,Gd,Vd,Pt,dm,Qi,qd,Lo,rn,lm,Hi,jd,zd,Gi,um,Kd,Wd,Jd,Xd,$o,gm,pm,ey,mm,Yd,Vi,fm,hm,Mo,nn,Fo,Uo,Qo,Zd,Am,el,Ho,ty,dr,ry,tl,sn,rl,ny,nl,ym,qi,on,Go,ji,et,iy,Sm,Im,lr,il,sl,ol,zi,Ki,Wi,sy,oy,kt,Vo,ay,an,bm,qo,cy,Cm,Em,vm,dy,Tm,wm,ly,i,uy,Ji,jo,zo}from"./chunk-fe6m7wb0.js";import{n}from"./chunk-7d9ek8rc.js";import{ke,ft,Wn}from"./chunk-zy3kr4s2.js";import{De,Us,Qs,Bg,Rc,Dc,Hs,Pc,gt,ne,pt,he,T,Pe,Hn,kc,He,Nc,Gn,Vn,qn,Vt,qt,jt,jn,wr,Bc,Rr,Dr,mt,zn,Oc,zt,Pr,Kn,Lc,$g,Mg,$c,kr}from"./chunk-fne338jr.js";import{o}from"./chunk-1psh3mhm.js";import{A}from"./chunk-by7hejhg.js";import{jr,Oe}from"./chunk-a77mhcs7.js";import{Mc,Ge,I}from"./chunk-1087xz1v.js";import{C}from"./chunk-tpvmpmxj.js";import{ht,Se,qe,Fg,Kt,Fc,Uc,Wt,G,Jn,Jt,Xt,Xn,js,zs,Nr,Br,Yn,xr,Ks,Ws,Js,Xs,se,Ys,Zs,eo,to,Ie,ro,no,io,B,Qc,Zn,Hc,be,Or}from"./chunk-zwayp7fz.js";import{Ve}from"./chunk-hcbrgyfz.js";import{ie}from"./chunk-h6kptkce.js";import{Ug,Gc,Qg,oe,Vc,ei,Hg,qc,Gg,Vg,Wh,Lr,oo,F,Mr,ri,ni,Fr,Qr,ii,ao,si,oi,ai,ci,li,Hr,Ce,Kc,yt,Wc,Gr,Yc,ze,ae,Ke,We,It,pi,mi,Ne,Ct,Be,hi,Ai,yi,Si,Ii,bi,Ci,Vr,U,go,hp,ad,vi,Ti,wi,Ri,pd,mo,md,rr,Pi,fo,ho,fd,ki,hd}from"./chunk-zjkxhvn0.js";import{yo,Io,bo,x,xe}from"./chunk-dmv3vryr.js";import{su,pa,us,gs,ma,ou,au,ps,fa,ha,du,lu,Aa}from"./chunk-qra9k26f.js";import{Ec,Mn,Un,Os,_s,Ls,$s,vc,Tc}from"./chunk-9f18pebj.js";import{wc}from"./chunk-c6kb5c5v.js";import{ce,Ni,Ao,Ad,Bi,kp}from"./chunk-4m5gpp6w.js";import{al,cn,cl,dl,ll,Xi,Rm,dn}from"./chunk-sxqe8e9c.js";import{LS,ls}from"./chunk-jz6dacx1.js";var eR="https://api.machines.dev/v1";class So extends Error{status;path;constructor(u,g,h){super(u);this.status=g;this.path=h;this.name="FlyApiError"}}function sd(u){let g=u.ip.includes(":");if(g&&u.ip.startsWith("fdaa:"))return"private_v6";if(u.shared)return"shared_v4";return g?"v6":"v4"}class Cp{token;fetch;constructor(u){if(!u.token)throw Error("Fly.io needs an API token: set FLY_API_TOKEN (`fly tokens create deploy` makes one scoped to an app).");this.token=u.token,this.fetch=u.fetch??fetch}async rest(u,g,h={}){let y=new URL(`https://api.machines.dev/v1${g}`);for(let[M,V]of Object.entries(h.query??{}))y.searchParams.set(M,V);let R=await this.fetch(y,{method:u,headers:{Authorization:`Bearer ${this.token}`,...h.body!==void 0?{"Content-Type":"application/json"}:{},...h.headers},body:h.body===void 0?void 0:JSON.stringify(h.body)});if(R.status===404&&h.notFound==="null")return null;let v=await R.text(),P=v?Sp(v):void 0;if(!R.ok){let M=typeof P==="object"&&P&&"error"in P?String(P.error):v||R.statusText;throw new So(`Fly.io ${u} ${g} failed (${R.status}): ${M}`,R.status,g)}return P}getApp(u){return this.rest("GET",`/apps/${encodeURIComponent(u)}`,{notFound:"null"})}createApp(u,g){return this.rest("POST","/apps",{body:{app_name:u,org_slug:g}})}async listMachines(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines`)??[]}createMachine(u,g){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines`,{body:g})}updateMachine(u,g,h,y){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(g)}`,{body:h,headers:{"fly-machine-lease-nonce":y}})}async acquireLease(u,g,h=120){let R=(await this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(g)}/lease`,{body:{ttl:h}})).data?.nonce;if(!R)throw new So(`Fly.io gave no lease nonce for Machine ${g}`,200,`/machines/${g}/lease`);return R}async releaseLease(u,g,h){await this.rest("DELETE",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(g)}/lease`,{headers:{"fly-machine-lease-nonce":h}})}async waitForState(u,g,h,y={}){await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(g)}/wait`,{query:{state:h,timeout:String(y.timeoutSeconds??60),...y.instanceId?{instance_id:y.instanceId}:{}}})}async listVolumes(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/volumes`)??[]}createVolume(u,g){return this.rest("POST",`/apps/${encodeURIComponent(u)}/volumes`,{body:{...g,encrypted:!0}})}async setSecrets(u,g){return(await this.rest("POST",`/apps/${encodeURIComponent(u)}/secrets`,{body:{values:g}})).version}async listIpAssignments(u){return(await this.rest("GET",`/apps/${encodeURIComponent(u)}/ip_assignments`)).ips??[]}async assignIp(u,g){let h=await this.rest("POST",`/apps/${encodeURIComponent(u)}/ip_assignments`,{body:{type:g}});if(!h.ip)throw new So(`Fly.io assigned no ${g} address to ${u}`,200,`/apps/${u}/ip_assignments`);return{ip:h.ip,shared:h.shared??g==="shared_v4",region:h.region}}async requestCertificate(u,g){return this.rest("POST",`/apps/${encodeURIComponent(u)}/certificates/acme`,{body:{hostname:g}})}}function Sp(u){try{return JSON.parse(u)}catch{return}}var zc="ts-cloud-role";function nR(u,g){let h=u.fly??{},y=h.app??`${u.project.slug}-${g.environment}`;if(!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/.test(y))throw Error(`"${y}" is not a valid Fly app name: lowercase letters, digits and dashes, 3 to 63 characters.`);let R=h.internalPort??3000,v=h.count??1;if(!Number.isInteger(v)||v<1)throw Error(`fly.count must be a whole number of at least 1, got ${v}.`);return{app:y,org:h.org??"personal",image:g.image,regions:h.regions?.length?h.regions:["iad"],count:v,internalPort:R,healthPath:h.healthPath??"/",vm:{cpuKind:h.vm?.cpuKind??"shared",cpus:h.vm?.cpus??1,memoryMb:h.vm?.memoryMb??512},...h.volume?{volume:{name:h.volume.name??"data",sizeGb:h.volume.sizeGb,path:h.volume.path}}:{},autoStop:h.autoStop??!1,env:{...g.env,PORT:String(R)},secrets:g.secrets??{},hostnames:h.hostnames??[],release:g.release}}function Rp(u){return{image:u.image,env:u.env,guest:{cpu_kind:u.vm.cpuKind,cpus:u.vm.cpus,memory_mb:u.vm.memoryMb},services:[{protocol:"tcp",internal_port:u.internalPort,ports:[{port:80,handlers:["http"],force_https:!0},{port:443,handlers:["tls","http"]}],autostop:u.autoStop?"stop":"off",autostart:!0,...u.autoStop?{min_machines_running:0}:{},checks:[{type:"http",method:"GET",path:u.healthPath,interval:"15s",timeout:"5s",grace_period:"10s"}]}],restart:{policy:"on-failure",max_retries:10},metadata:{[zc]:"app","ts-cloud-release":u.release}}}async function iR(u,g,h=()=>{}){let y=!1;if(!await u.getApp(g.app))h(`Creating Fly app ${g.app} in ${g.org}`),await u.createApp(g.app,g.org),y=!0;let R;if(Object.keys(g.secrets).length>0)R=await u.setSecrets(g.app,g.secrets),h(`Set ${Object.keys(g.secrets).length} secret(s) (version ${R})`);let v=await u.listIpAssignments(g.app),P=new Set(v.map(sd));if(!P.has("v6"))v.push(await u.assignIp(g.app,"v6")),h("Assigned a dedicated IPv6");if(!P.has("v4")&&!P.has("shared_v4"))v.push(await u.assignIp(g.app,"shared_v4")),h("Assigned a shared IPv4");let M=Rp(g),V=(await u.listMachines(g.app)).filter((Ue)=>{let je=Ue.config?.metadata??{};if(je[zc])return je[zc]==="app";return!je.fly_process_group||je.fly_process_group==="app"}),Ae=g.volume?await u.listVolumes(g.app):[],ye=[],At=[],Tt=new Set;for(let Ue of g.regions){let je=V.filter((K)=>K.region===Ue).sort((K,St)=>K.id.localeCompare(St.id));for(let K=0;K<g.count;K++){let St=je[K];if(St){Tt.add(St.id),await bp(u,g.app,St,M,R),At.push(St.id),h(`Updated ${St.id} (${Ue}) to ${g.image}`);continue}let z=g.volume?[{volume:(await Ap(u,g,Ue,Ae)).id,path:g.volume.path}]:void 0,Xe=await u.createMachine(g.app,{region:Ue,name:`${g.app}-${Ue}-${K+1}`,config:{...M,...z?{mounts:z}:{}},...R!==void 0?{min_secrets_version:R}:{}});await u.waitForState(g.app,Xe.id,"started",{instanceId:Xe.instance_id}),ye.push(Xe.id),h(`Created ${Xe.id} in ${Ue}`)}}let Je=[];for(let Ue of g.hostnames)Je.push(await u.requestCertificate(g.app,Ue));return{app:g.app,url:`https://${g.app}.fly.dev`,createdApp:y,created:ye,updated:At,untouched:V.filter((Ue)=>!Tt.has(Ue.id)).map((Ue)=>Ue.id),ips:v,certificates:Je}}async function bp(u,g,h,y,R){let v=await u.acquireLease(g,h.id);try{let P=await u.updateMachine(g,h.id,{config:{...y,...h.config?.mounts?.length?{mounts:h.config.mounts}:{}},...R!==void 0?{min_secrets_version:R}:{}},v);await u.waitForState(g,h.id,"started",{instanceId:P.instance_id})}finally{await u.releaseLease(g,h.id,v)}}async function Ap(u,g,h,y){let R=y.find((P)=>P.region===h&&P.name===g.volume.name&&!P.attached_machine_id);if(R)return R.attached_machine_id="pending",R;let v=await u.createVolume(g.app,{name:g.volume.name,region:h,size_gb:g.volume.sizeGb});return y.push({...v,attached_machine_id:"pending"}),v}import{createHmac as cd,createSign as Pp,timingSafeEqual as Tp}from"node:crypto";function Di(u){let g=u instanceof Date?u.getTime():u;if(!Number.isFinite(g))throw TypeError("Media access timestamp must be finite");return Math.floor(g/1000)}function ld(u){return Buffer.from(u).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function wp(u){return Buffer.from(u).toString("base64url")}function ud(u,g=!1){if(!u||/[\r\n]/.test(u))throw TypeError("Media resource is invalid");let h=g?u.replaceAll("*","wildcard"):u,y=new URL(h);if(!["http:","https:"].includes(y.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!g&&u.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function dd(u,g){let h=Pp("RSA-SHA1");return h.update(u),h.end(),ld(h.sign(g))}function gd(u){ud(u.resource,!0);let h={DateLessThan:{"AWS:EpochTime":Di(u.expiresAt)}};if(u.activeAt!==void 0)h.DateGreaterThan={"AWS:EpochTime":Di(u.activeAt)};if(u.ipAddress)h.IpAddress={"AWS:SourceIp":u.ipAddress};return JSON.stringify({Statement:[{Resource:u.resource,Condition:h}]})}function uR(u,g,h){ud(u);let y=Di(g),R=u.includes("?")?"&":"?",v=gd({resource:u,expiresAt:g}),P=dd(v,h.privateKey);return`${u}${R}Expires=${y}&Signature=${encodeURIComponent(P)}&Key-Pair-Id=${encodeURIComponent(h.keyPairId)}`}function dR(u,g){let h=gd(u);return{"CloudFront-Key-Pair-Id":g.keyPairId,"CloudFront-Policy":ld(Buffer.from(h)),"CloudFront-Signature":dd(h,g.privateKey)}}function pR(u){if(!u.resource||/[\r\n]/.test(u.resource))throw TypeError("Media resource is invalid");let g=wp(Buffer.from(JSON.stringify({resource:u.resource,expiresAt:Di(u.expiresAt),...u.keyId?{keyId:u.keyId}:{},...u.audience?{audience:u.audience}:{}}))),h=cd("sha256",u.secret).update(g).digest("base64url");return`${g}.${h}`}function mR(u,g){let[h,y,R]=u.split(".");if(!h||!y||R)return null;let v=cd("sha256",g.secret).update(h).digest(),P;try{P=Buffer.from(y,"base64url")}catch{return null}if(v.length!==P.length||!Tp(v,P))return null;try{let M=JSON.parse(Buffer.from(h,"base64url").toString("utf8")),V=Di(g.now??Date.now());if(!M.resource||!Number.isSafeInteger(M.expiresAt)||M.expiresAt<=V)return null;if(g.resource&&M.resource!==g.resource)return null;if(g.audience&&M.audience!==g.audience)return null;return M}catch{return null}}function gR(u,g=!1){let h=new URL(u,"https://media.invalid").pathname.toLowerCase(),y=/\.(?:m3u8|mpd|vtt|json)$/.test(h),R=/\.(?:key|license)$/.test(h)||h.includes("/keys/")||h.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":g&&(y||R)?"private, no-store":y?"public, max-age=5, s-maxage=30, stale-while-revalidate=30":"public, max-age=31536000, immutable","Cross-Origin-Resource-Policy":"cross-origin","X-Content-Type-Options":"nosniff"}}function fR(u){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(u.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(u.region))throw TypeError("Media bucket region is invalid");let g=u.prefix?`/${u.prefix.replace(/^\/+|\/+$/g,"")}`:"",h=u.protected??!1,y="public, max-age=31536000, immutable",R=h?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${u.bucket}.s3.${u.region}.amazonaws.com`,originPath:g,domain:u.domain,trustedKeyGroupIds:[...new Set(u.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:R,compress:!0,signed:h},{pathPattern:"*.mpd",cacheControl:R,compress:!0,signed:h},{pathPattern:"*.vtt",cacheControl:R,compress:!0,signed:h},{pathPattern:"*",cacheControl:y,compress:!1,signed:h}],responseHeaders:{"Access-Control-Allow-Headers":"Range, If-Range","Access-Control-Allow-Methods":"GET, HEAD, OPTIONS","Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":"Accept-Ranges, Content-Length, Content-Range, ETag","X-Content-Type-Options":"nosniff"}}}class Ip{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(u){this.config=u.config,this.environment=u.environment,this.builder=new hl(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let g=this.config.environments[this.environment]?.infrastructure;if(!g)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...g,compute:{...this.config.infrastructure?.compute,...g.compute},storage:{...this.config.infrastructure?.storage,...g.storage},functions:{...this.config.infrastructure?.functions,...g.functions},servers:{...this.config.infrastructure?.servers,...g.servers},databases:{...this.config.infrastructure?.databases,...g.databases},cdn:{...this.config.infrastructure?.cdn,...g.cdn},sftp:g.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...g.queues},redirects:{...this.config.infrastructure?.redirects,...g.redirects},realtime:{...this.config.infrastructure?.realtime,...g.realtime},cache:{...this.config.infrastructure?.cache,...g.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...g.fileSystem},email:{...this.config.infrastructure?.email,...g.email},search:{...this.config.infrastructure?.search,...g.search},ai:{...this.config.infrastructure?.ai,...g.ai}}}}shouldDeploy(u){if(u.environments&&!u.environments.includes(this.environment))return!1;if(u.requiresFeatures){let g=this.config.features||{};if(!u.requiresFeatures.every((y)=>g[y]===!0))return!1}if(u.regions){let g=this.config.environments[this.environment]?.region||this.config.project.region;if(!u.regions.includes(g))return!1}if(u.condition&&typeof u.condition==="function")return u.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let u=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,g=Number(u||3008);return Number.isFinite(g)&&g>0?g:3008}defaultComputeCachePathPatterns(){return["/api/*","/auth/*","/publisher/api/*","/publisher/*","/publish","/publish/*","/analytics/*","/packages/*","/npm/*","/zig/*","/php/*","/commits/*","/health","/dashboard/*","/search","/login","/logout","/signup","/account","/account/*"]}shouldRouteStorageBucketToCompute(u,g){return u==="public"||g.routeCompute===!0}storageBucketName(u,g,h){return this.mergedConfig.infrastructure?.storage?.[h]?.bucket??`${u}-${g}-${h}`}fileSystemLogicalId(u,g,h){return t(r({slug:`${u}-${h}`,environment:g,resourceType:"efs"}))}resolveSftpStorage(u,g,h){let y=u.storage;if(y?.type==="efs"&&y.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[y.fileSystem])throw Error(`sftp: storage.fileSystem "${y.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(g,h,y.fileSystem)},posixProfile:y.posixProfile}}if(y?.type==="s3"&&y.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[y.storageBucket])throw Error(`sftp: storage.storageBucket "${y.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(g,h,y.storageBucket)}}return}resolveComputeCachePathPatterns(u){if(u&&u.length>0)return u;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(u,g){return{PathPattern:u,TargetOriginId:g,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",OriginRequestPolicyId:"b689b0a8-53d0-40ab-baf2-68738e2966ac"}}appendComputeAppOrigin(u,g,h,y,R,v){let P=this.serverEipLogicalIds.get("app"),M=this.serverEipLogicalIds.get("appInstance");if(!P)return;let V=`EC2-${y}-${R}-api`,Ae=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",ye=Ae==="us-east-1"?".compute-1.amazonaws.com":`.${Ae}.compute.amazonaws.com`,At={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:P}]}]},ye]]},Tt=this.resolveApiOriginPort();if(u.push({Id:V,DomainName:At,CustomOriginConfig:{HTTPPort:Tt,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),h.push(P),M)h.push(M);for(let Je of v)g.push(this.createComputeCacheBehavior(Je,V))}buildCaddyfile(u){let g=u.filter(([,R])=>typeof R.domain==="string"&&R.domain&&typeof R.port==="number");if(g.length===0)return;let h=new Map;for(let[,R]of g){let v=h.get(R.domain)??[];v.push({port:R.port,path:R.path}),h.set(R.domain,v)}let y=[];for(let[R,v]of h){let M=[...v].sort((V,Ae)=>{let ye=!V.path||V.path==="/",At=!Ae.path||Ae.path==="/";if(ye&&!At)return 1;if(!ye&&At)return-1;return(Ae.path?.length??0)-(V.path?.length??0)}).map((V)=>{let Ae=!V.path||V.path==="/",ye=`reverse_proxy localhost:${V.port}`;return Ae?` handle {
2
- ${ye}
3
- }`:` handle ${V.path} {
4
- ${ye}
5
- }`});y.push(`${R} {
1
+ import{JI,XI,gl,Pm,pl,ml,ln,H,l,fl,km,J,hl,p,py,C,rt,Zi,un,R,ge,Al,my,r,t,YI,ZI,m,eb,tb,rb,nb,ib,ur,yl,es,fy,sb,ob,$e,nt,Sl,Nm,Bm,ab,xm,Om,_m,Wo,Il,pe,gn,Nt,Jo,Bt,we,hy,bl,Xo,Lm,$m,Mm,Fm,Cl,cb,X,v,Ay,yy,Um,a,I,it,f,Qm,st,Y,xt,db,Hm,Z,El,Me,gr,Yo,me,vl,fe,Sy,Zo,ee,te,L,ts,D,pr,Ot,re,e,pn,lb,Gm,Tl,ub,gb,pb,mb,wl,fb,hb,Ab,yb,Sb,Ib,bb,Cb,Eb,vb,Tb,wb,Iy,by,Cy,Ey,vy,Ty,wy,mr,Vm,qm,fr,rs,Rb,jm,Db,Pb,mn,kb,Nb,Bb,xb,Ob,_b,zm,k,Re,ns,ea,fn,is,ta,Ry,Lb,ss,ra,Dy,Py,ky,Ny,By,xy,os,$b,na,Oy,Km,q,_y,ot,ia,_t,Ly,Wm,$y,My,Fy,Jm,j,Mb,Fb,Ub,Qb,Uy,Hb,ne,Gb,Vb,qb,Rl,Dl,Qy,Xm,Ym,jb,zb,Kb,Wb,Jb,Hy,Pl,Xb,Yb,Zb,eC,tC,Gy,Vy,rC,nC,iC,sC,oC,aC,cC,qy,dC,Zm,kl,lC,uC,gC,pC,ef,tf,rf,mC,Nl,jy,zy,Ky,Wy,Bl,Jy,fC,hC,AC,yC,SC,IC,bC,Xy,Yy,Zy,eS,nf,CC,EC,vC,TC,wC,RC,DC,PC,kC,tS,rS,nS,iS,NC,BC,sf,xC,of,af,cf,df,OC,_C,LC,$C,Fe,as,MC,FC,UC,QC,HC,GC,VC,qC,sS,jC,zC,lf,uf,KC,WC,oS,JC,XC,YC,ZC,eE,tE,rE,nE,iE,sE,oE,aE,cE,dE,lE,uE,gE,pE,mE,fE,hE,xl,aS,Ol,cS,_l,dS,Ll,lS,$l,uS,hr,gS,Ml,pS,cs,mS,Fl,fS,Ul,hS,gf,AE,pf,yE,Ql,AS,Ar,yS,mf,SE,Hl,SS,ff,IE,hf,bE,Af,CE,Gl,IS,yf,EE,Sf,vE,If,TE,bf,wE,Vl,bS,ql,CS,Cf,RE,Ef,DE,vf,PE,Tf,kE,wf,NE,Rf,BE,jl,ES,Df,xE,Pf,OE,kf,_E,Nf,LE,Bf,$E,xf,ME,Of,_f,Lf,$f,Mf,FE,Ff,UE,Uf,QE,Qf,HE,at,Hf,vS,sa,zl,hn,TS,ds,yr,Kl,Wl,wS,RS,Jl,Gf,Xl,Vf,GE,VE,oa,aa,ca,Yl,An,Zl,eu,ls,da,la,qf,DS,PS,kS,qE,jf,zf,jE,NS,Kf,BS,xS,OS,zE,Wf,yn,tu,Jf,KE,_S,ua,ga,ru,Xf,WE,nu,LS,Yf,JE,Zf,XE,eh,YE}from"./chunk-316cbffs.js";import{iu,N,su,pa,FS,th,US,QS,HS,GS,VS,qS,jS,zS}from"./chunk-3t5a5gr2.js";import{Sa,rh,pu,WS,fs,mu,Ia,nh,ih,In,ba,fu,ct,hu,Au,yu,hs,bn,sh,dt,Su,Ca,Ea,va,Iu,bu,Cu,As,Ta,Eu,Cn,ys,wa,Lt,oh,vu,Tu,ah,wu,Ra,Sr,Ru,Du,Pu,ku,lt,ch,Nu,Ir,Da,Pa,ka,Ss,Is,En,Bu,bs,Na,Ba,vn,xu,Tn,dh,lh,$t,wn,xa,uh,Ou,_u,Oa,Lu,$u,Mu,JS,he,Fu,XS,YS,Cs,Es,ZS,De,gh,Mt,Ue,Qe,Ft,Uu,Qu,Hu,Gu,ph,mh,_a,fh,hh,La,Vu,qu,Ah,Ae,yh,ju,Pe,$a,ut,Ut,Qt,Rn,vs,zu,eI,Sh,Ih,bh,Ch,Ma,Fa,Ku,Ua,Dn,Qa,Wu,Ts,Ju,Ha,Ga,Va,qa,ja,za,Ka,Wa,Xu,br,Ja,Yu,Pn,Zu,Xa,Ya,eg,Cr,Za,ec,Eh,tI,ws,rI,nI,iI,tc,rc,tg,vh,nc,kn,rg,Rs,ng,ig,sg,ic,Th,sc,og,wh,oc,Rh,Nn,Bn,ag,Ds,pg,Ag,yg,Sg,Ig,bg,ks,Er,cc,xn,On,vr,gt,_h,lc,Lh,$h,vg,uc,Bs,Tg,gc,Gt,Ge,wg,pc,mc,Rg,fc,hc,Ac,yc,Dg,Pg,Ln,Sc,Ic,bc,Cc,kg,xs,$n,Os,Ec}from"./chunk-jcxm737x.js";import{gu}from"./chunk-tes38y8x.js";import{Q,Wr,Rd,vo,d,nm,im}from"./chunk-zpkf2jt2.js";import{wt,wd,Li,$i,Mi,rm}from"./chunk-bxq80y73.js";import{pA,mA,fA,$p,Mp,Fp,hA,Up,Qp,AA,yA,Hp,SA,IA,vd,Gp,bA,CA,Vp,EA,vA,TA,wA,RA,DA,PA,_i,Td,qp,jp,zp,Kp,Wp,Jp,Xp,Yp,Zp,em,tm,kA,NA,BA,xA,OA,_A,LA}from"./chunk-xa2ahxxa.js";import{Ze,Dd,Te,ir,Pd,O,sr,Rt,kd,To,FA,sm,Nd,s,Fi,wo,Jr,Bd,xd,Xr,UA,Od,jI,zI,Ro,KI,WI,_d,Ld,Ui,Do,ue,c,Po,et,Yr,QA,HA,$d,GA,ko,VA,qA,No,Md,Zr,Bo,jA,or,Fd,om,ar,en,zA,xo,KA,_,WA,Ud,am,Oo,JA,XA,YA,Qd,Qi,_o,Hd,cr,Dt,ZA,tn,ey,Gd,cm,dm,Lo,Vd,qd,Pt,lm,Hi,jd,$o,rn,um,Gi,zd,Kd,Vi,gm,Wd,Jd,Xd,Yd,Mo,pm,mm,ty,fm,Zd,qi,hm,Am,Fo,nn,Uo,Qo,Ho,el,ym,tl,Go,ry,dr,ny,rl,sn,nl,iy,il,Sm,ji,on,Vo,zi,tt,sy,Im,bm,lr,sl,ol,al,Ki,Wi,Ji,oy,ay,kt,qo,cy,an,Cm,jo,dy,Em,vm,Tm,ly,wm,Rm,uy,i,gy,Xi,zo,Ko}from"./chunk-n6tgqd7d.js";import{n}from"./chunk-vaczx33v.js";import{Be,ht,Wn}from"./chunk-kken64a9.js";import{ke,Qs,Hs,xg,Dc,Pc,Gs,kc,pt,ie,mt,ye,w,Ne,Hn,Nc,Ve,Bc,Gn,Vn,qn,Vt,qt,jt,jn,wr,xc,Rr,Dr,ft,zn,_c,zt,Pr,Kn,$c,Mg,Fg,Mc,kr}from"./chunk-4bysqvjh.js";import{o}from"./chunk-byt4re1c.js";import{y}from"./chunk-cjqw4ns4.js";import{jr,Le}from"./chunk-93xknw91.js";import{Fc,qe,b}from"./chunk-4afz3x6w.js";import{E}from"./chunk-p1agrrnq.js";import{At,be,ze,Ug,Kt,Uc,Qc,Wt,G,Jn,Jt,Xt,Xn,zs,Ks,Nr,Br,Yn,xr,Ws,Js,Xs,Ys,oe,Zs,eo,to,ro,Ce,no,io,so,B,Hc,Zn,Gc,Ee,Or}from"./chunk-1kagq9vp.js";import{je}from"./chunk-7y1pknej.js";import{se}from"./chunk-sp0ne2ax.js";import{Qg,Vc,Hg,ae,qc,ei,Gg,jc,Vg,qg,Jh,Lr,ao,F,Mr,ri,ni,Fr,Qr,ii,co,si,oi,ai,ci,li,Hr,ve,Wc,St,Jc,Gr,Zc,We,ce,Je,Xe,bt,pi,mi,xe,Et,Oe,hi,Ai,yi,Si,Ii,bi,Ci,Vr,U,po,Ap,cd,vi,Ti,wi,Ri,md,fo,fd,rr,Pi,ho,Ao,hd,ki,Ad}from"./chunk-ybhjh309.js";import{So,bo,Co,x,Op,_e}from"./chunk-bzdfx427.js";import{ou,ma,gs,ps,fa,au,cu,ms,ha,Aa,lu,uu,ya}from"./chunk-r2gtxb7n.js";import{vc,Mn,Un,_s,Ls,$s,Ms,Tc,wc}from"./chunk-z1087cap.js";import{Rc}from"./chunk-stqg97mh.js";import{de,Ni,yo,yd,Bi,Np}from"./chunk-wggeew90.js";import{cl,cn,dl,ll,ul,Yi,Dm,dn}from"./chunk-x1k1sbgf.js";import{$S,us}from"./chunk-wnevarf9.js";var tR="https://api.machines.dev/v1";class Io extends Error{status;path;constructor(u,g,h){super(u);this.status=g;this.path=h;this.name="FlyApiError"}}function sd(u){let g=u.ip.includes(":");if(g&&u.ip.startsWith("fdaa:"))return"private_v6";if(u.shared)return"shared_v4";return g?"v6":"v4"}class hp{token;fetch;constructor(u){if(!u.token)throw Error("Fly.io needs an API token: set FLY_API_TOKEN (`fly tokens create deploy` makes one scoped to an app).");this.token=u.token,this.fetch=u.fetch??fetch}async rest(u,g,h={}){let S=new URL(`https://api.machines.dev/v1${g}`);for(let[M,W]of Object.entries(h.query??{}))S.searchParams.set(M,W);let A=await this.fetch(S,{method:u,headers:{Authorization:`Bearer ${this.token}`,...h.body!==void 0?{"Content-Type":"application/json"}:{},...h.headers},body:h.body===void 0?void 0:JSON.stringify(h.body)});if(A.status===404&&h.notFound==="null")return null;let T=await A.text(),P=T?yp(T):void 0;if(!A.ok){let M=typeof P==="object"&&P&&"error"in P?String(P.error):T||A.statusText;throw new Io(`Fly.io ${u} ${g} failed (${A.status}): ${M}`,A.status,g)}return P}getApp(u){return this.rest("GET",`/apps/${encodeURIComponent(u)}`,{notFound:"null"})}createApp(u,g){return this.rest("POST","/apps",{body:{app_name:u,org_slug:g}})}async listMachines(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines`)??[]}createMachine(u,g){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines`,{body:g})}updateMachine(u,g,h,S){return this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(g)}`,{body:h,headers:{"fly-machine-lease-nonce":S}})}async acquireLease(u,g,h=120){let A=(await this.rest("POST",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(g)}/lease`,{body:{ttl:h}})).data?.nonce;if(!A)throw new Io(`Fly.io gave no lease nonce for Machine ${g}`,200,`/machines/${g}/lease`);return A}async releaseLease(u,g,h){await this.rest("DELETE",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(g)}/lease`,{headers:{"fly-machine-lease-nonce":h}})}async waitForState(u,g,h,S={}){await this.rest("GET",`/apps/${encodeURIComponent(u)}/machines/${encodeURIComponent(g)}/wait`,{query:{state:h,timeout:String(S.timeoutSeconds??60),...S.instanceId?{instance_id:S.instanceId}:{}}})}async listVolumes(u){return await this.rest("GET",`/apps/${encodeURIComponent(u)}/volumes`)??[]}createVolume(u,g){return this.rest("POST",`/apps/${encodeURIComponent(u)}/volumes`,{body:{...g,encrypted:!0}})}async setSecrets(u,g){return(await this.rest("POST",`/apps/${encodeURIComponent(u)}/secrets`,{body:{values:g}})).version}async listIpAssignments(u){return(await this.rest("GET",`/apps/${encodeURIComponent(u)}/ip_assignments`)).ips??[]}async assignIp(u,g){let h=await this.rest("POST",`/apps/${encodeURIComponent(u)}/ip_assignments`,{body:{type:g}});if(!h.ip)throw new Io(`Fly.io assigned no ${g} address to ${u}`,200,`/apps/${u}/ip_assignments`);return{ip:h.ip,shared:h.shared??g==="shared_v4",region:h.region}}async requestCertificate(u,g){return this.rest("POST",`/apps/${encodeURIComponent(u)}/certificates/acme`,{body:{hostname:g}})}}function yp(u){try{return JSON.parse(u)}catch{return}}var Lc="ts-cloud-role";function iR(u,g){let h=u.fly??{},S=h.app??`${u.project.slug}-${g.environment}`;if(!/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/.test(S))throw Error(`"${S}" is not a valid Fly app name: lowercase letters, digits and dashes, 3 to 63 characters.`);let A=h.internalPort??3000,T=h.count??1;if(!Number.isInteger(T)||T<1)throw Error(`fly.count must be a whole number of at least 1, got ${T}.`);return{app:S,org:h.org??"personal",image:g.image,regions:h.regions?.length?h.regions:["iad"],count:T,internalPort:A,healthPath:h.healthPath??"/",vm:{cpuKind:h.vm?.cpuKind??"shared",cpus:h.vm?.cpus??1,memoryMb:h.vm?.memoryMb??512},...h.volume?{volume:{name:h.volume.name??"data",sizeGb:h.volume.sizeGb,path:h.volume.path}}:{},autoStop:h.autoStop??!1,env:{...g.env,PORT:String(A)},secrets:g.secrets??{},hostnames:h.hostnames??[],release:g.release}}function Cp(u){return{image:u.image,env:u.env,guest:{cpu_kind:u.vm.cpuKind,cpus:u.vm.cpus,memory_mb:u.vm.memoryMb},services:[{protocol:"tcp",internal_port:u.internalPort,ports:[{port:80,handlers:["http"],force_https:!0},{port:443,handlers:["tls","http"]}],autostop:u.autoStop?"stop":"off",autostart:!0,...u.autoStop?{min_machines_running:0}:{},checks:[{type:"http",method:"GET",path:u.healthPath,interval:"15s",timeout:"5s",grace_period:"10s"}]}],restart:{policy:"on-failure",max_retries:10},metadata:{[Lc]:"app","ts-cloud-release":u.release}}}async function oR(u,g,h=()=>{}){let S=!1;if(!await u.getApp(g.app))h(`Creating Fly app ${g.app} in ${g.org}`),await u.createApp(g.app,g.org),S=!0;let A;if(Object.keys(g.secrets).length>0)A=await u.setSecrets(g.app,g.secrets),h(`Set ${Object.keys(g.secrets).length} secret(s) (version ${A})`);let T=await u.listIpAssignments(g.app),P=new Set(T.map(sd));if(!P.has("v6"))T.push(await u.assignIp(g.app,"v6")),h("Assigned a dedicated IPv6");if(!P.has("v4")&&!P.has("shared_v4"))T.push(await u.assignIp(g.app,"shared_v4")),h("Assigned a shared IPv4");let M=Cp(g),W=(await u.listMachines(g.app)).filter((Se)=>{let Ie=Se.config?.metadata??{};if(Ie[Lc])return Ie[Lc]==="app";return!Ie.fly_process_group||Ie.fly_process_group==="app"}),le=g.volume?await u.listVolumes(g.app):[],K=[],Ct=[],Tt=new Set;for(let Se of g.regions){let Ie=W.filter((z)=>z.region===Se).sort((z,Ye)=>z.id.localeCompare(Ye.id));for(let z=0;z<g.count;z++){let Ye=Ie[z];if(Ye){Tt.add(Ye.id),await Sp(u,g.app,Ye,M,A),Ct.push(Ye.id),h(`Updated ${Ye.id} (${Se}) to ${g.image}`);continue}let V=g.volume?[{volume:(await Rp(u,g,Se,le)).id,path:g.volume.path}]:void 0,Ke=await u.createMachine(g.app,{region:Se,name:`${g.app}-${Se}-${z+1}`,config:{...M,...V?{mounts:V}:{}},...A!==void 0?{min_secrets_version:A}:{}});await u.waitForState(g.app,Ke.id,"started",{instanceId:Ke.instance_id}),K.push(Ke.id),h(`Created ${Ke.id} in ${Se}`)}}let He=[];for(let Se of g.hostnames)He.push(await u.requestCertificate(g.app,Se));return{app:g.app,url:`https://${g.app}.fly.dev`,createdApp:S,created:K,updated:Ct,untouched:W.filter((Se)=>!Tt.has(Se.id)).map((Se)=>Se.id),ips:T,certificates:He}}async function Sp(u,g,h,S,A){let T=await u.acquireLease(g,h.id);try{let P=await u.updateMachine(g,h.id,{config:{...S,...h.config?.mounts?.length?{mounts:h.config.mounts}:{}},...A!==void 0?{min_secrets_version:A}:{}},T);await u.waitForState(g,h.id,"started",{instanceId:P.instance_id})}finally{await u.releaseLease(g,h.id,T)}}async function Rp(u,g,h,S){let A=S.find((P)=>P.region===h&&P.name===g.volume.name&&!P.attached_machine_id);if(A)return A.attached_machine_id="pending",A;let T=await u.createVolume(g.app,{name:g.volume.name,region:h,size_gb:g.volume.sizeGb});return S.push({...T,attached_machine_id:"pending"}),T}import{createHmac as ad,createSign as bp,timingSafeEqual as Pp}from"node:crypto";function Di(u){let g=u instanceof Date?u.getTime():u;if(!Number.isFinite(g))throw TypeError("Media access timestamp must be finite");return Math.floor(g/1000)}function ld(u){return Buffer.from(u).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function Tp(u){return Buffer.from(u).toString("base64url")}function ud(u,g=!1){if(!u||/[\r\n]/.test(u))throw TypeError("Media resource is invalid");let h=g?u.replaceAll("*","wildcard"):u,S=new URL(h);if(!["http:","https:"].includes(S.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!g&&u.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function dd(u,g){let h=bp("RSA-SHA1");return h.update(u),h.end(),ld(h.sign(g))}function pd(u){ud(u.resource,!0);let h={DateLessThan:{"AWS:EpochTime":Di(u.expiresAt)}};if(u.activeAt!==void 0)h.DateGreaterThan={"AWS:EpochTime":Di(u.activeAt)};if(u.ipAddress)h.IpAddress={"AWS:SourceIp":u.ipAddress};return JSON.stringify({Statement:[{Resource:u.resource,Condition:h}]})}function dR(u,g,h){ud(u);let S=Di(g),A=u.includes("?")?"&":"?",T=pd({resource:u,expiresAt:g}),P=dd(T,h.privateKey);return`${u}${A}Expires=${S}&Signature=${encodeURIComponent(P)}&Key-Pair-Id=${encodeURIComponent(h.keyPairId)}`}function pR(u,g){let h=pd(u);return{"CloudFront-Key-Pair-Id":g.keyPairId,"CloudFront-Policy":ld(Buffer.from(h)),"CloudFront-Signature":dd(h,g.privateKey)}}function mR(u){if(!u.resource||/[\r\n]/.test(u.resource))throw TypeError("Media resource is invalid");let g=Tp(Buffer.from(JSON.stringify({resource:u.resource,expiresAt:Di(u.expiresAt),...u.keyId?{keyId:u.keyId}:{},...u.audience?{audience:u.audience}:{}}))),h=ad("sha256",u.secret).update(g).digest("base64url");return`${g}.${h}`}function gR(u,g){let[h,S,A]=u.split(".");if(!h||!S||A)return null;let T=ad("sha256",g.secret).update(h).digest(),P;try{P=Buffer.from(S,"base64url")}catch{return null}if(T.length!==P.length||!Pp(T,P))return null;try{let M=JSON.parse(Buffer.from(h,"base64url").toString("utf8")),W=Di(g.now??Date.now());if(!M.resource||!Number.isSafeInteger(M.expiresAt)||M.expiresAt<=W)return null;if(g.resource&&M.resource!==g.resource)return null;if(g.audience&&M.audience!==g.audience)return null;return M}catch{return null}}function fR(u,g=!1){let h=new URL(u,"https://media.invalid").pathname.toLowerCase(),S=/\.(?:m3u8|mpd|vtt|json)$/.test(h),A=/\.(?:key|license)$/.test(h)||h.includes("/keys/")||h.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":g&&(S||A)?"private, no-store":S?"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 hR(u){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(u.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(u.region))throw TypeError("Media bucket region is invalid");let g=u.prefix?`/${u.prefix.replace(/^\/+|\/+$/g,"")}`:"",h=u.protected??!1,S="public, max-age=31536000, immutable",A=h?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${u.bucket}.s3.${u.region}.amazonaws.com`,originPath:g,domain:u.domain,trustedKeyGroupIds:[...new Set(u.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:A,compress:!0,signed:h},{pathPattern:"*.mpd",cacheControl:A,compress:!0,signed:h},{pathPattern:"*.vtt",cacheControl:A,compress:!0,signed:h},{pathPattern:"*",cacheControl:S,compress:!1,signed:h}],responseHeaders:{"Access-Control-Allow-Headers":"Range, If-Range","Access-Control-Allow-Methods":"GET, HEAD, OPTIONS","Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":"Accept-Ranges, Content-Length, Content-Range, ETag","X-Content-Type-Options":"nosniff"}}}class wp{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;storageFailoverReplicas=[];constructor(u){this.config=u.config,this.environment=u.environment,this.builder=new Al(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let g=this.config.environments[this.environment]?.infrastructure;if(!g)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...g,compute:{...this.config.infrastructure?.compute,...g.compute},storage:{...this.config.infrastructure?.storage,...g.storage},functions:{...this.config.infrastructure?.functions,...g.functions},servers:{...this.config.infrastructure?.servers,...g.servers},databases:{...this.config.infrastructure?.databases,...g.databases},cdn:{...this.config.infrastructure?.cdn,...g.cdn},sftp:g.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...g.queues},redirects:{...this.config.infrastructure?.redirects,...g.redirects},realtime:{...this.config.infrastructure?.realtime,...g.realtime},cache:{...this.config.infrastructure?.cache,...g.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...g.fileSystem},email:{...this.config.infrastructure?.email,...g.email},search:{...this.config.infrastructure?.search,...g.search},ai:{...this.config.infrastructure?.ai,...g.ai}}}}shouldDeploy(u){if(u.environments&&!u.environments.includes(this.environment))return!1;if(u.requiresFeatures){let g=this.config.features||{};if(!u.requiresFeatures.every((S)=>g[S]===!0))return!1}if(u.regions){let g=this.config.environments[this.environment]?.region||this.config.project.region;if(!u.regions.includes(g))return!1}if(u.condition&&typeof u.condition==="function")return u.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let u=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,g=Number(u||3008);return Number.isFinite(g)&&g>0?g:3008}defaultComputeCachePathPatterns(){return["/api/*","/auth/*","/publisher/api/*","/publisher/*","/publish","/publish/*","/analytics/*","/packages/*","/npm/*","/zig/*","/php/*","/commits/*","/health","/dashboard/*","/search","/login","/logout","/signup","/account","/account/*"]}shouldRouteStorageBucketToCompute(u,g){return u==="public"||g.routeCompute===!0}storageBucketName(u,g,h){return this.mergedConfig.infrastructure?.storage?.[h]?.bucket??`${u}-${g}-${h}`}fileSystemLogicalId(u,g,h){return t(r({slug:`${u}-${h}`,environment:g,resourceType:"efs"}))}resolveSftpStorage(u,g,h){let S=u.storage;if(S?.type==="efs"&&S.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[S.fileSystem])throw Error(`sftp: storage.fileSystem "${S.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(g,h,S.fileSystem)},posixProfile:S.posixProfile}}if(S?.type==="s3"&&S.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[S.storageBucket])throw Error(`sftp: storage.storageBucket "${S.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(g,h,S.storageBucket)}}return}resolveComputeCachePathPatterns(u){if(u&&u.length>0)return u;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(u,g){return{PathPattern:u,TargetOriginId:g,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD"],Compress:!0,CachePolicyId:"4135ea2d-6df8-44a3-9df3-4b5a84be39ad",OriginRequestPolicyId:"b689b0a8-53d0-40ab-baf2-68738e2966ac"}}appendComputeAppOrigin(u,g,h,S,A,T){let P=this.serverEipLogicalIds.get("app"),M=this.serverEipLogicalIds.get("appInstance");if(!P)return;let W=`EC2-${S}-${A}-api`,le=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",K=le==="us-east-1"?".compute-1.amazonaws.com":`.${le}.compute.amazonaws.com`,Ct={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:P}]}]},K]]},Tt=this.resolveApiOriginPort();if(u.push({Id:W,DomainName:Ct,CustomOriginConfig:{HTTPPort:Tt,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),h.push(P),M)h.push(M);for(let He of T)g.push(this.createComputeCacheBehavior(He,W))}buildCaddyfile(u){let g=u.filter(([,A])=>typeof A.domain==="string"&&A.domain&&typeof A.port==="number");if(g.length===0)return;let h=new Map;for(let[,A]of g){let T=h.get(A.domain)??[];T.push({port:A.port,path:A.path}),h.set(A.domain,T)}let S=[];for(let[A,T]of h){let M=[...T].sort((W,le)=>{let K=!W.path||W.path==="/",Ct=!le.path||le.path==="/";if(K&&!Ct)return 1;if(!K&&Ct)return-1;return(le.path?.length??0)-(W.path?.length??0)}).map((W)=>{let le=!W.path||W.path==="/",K=`reverse_proxy localhost:${W.port}`;return le?` handle {
2
+ ${K}
3
+ }`:` handle ${W.path} {
4
+ ${K}
5
+ }`});S.push(`${A} {
6
6
  ${M.join(`
7
7
  `)}
8
- }`)}return y.join(`
8
+ }`)}return S.join(`
9
9
 
10
- `)}normalizeMountPath(u){let g=u?.mountPath||u?.path;if(!g||g==="/")return;let h=`/${g}`.replace(/\/+/g,"/").replace(/\/$/,"");return h==="/"?void 0:h}storageBucketLogicalId(u,g,h){return`${u}-${g}-s3-${h}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((y)=>y.charAt(0).toUpperCase()+y.slice(1)).join("")}pathMountRewriteFunctionCode(u,g="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(u)}; var rewriteStyle = ${JSON.stringify(g)}; var uri = request.uri; if (uri === prefix) { uri = '/'; } else if (uri.indexOf(prefix + '/') === 0) { uri = uri.substring(prefix.length); } if (uri === '' || uri === '/') { request.uri = '/index.html'; return request; } if (uri.endsWith('/')) { request.uri = uri + 'index.html'; return request; } var lastSegment = uri.substring(uri.lastIndexOf('/') + 1); if (lastSegment.indexOf('.') === -1) { request.uri = rewriteStyle === 'flat' ? uri + '.html' : uri + '/index.html'; return request; } request.uri = uri; return request; }`}generate(){let u=this.mergedConfig.project.slug,g=this.environment,h=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),y=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),R=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(u,g),this.generateContainerInfrastructure(u,g);if(h)this.generateServerless(u,g);if(y)this.generateServer(u,g);if(R)this.generateComputeApp(u,g);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(u,g);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(u,g),this.storageFailoverReplicas.length>0)this.builder.addMetadata(Il,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(u){}generateNetworkInfrastructure(u,g){if(this.builder.hasResource("VPC"))return;let y=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:R,logicalId:v}=S.createVpc({slug:u,environment:g,cidr:y,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",R);let P=`${u}${g}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${u}-${g}-igw`},{Key:"Environment",Value:g}]}});let M=`${u}${g}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(M,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:P}}});let V=`${u}${g}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(V,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${u}-${g}-public-rt`},{Key:"Environment",Value:g}]}}),this.builder.addResource(`${u}${g}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:V},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:P}},DependsOn:M});let Ae=this.mergedConfig.environments[g]?.region||this.mergedConfig.project.region||"us-east-1",ye=["a","b"];for(let At=0;At<2;At++){let Tt=`PublicSubnet${At+1}`;this.builder.addResource(Tt,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${At}.0/24`,AvailabilityZone:`${Ae}${ye[At]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${u}-${g}-public-${ye[At]}`},{Key:"Environment",Value:g}]}}),this.builder.addResource(`${Tt}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:Tt},RouteTableId:{Ref:V}}})}}generateContainerInfrastructure(u,g){let h=this.mergedConfig.infrastructure?.containers;if(!h)return;let y=this.mergedConfig.infrastructure?.loadBalancer,R=this.mergedConfig.infrastructure?.ssl,v=this.mergedConfig.infrastructure?.dns,P;if(R?.enabled&&R.domains?.length)if(R.certificateArn);else{let ye=R.domains[0],At=R.domains.slice(1).map((Ue)=>{if(Ue.includes(".")&&Ue.endsWith(ye))return Ue.replace(`.${ye}`,"");return Ue}),{certificate:Tt,logicalId:Je}=E.createCertificate({domain:ye,subdomains:At,slug:u,environment:g,validationMethod:"DNS",hostedZoneId:v?.hostedZoneId});P=Je,this.builder.addResource(Je,Tt)}let M="ECSCluster";this.builder.addResource(M,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${u}-${g}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${u}-${g}`},{Key:"Environment",Value:g}]}});let V=`${u}${g}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(V,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${u}-${g}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0",Description:"HTTP"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${g}-alb-sg`},{Key:"Environment",Value:g}]}});let Ae=`${u}${g}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[ye,At]of Object.entries(h)){let Tt=At.port||3000;this.builder.addResource(Ae,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${u}-${g}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:Tt,ToPort:Tt,SourceSecurityGroupId:{Ref:V},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${g}-ecs-sg`},{Key:"Environment",Value:g}]}});let Je=`${u}${g}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Je,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-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 Ue=`${u}${g}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ue,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-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 je=`${u}${g}${ye}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),K=`/ecs/${u}-${g}-${ye}`;this.builder.addResource(je,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:K,RetentionInDays:30}});let St=`${u}${g}${ye}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),z=String(At.cpu||512),Xe=String(At.memory||1024);this.builder.addResource(St,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${g}-${ye}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:z,Memory:Xe,ExecutionRoleArn:{"Fn::GetAtt":[Je,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[Ue,"Arn"]},ContainerDefinitions:[{Name:ye,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${u}:latest`},Essential:!0,PortMappings:[{ContainerPort:Tt,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":K,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":ye}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${Tt}${At.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${g}-${ye}`},{Key:"Environment",Value:g}]},DependsOn:[Je,Ue,je]});let bt=`${u}${g}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(y?.enabled!==!1){this.builder.addResource(bt,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${u}-${g}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:V}],Tags:[{Key:"Name",Value:`${u}-${g}-alb`},{Key:"Environment",Value:g}]}});let vt=`${u}${g}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),Et=y?.healthCheck?.path||At.healthCheck||"/health";this.builder.addResource(vt,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${u}-${g}-tg`,Port:Tt,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:Et,HealthCheckIntervalSeconds:y?.healthCheck?.interval||30,HealthyThresholdCount:y?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:y?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${u}-${g}-tg`},{Key:"Environment",Value:g}]}});let Ht=`${u}${g}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(R?.enabled&&R?.redirectHttp)this.builder.addResource(Ht,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:bt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(Ht,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:bt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:vt}}]}});if(R?.enabled){let Yt=R.certificateArn||(P?{Ref:P}:void 0);if(Yt){let tr=`${u}${g}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(tr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:bt},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Yt}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:vt}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Zt=`${u}${g}${ye}Service`.replace(/[^a-zA-Z0-9]/g,""),er=At.desiredCount||1;this.builder.addResource(Zt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${g}-${ye}`,Cluster:{Ref:M},TaskDefinition:{Ref:St},DesiredCount:er,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Ae}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:ye,ContainerPort:Tt,TargetGroupArn:{Ref:vt}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${u}-${g}-${ye}`},{Key:"Environment",Value:g}]},DependsOn:[St,Ht,vt]});let Tr=At.autoScaling;if(Tr){let Yt=`${u}${g}${ye}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Yt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:Tr.max||10,MinCapacity:Tr.min||1,ResourceId:{"Fn::Sub":`service/\${${M}}/${u}-${g}-${ye}`},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:Zt}),Tr.targetCpuUtilization)this.builder.addResource(`${u}${g}${ye}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${g}-${ye}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Yt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:Tr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(Tr.targetMemoryUtilization)this.builder.addResource(`${u}${g}${ye}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${g}-${ye}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Yt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:Tr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(v?.domain&&v?.hostedZoneId)this.builder.addResource(`${u}${g}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:v.hostedZoneId,Name:`api.${v.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[bt,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[bt,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[M,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${u}-${g}-${ye}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[bt,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let vt=`${u}${g}${ye}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(vt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${g}-${ye}`,Cluster:{Ref:M},TaskDefinition:{Ref:St},DesiredCount:At.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Ae}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${u}-${g}-${ye}`},{Key:"Environment",Value:g}]},DependsOn:[St]})}break}}generateServerless(u,g){if(this.mergedConfig.infrastructure?.functions)for(let[h,y]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(y))continue;let{role:R,logicalId:v}=ge.createRole({slug:u,environment:g,roleName:`${u}-${g}-${h}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(v,R);let{lambdaFunction:P,logicalId:M}=a.createLambdaFunction({slug:u,environment:g,functionName:`${u}-${g}-${h}`,handler:y.handler||"index.handler",runtime:y.runtime||"nodejs20.x",code:{zipFile:y.code||"export const handler = async () => ({ statusCode: 200 });"},role:v,timeout:y.timeout,memorySize:y.memorySize});this.builder.addResource(M,P)}if(this.mergedConfig.infrastructure?.api){let{restApi:h,logicalId:y}=El.createRestApi({slug:u,environment:g,apiName:`${u}-${g}-api`});this.builder.addResource(y,h)}}generateServer(u,g){if(!this.mergedConfig.infrastructure?.servers)return;let h=this.mergedConfig.infrastructure.servers,y=this.mergedConfig.infrastructure?.compute,R=this.mergedConfig.infrastructure?.ssl;if(Object.values(h).some((P)=>!P.privateNetwork||P.privateNetwork==="create"))this.generateNetworkInfrastructure(u,g);for(let[P,M]of Object.entries(h)){let V=M.instanceType||M.size||y?.size,ye=(V?a.InstanceSize.specs[V]:void 0)?.instanceType||V||"t3.micro",At=M.type||"app",Tt=M.userData||M.startupScript;if(!Tt)Tt=a.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:M.bunVersion||"latest",webServer:"none",domain:M.domain,enableSsl:!!R?.enabled,sslEmail:R?.letsEncrypt?.email,installRedis:At==="cache",installDatabaseClients:!!M.database});let Je=M.privateNetwork&&M.privateNetwork!=="create"?M.privateNetwork:{Ref:"VPC"},Ue=M.subnet||{Ref:"PublicSubnet1"},K=!!this.mergedConfig.infrastructure?.email?.server?.enabled,St=[22,80,443,this.resolveApiOriginPort()];if(K)St.push(25,465,587,143,993);let z=a.createServerModeStack({slug:`${u}-${P}`,environment:g,vpcId:Je,subnetId:Ue,instanceType:ye,keyName:M.keyName||`${u}-${g}`,domain:M.domain,userData:Tt,volumeSize:M.diskSize||20,imageId:M.image,allowedPorts:St});for(let[Xe,bt]of Object.entries(z.resources))this.builder.addResource(Xe,bt);this.serverEipLogicalIds.set(P,z.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${P}Instance`,z.outputs.instanceLogicalId),this.builder.addOutput(`${P}InstanceId`,{Value:{Ref:z.outputs.instanceLogicalId},Description:`Instance ID for ${P} server`}),this.builder.addOutput(`${P}PublicIp`,{Value:{Ref:z.outputs.eipLogicalId},Description:`Public IP for ${P} server`})}}generateComputeApp(u,g){let h=this.mergedConfig.infrastructure?.compute;if(!h)return;let y=this.mergedConfig.sites||{},R=Object.entries(y),P=this.mergedConfig.infrastructure?.dns?.domain,M=this.mergedConfig.infrastructure?.database,V=h.size,ye=(V?a.InstanceSize.specs[V]:void 0)?.instanceType||V||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(u,g);let At=this.buildCaddyfile(R),Tt=a.UserData.generateBunAppScript({runtime:h.runtime||"bun",runtimeVersion:h.runtimeVersion||"latest",systemPackages:h.systemPackages,database:M,caddyfile:At}),Je=oo(h.appUpdates),Ue=Je.length>0?`${Tt}
11
- ${Je.join(`
10
+ `)}normalizeMountPath(u){let g=u?.mountPath||u?.path;if(!g||g==="/")return;let h=`/${g}`.replace(/\/+/g,"/").replace(/\/$/,"");return h==="/"?void 0:h}storageBucketLogicalId(u,g,h){return`${u}-${g}-s3-${h}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((S)=>S.charAt(0).toUpperCase()+S.slice(1)).join("")}pathMountRewriteFunctionCode(u,g="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(u)}; var rewriteStyle = ${JSON.stringify(g)}; var uri = request.uri; if (uri === prefix) { uri = '/'; } else if (uri.indexOf(prefix + '/') === 0) { uri = uri.substring(prefix.length); } if (uri === '' || uri === '/') { request.uri = '/index.html'; return request; } if (uri.endsWith('/')) { request.uri = uri + 'index.html'; return request; } var lastSegment = uri.substring(uri.lastIndexOf('/') + 1); if (lastSegment.indexOf('.') === -1) { request.uri = rewriteStyle === 'flat' ? uri + '.html' : uri + '/index.html'; return request; } request.uri = uri; return request; }`}generate(){let u=this.mergedConfig.project.slug,g=this.environment,h=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),S=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),A=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(u,g),this.generateContainerInfrastructure(u,g);if(h)this.generateServerless(u,g);if(S)this.generateServer(u,g);if(A)this.generateComputeApp(u,g);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(u,g);if(this.storageFailoverReplicas=[],this.generateSharedInfrastructure(u,g),this.storageFailoverReplicas.length>0)this.builder.addMetadata(bl,this.storageFailoverReplicas);if(this.config.tags)this.applyGlobalTags(this.config.tags);return this}getStorageFailoverReplicas(){return[...this.storageFailoverReplicas]}applyGlobalTags(u){}generateNetworkInfrastructure(u,g){if(this.builder.hasResource("VPC"))return;let S=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:A,logicalId:T}=I.createVpc({slug:u,environment:g,cidr:S,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",A);let P=`${u}${g}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${u}-${g}-igw`},{Key:"Environment",Value:g}]}});let M=`${u}${g}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(M,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:P}}});let W=`${u}${g}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(W,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${u}-${g}-public-rt`},{Key:"Environment",Value:g}]}}),this.builder.addResource(`${u}${g}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:W},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:P}},DependsOn:M});let le=this.mergedConfig.environments[g]?.region||this.mergedConfig.project.region||"us-east-1",K=["a","b"];for(let Ct=0;Ct<2;Ct++){let Tt=`PublicSubnet${Ct+1}`;this.builder.addResource(Tt,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${Ct}.0/24`,AvailabilityZone:`${le}${K[Ct]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${u}-${g}-public-${K[Ct]}`},{Key:"Environment",Value:g}]}}),this.builder.addResource(`${Tt}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:Tt},RouteTableId:{Ref:W}}})}}generateContainerInfrastructure(u,g){let h=this.mergedConfig.infrastructure?.containers;if(!h)return;let S=this.mergedConfig.infrastructure?.loadBalancer,A=this.mergedConfig.infrastructure?.ssl,T=this.mergedConfig.infrastructure?.dns,P;if(A?.enabled&&A.domains?.length)if(A.certificateArn);else{let K=A.domains[0],Ct=A.domains.slice(1).map((Se)=>{if(Se.includes(".")&&Se.endsWith(K))return Se.replace(`.${K}`,"");return Se}),{certificate:Tt,logicalId:He}=v.createCertificate({domain:K,subdomains:Ct,slug:u,environment:g,validationMethod:"DNS",hostedZoneId:T?.hostedZoneId});P=He,this.builder.addResource(He,Tt)}let M="ECSCluster";this.builder.addResource(M,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${u}-${g}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${u}-${g}`},{Key:"Environment",Value:g}]}});let W=`${u}${g}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(W,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${u}-${g}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0",Description:"HTTP"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${g}-alb-sg`},{Key:"Environment",Value:g}]}});let le=`${u}${g}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[K,Ct]of Object.entries(h)){let Tt=Ct.port||3000;this.builder.addResource(le,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${u}-${g}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:Tt,ToPort:Tt,SourceSecurityGroupId:{Ref:W},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${g}-ecs-sg`},{Key:"Environment",Value:g}]}});let He=`${u}${g}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(He,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-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 Se=`${u}${g}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Se,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-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 Ie=`${u}${g}${K}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),z=`/ecs/${u}-${g}-${K}`;this.builder.addResource(Ie,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:z,RetentionInDays:30}});let Ye=`${u}${g}${K}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),V=String(Ct.cpu||512),Ke=String(Ct.memory||1024);this.builder.addResource(Ye,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${g}-${K}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:V,Memory:Ke,ExecutionRoleArn:{"Fn::GetAtt":[He,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[Se,"Arn"]},ContainerDefinitions:[{Name:K,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${u}:latest`},Essential:!0,PortMappings:[{ContainerPort:Tt,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":z,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":K}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${Tt}${Ct.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${g}-${K}`},{Key:"Environment",Value:g}]},DependsOn:[He,Se,Ie]});let yt=`${u}${g}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(S?.enabled!==!1){this.builder.addResource(yt,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${u}-${g}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:W}],Tags:[{Key:"Name",Value:`${u}-${g}-alb`},{Key:"Environment",Value:g}]}});let It=`${u}${g}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),vt=S?.healthCheck?.path||Ct.healthCheck||"/health";this.builder.addResource(It,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${u}-${g}-tg`,Port:Tt,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:vt,HealthCheckIntervalSeconds:S?.healthCheck?.interval||30,HealthyThresholdCount:S?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:S?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${u}-${g}-tg`},{Key:"Environment",Value:g}]}});let Ht=`${u}${g}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(A?.enabled&&A?.redirectHttp)this.builder.addResource(Ht,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:yt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(Ht,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:yt},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:It}}]}});if(A?.enabled){let Yt=A.certificateArn||(P?{Ref:P}:void 0);if(Yt){let tr=`${u}${g}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(tr,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:yt},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:Yt}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:It}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let Zt=`${u}${g}${K}Service`.replace(/[^a-zA-Z0-9]/g,""),er=Ct.desiredCount||1;this.builder.addResource(Zt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${g}-${K}`,Cluster:{Ref:M},TaskDefinition:{Ref:Ye},DesiredCount:er,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:le}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:K,ContainerPort:Tt,TargetGroupArn:{Ref:It}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${u}-${g}-${K}`},{Key:"Environment",Value:g}]},DependsOn:[Ye,Ht,It]});let Tr=Ct.autoScaling;if(Tr){let Yt=`${u}${g}${K}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Yt,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:Tr.max||10,MinCapacity:Tr.min||1,ResourceId:{"Fn::Sub":`service/\${${M}}/${u}-${g}-${K}`},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:Zt}),Tr.targetCpuUtilization)this.builder.addResource(`${u}${g}${K}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${g}-${K}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Yt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:Tr.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(Tr.targetMemoryUtilization)this.builder.addResource(`${u}${g}${K}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${g}-${K}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Yt},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:Tr.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(T?.domain&&T?.hostedZoneId)this.builder.addResource(`${u}${g}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:T.hostedZoneId,Name:`api.${T.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[yt,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[yt,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[M,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${u}-${g}-${K}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[yt,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let It=`${u}${g}${K}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(It,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${g}-${K}`,Cluster:{Ref:M},TaskDefinition:{Ref:Ye},DesiredCount:Ct.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:le}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${u}-${g}-${K}`},{Key:"Environment",Value:g}]},DependsOn:[Ye]})}break}}generateServerless(u,g){if(this.mergedConfig.infrastructure?.functions)for(let[h,S]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(S))continue;let{role:A,logicalId:T}=me.createRole({slug:u,environment:g,roleName:`${u}-${g}-${h}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(T,A);let{lambdaFunction:P,logicalId:M}=a.createLambdaFunction({slug:u,environment:g,functionName:`${u}-${g}-${h}`,handler:S.handler||"index.handler",runtime:S.runtime||"nodejs20.x",code:{zipFile:S.code||"export const handler = async () => ({ statusCode: 200 });"},role:T,timeout:S.timeout,memorySize:S.memorySize});this.builder.addResource(M,P)}if(this.mergedConfig.infrastructure?.api){let{restApi:h,logicalId:S}=vl.createRestApi({slug:u,environment:g,apiName:`${u}-${g}-api`});this.builder.addResource(S,h)}}generateServer(u,g){if(!this.mergedConfig.infrastructure?.servers)return;let h=this.mergedConfig.infrastructure.servers,S=this.mergedConfig.infrastructure?.compute,A=this.mergedConfig.infrastructure?.ssl;if(Object.values(h).some((P)=>!P.privateNetwork||P.privateNetwork==="create"))this.generateNetworkInfrastructure(u,g);for(let[P,M]of Object.entries(h)){let W=M.instanceType||M.size||S?.size,K=(W?a.InstanceSize.specs[W]:void 0)?.instanceType||W||"t3.micro",Ct=M.type||"app",Tt=M.userData||M.startupScript;if(!Tt)Tt=a.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:M.bunVersion||"latest",webServer:"none",domain:M.domain,enableSsl:!!A?.enabled,sslEmail:A?.letsEncrypt?.email,installRedis:Ct==="cache",installDatabaseClients:!!M.database});let He=M.privateNetwork&&M.privateNetwork!=="create"?M.privateNetwork:{Ref:"VPC"},Se=M.subnet||{Ref:"PublicSubnet1"},z=!!this.mergedConfig.infrastructure?.email?.server?.enabled,Ye=[22,80,443,this.resolveApiOriginPort()];if(z)Ye.push(25,465,587,143,993);let V=a.createServerModeStack({slug:`${u}-${P}`,environment:g,vpcId:He,subnetId:Se,instanceType:K,keyName:M.keyName||`${u}-${g}`,domain:M.domain,userData:Tt,volumeSize:M.diskSize||20,imageId:M.image,allowedPorts:Ye});for(let[Ke,yt]of Object.entries(V.resources))this.builder.addResource(Ke,yt);this.serverEipLogicalIds.set(P,V.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${P}Instance`,V.outputs.instanceLogicalId),this.builder.addOutput(`${P}InstanceId`,{Value:{Ref:V.outputs.instanceLogicalId},Description:`Instance ID for ${P} server`}),this.builder.addOutput(`${P}PublicIp`,{Value:{Ref:V.outputs.eipLogicalId},Description:`Public IP for ${P} server`})}}generateComputeApp(u,g){let h=this.mergedConfig.infrastructure?.compute;if(!h)return;let S=this.mergedConfig.sites||{},A=Object.entries(S),P=this.mergedConfig.infrastructure?.dns?.domain,M=this.mergedConfig.infrastructure?.database,W=h.size,K=(W?a.InstanceSize.specs[W]:void 0)?.instanceType||W||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(u,g);let Ct=this.buildCaddyfile(A),Tt=a.UserData.generateBunAppScript({runtime:h.runtime||"bun",runtimeVersion:h.runtimeVersion||"latest",systemPackages:h.systemPackages,database:M,caddyfile:Ct}),He=ao(h.appUpdates),Se=He.length>0?`${Tt}
11
+ ${He.join(`
12
12
  `)}
13
- `:Tt,je=R.map(([,Et])=>Et.port).filter((Et)=>typeof Et==="number"&&![80,443].includes(Et)),K=this.resolveApiOriginPort(),St=`${u}${g}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),z=`${u}-${g}-deploy`;this.builder.addResource(St,{Type:"AWS::S3::Bucket",Properties:{BucketName:z,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"expire-old-releases",Status:"Enabled",ExpirationInDays:7,Prefix:"releases/"}]},Tags:[{Key:"Project",Value:u},{Key:"Environment",Value:g},{Key:"ManagedBy",Value:"ts-cloud"}]}});let Xe=a.createServerModeStack({slug:`${u}-app`,environment:g,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:ye,keyName:h.allowSsh?`${u}-${g}`:void 0,domain:P,userData:Ue,volumeSize:h.disk?.size||20,imageId:h.image,allowedPorts:[...h.allowSsh?[22]:[],80,443,K,...je]}),bt=Xe.resources[Xe.outputs.instanceLogicalId];if(bt?.Properties){let Et=bt.Properties.Tags||[];bt.Properties.Tags=[...Et,{Key:"Project",Value:u},{Key:"Environment",Value:g},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let vt=Xe.resources[Xe.outputs.roleLogicalId];if(vt?.Properties)vt.Properties.Policies=vt.Properties.Policies||[],vt.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${z}`,`arn:aws:s3:::${z}/*`]}]}});for(let[Et,Ht]of Object.entries(Xe.resources))this.builder.addResource(Et,Ht);this.builder.addOutput("deployBucketName",{Value:{Ref:St},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:Xe.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:Xe.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",Xe.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",Xe.outputs.instanceLogicalId)}jumpBoxFileSystemId(u,g,h){let y=Object.keys(this.mergedConfig.infrastructure?.fileSystem??{});if(typeof h==="string")return y.includes(h)?{Ref:this.fileSystemLogicalId(u,g,h)}:h;if(y.length===1)return{Ref:this.fileSystemLogicalId(u,g,y[0])};throw Error(y.length===0?"infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares no file system. Declare one, or set mountEfs to an EFS id.":`infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares ${y.length} (${y.join(", ")}). Set mountEfs to the name of the one to mount.`)}generateJumpBox(u,g){let h=this.mergedConfig.infrastructure?.jumpBox;if(!h)return;let y=h===!0?{}:h;if(y.enabled===!1)return;this.generateNetworkInfrastructure(u,g);let R=y.size||"micro",P=a.InstanceSize.specs[R]?.instanceType||R||"t3.micro",M=a.createJumpBox({slug:u,environment:g,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:y.keyName,instanceType:P,allowedCidrs:y.allowedCidrs,mountEfs:y.mountEfs?{fileSystemId:this.jumpBoxFileSystemId(u,g,y.mountEfs),mountPath:y.mountPath||"/mnt/efs"}:void 0,databaseTools:y.databaseTools});for(let[V,Ae]of Object.entries(M.resources))this.builder.addResource(V,Ae);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:M.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(u,g){let h=this.mergedConfig.infrastructure?.ssl,y=this.mergedConfig.infrastructure?.dns,R=y?.domain,v=y?.hostedZoneId,P=[],M,V;if(h?.certificateArn)V=h.certificateArn;else if(h?.enabled&&R&&v){let je=h.domains||[R],K=je[0],St=je.slice(1).map((bt)=>{if(bt.includes(".")&&bt.endsWith(K))return bt.replace(`.${K}`,"");return bt}),{certificate:z,logicalId:Xe}=E.createCertificate({domain:K,subdomains:St,slug:u,environment:g,validationMethod:"DNS",hostedZoneId:v});M=Xe,this.builder.addResource(Xe,z)}if(this.mergedConfig.infrastructure?.storage){let je=Object.entries(this.mergedConfig.infrastructure.storage).some(([,z])=>z.website),K;if(je&&(M||V))K=`${u}${g}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(K,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${u}-${g}-s3-oac`,Description:`OAC for ${u} ${g} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let St=Object.entries(this.mergedConfig.infrastructure.storage).map(([z,Xe])=>({name:z,config:Xe,mountPath:this.normalizeMountPath(Xe),rewriteStyle:Xe.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(u,g,z)})).filter((z)=>z.name!=="public"&&z.config.website&&z.mountPath);for(let[z,Xe]of Object.entries(this.mergedConfig.infrastructure.storage)){let bt=!!(Xe.website&&K),vt=this.storageBucketName(u,g,z),{bucket:Et,logicalId:Ht}=_e.createBucket({slug:u,name:z,environment:g,bucketName:vt,versioning:Xe.versioning,encryption:Xe.encryption,public:bt?!1:Xe.public}),Zt=this.normalizeMountPath(Xe),er;if(Xe.failover){let Yt=`infrastructure.storage.${z}`;if(!bt||!R||Zt&&z!=="public")throw Error(`${Yt}.failover needs this bucket to be served by its own CloudFront distribution: a website bucket (website: true), not mounted under the path of another site, with infrastructure.dns.domain set and SSL configured (infrastructure.ssl.certificateArn, or ssl.enabled with dns.hostedZoneId).`);if(er=_m({failover:Xe.failover,primaryBucket:vt,primaryRegion:this.mergedConfig.project.region||"us-east-1",where:Yt}),er.replicate&&Et.Properties){let tr=`${Ht}FailoverReplicationRole`;this.builder.addResource(tr,$m({primaryBucket:vt,replicaBucket:er.replicaBucket}));let _r=Et.Properties;_r.VersioningConfiguration={Status:"Enabled"},_r.ReplicationConfiguration=Mm({replicaBucket:er.replicaBucket,roleArn:{"Fn::GetAtt":[tr,"Arn"]}})}}if(bt&&Et.Properties)Et.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(Ht,Et),Xe.website){let Yt=typeof Xe.website==="object"?Xe.website:{},tr=_e.enableWebsiteHosting(Et,Yt.indexDocument||"index.html",Yt.errorDocument);this.builder.addResource(Ht,tr)}let Tr=this.normalizeMountPath(Xe);if(bt&&K&&R&&!(Tr&&z!=="public")){let Yt=`${u}${g}${z}CDN`.replace(/[^a-zA-Z0-9]/g,""),tr=[];if(Xe.aliases&&Xe.aliases.length>0)tr.push(...Xe.aliases);else if(z==="public"){if(tr.push(R),h?.domains?.includes(`www.${R}`))tr.push(`www.${R}`)}else if(z==="docs")tr.push(`docs.${R}`);else if(z==="blog")tr.push(`blog.${R}`);let _r=typeof Xe.website==="object"?Xe.website:{},Kr=Xe.spa===!0,zr=_r.errorDocument||(Kr?"index.html":"404.html"),$r=[];if(Kr)$r.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else $r.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${zr}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${zr}`,ErrorCachingMinTTL:300});let qr=V&&tr.length>0?{AcmCertificateArn:V,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:M&&tr.length>0?{AcmCertificateArn:{Ref:M},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Qn=`S3-${u}-${g}-${z}`,oc=this.mergedConfig.project.region||"us-east-1",ti;if(!Kr)ti=`${u}${g}${z}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(ti,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${g}-${z}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${u} ${g} ${z} - 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 fi=[{Id:Qn,DomainName:{"Fn::Sub":`\${${Ht}}.s3.${oc}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:K}}],uo=[],cc=[];if(this.shouldRouteStorageBucketToCompute(z,Xe)){this.appendComputeAppOrigin(fi,uo,cc,u,g,this.resolveComputeCachePathPatterns(Xe.computeRoutes));for(let nr of St){let Co=`S3-${u}-${g}-${nr.name}`,_c=`${u}${g}${nr.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(_c,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${g}-${nr.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${u} ${g} ${nr.name} at ${nr.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(nr.mountPath,nr.rewriteStyle)}}),fi.push({Id:Co,DomainName:{"Fn::Sub":`\${${nr.logicalId}}.s3.${oc}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:K}}),cc.push(nr.logicalId,_c);for(let yp of[nr.mountPath,`${nr.mountPath}/*`])uo.push({PathPattern:yp,TargetOriginId:Co,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":[_c,"FunctionARN"]}}]})}}let po,od=Qn;if(er){let nr=`${Qn}-failover`;Object.assign(fi[0],er.primaryConnection),fi.push({Id:nr,DomainName:Lm(er.replicaBucket,er.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:K}}),po=gn({primaryOriginId:Qn,secondaryOriginId:nr,statusCodes:er.statusCodes}),od=po.Items[0].Id}let xc={Type:"AWS::CloudFront::Distribution",DependsOn:[Ht,K,...ti?[ti]:[],...cc],Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${g} ${z} site`,DefaultRootObject:"index.html",Origins:fi,...po?{OriginGroups:po}:{},DefaultCacheBehavior:{TargetOriginId:od,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...ti?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[ti,"FunctionARN"]}}]}:{}},...uo.length>0?{CacheBehaviors:uo}:{},...tr.length>0?{Aliases:tr}:{},ViewerCertificate:qr,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:$r}}};if(M)xc.DependsOn.push(M);if(er)Bt(xc.Properties.DistributionConfig,`infrastructure.storage.${z}`),this.storageFailoverReplicas.push({name:z,primaryBucket:vt,primaryRegion:oc,replicaBucket:er.replicaBucket,replicaRegion:er.replicaRegion,replicate:er.replicate,distributionArnOutput:`${z}CloudFrontDistributionArn`}),this.builder.addOutput(`${z}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`},Description:`CloudFront distribution ARN for ${z} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${z}FailoverBucketName`,{Value:er.replicaBucket,Description:`Failover replica bucket for ${z} (${er.replicaRegion}), outside this stack`});this.builder.addResource(Yt,xc);let fp=`${Ht}CloudFrontPolicy`;if(this.builder.addResource(fp,{Type:"AWS::S3::BucketPolicy",DependsOn:[Ht,Yt],Properties:{Bucket:{Ref:Ht},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${Ht}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(z,Xe))for(let nr of St){let Co=`${nr.logicalId}CloudFrontPolicy`;this.builder.addResource(Co,{Type:"AWS::S3::BucketPolicy",DependsOn:[nr.logicalId,Yt],Properties:{Bucket:{Ref:nr.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:::\${${nr.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`}}}}]}}})}if(tr.length>0)P.push({name:z,bucketLogicalId:Ht,distLogicalId:Yt,oacLogicalId:K,aliases:tr});this.builder.addOutput(`${z}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Yt,"DomainName"]},Description:`CloudFront domain for ${z}`}),this.builder.addOutput(`${z}CloudFrontDistributionId`,{Value:{Ref:Yt},Description:`CloudFront distribution ID for ${z}`})}if(this.builder.addOutput(`${z}BucketName`,{Value:{Ref:Ht},Description:`S3 bucket name for ${z}`}),z==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:Ht},Description:"Frontend S3 bucket name"});if(z==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:Ht},Description:"Documentation S3 bucket name"});if(z==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:Ht},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let je=this.mergedConfig.infrastructure.sftp,K=Cl.create({...je,storage:this.resolveSftpStorage(je,u,g)??je.storage,slug:u,environment:g});for(let[St,z]of Object.entries(K.resources))this.builder.addResource(St,z);this.builder.addOutput("SftpServerId",{Value:{Ref:K.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${K.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:K.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(v&&P.length>0)for(let{name:je,distLogicalId:K,aliases:St}of P)for(let z of St){let Xe=z.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Xe}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[K],Properties:{HostedZoneId:v,Name:z,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[K,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${Xe}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[K],Properties:{HostedZoneId:v,Name:z,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[K,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[je,K]of Object.entries(this.mergedConfig.infrastructure.databases))if(K.engine==="dynamodb"){let{table:St,logicalId:z}=gr.createTable({slug:u,environment:g,tableName:`${u}-${g}-${je}`,partitionKey:K.partitionKey||{name:"id",type:"S"},sortKey:K.sortKey});this.builder.addResource(z,St)}else if(K.engine==="postgres"){let{dbInstance:St,logicalId:z}=gr.createPostgres({slug:u,environment:g,dbInstanceIdentifier:`${u}-${g}-${je}`,masterUsername:K.username||"admin",masterUserPassword:K.password||"changeme123",allocatedStorage:K.storage||20,dbInstanceClass:K.instanceClass||"db.t3.micro"});this.builder.addResource(z,St)}else if(K.engine==="mysql"){let{dbInstance:St,logicalId:z}=gr.createMysql({slug:u,environment:g,dbInstanceIdentifier:`${u}-${g}-${je}`,masterUsername:K.username||"admin",masterUserPassword:K.password||"changeme123",allocatedStorage:K.storage||20,dbInstanceClass:K.instanceClass||"db.t3.micro"});this.builder.addResource(z,St)}}if(this.mergedConfig.infrastructure?.cdn)for(let[je,K]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!K.origin)continue;let St=typeof K.customDomain==="string"?K.customDomain:K.customDomain?.domain||K.domain,z=typeof K.customDomain==="object"?K.customDomain?.certificateArn:K.certificateArn,Xe=z||V,bt=`${u}${g}${je}CDN`.replace(/[^a-zA-Z0-9]/g,""),vt=`S3-${u}-${g}-${je}-cdn`,Et=[{Id:vt,DomainName:K.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:K.originShield?{Enabled:!0,OriginShieldRegion:K.originShieldRegion||this.mergedConfig.environments[g]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...ue(K,`infrastructure.cdn.${je}`)}],Ht=[],Zt=[],er=["GET","HEAD","OPTIONS"],Tr=vt,Yt;if(K.failoverOrigin){Nt(er,`the default cache behavior of infrastructure.cdn.${je}`);let zr=`${vt}-failover`,$r=typeof K.failoverOrigin==="string"?{domain:K.failoverOrigin}:K.failoverOrigin;if(!$r.domain)throw Error(`infrastructure.cdn.${je}.failoverOrigin.domain is required`);if($r.domain===K.origin)throw Error(`infrastructure.cdn.${je}: failoverOrigin must differ from origin (both are ${K.origin})`);Et.push({Id:zr,DomainName:$r.domain,OriginPath:$r.originPath||"",...Wo($r.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...ue($r,`infrastructure.cdn.${je}.failoverOrigin`)}),Yt=gn({primaryOriginId:vt,secondaryOriginId:zr,statusCodes:K.failoverStatusCodes}),Tr=Yt.Items[0].Id}else if(K.failoverStatusCodes)throw Error(`infrastructure.cdn.${je}: failoverStatusCodes needs failoverOrigin to fail over to`);if(K.routeCompute)this.appendComputeAppOrigin(Et,Ht,Zt,u,g,this.resolveComputeCachePathPatterns(K.computeRoutes));let tr=Xe&&St?{AcmCertificateArn:M&&!z?{Ref:M}:Xe,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},_r=[...Zt];if(M&&!z&&St)_r.push(M);let Kr={Type:"AWS::CloudFront::Distribution",..._r.length>0?{DependsOn:_r}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${g} ${je} CDN`,DefaultRootObject:"index.html",Origins:Et,...Yt?{OriginGroups:Yt}:{},DefaultCacheBehavior:{TargetOriginId:Tr,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:er,CachedMethods:["GET","HEAD","OPTIONS"],Compress:K.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...Ht.length>0?{CacheBehaviors:Ht}:{},...St&&Xe?{Aliases:[St]}:{},ViewerCertificate:tr,PriceClass:"PriceClass_100",HttpVersion:K.http3?"http2and3":"http2"}}};if(Bt(Kr.Properties.DistributionConfig,`infrastructure.cdn.${je}`),this.builder.addResource(bt,Kr),v&&St&&Xe){let zr=St.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${zr}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[bt,...M&&!z?[M]:[]],Properties:{HostedZoneId:v,Name:St,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[bt,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[je,K]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(K))continue;let{queue:St,logicalId:z}=X.createQueue({slug:u,environment:g,name:`${u}-${g}-${je}`,fifo:K.fifo,visibilityTimeout:K.visibilityTimeout,messageRetentionPeriod:K.messageRetentionPeriod,delaySeconds:K.delaySeconds,maxMessageSize:K.maxMessageSize,receiveMessageWaitTime:K.receiveMessageWaitTime,contentBasedDeduplication:K.contentBasedDeduplication,encrypted:K.encrypted,kmsKeyId:K.kmsKeyId});this.builder.addResource(z,St);let Xe;if(K.deadLetterQueue){let{deadLetterQueue:bt,updatedSourceQueue:vt,deadLetterLogicalId:Et}=X.createDeadLetterQueue(z,{slug:u,environment:g,maxReceiveCount:K.maxReceiveCount});Xe=Et,this.builder.addResource(Et,bt);let Zt=this.builder.getResources()[z];if(Zt?.Properties)Zt.Properties.RedrivePolicy=vt.Properties?.RedrivePolicy}if(K.trigger){let bt=K.trigger,vt=`${u}${g}${bt.functionName}`.replace(/[^a-zA-Z0-9]/g,""),Et={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[z,"Arn"]},FunctionName:{Ref:vt},BatchSize:bt.batchSize||10,MaximumBatchingWindowInSeconds:bt.batchWindow||0,Enabled:!0,...bt.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...bt.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:bt.maxConcurrency}},...bt.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(bt.filterPattern)}]}}},DependsOn:[z,vt]};this.builder.addResource(`${z}Trigger`,Et)}if(K.alarms?.enabled){let bt=K.alarms,vt=bt.notificationTopicArn;if(!vt&&bt.notificationEmails?.length){let Zt=`${z}AlarmTopic`;this.builder.addResource(Zt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${g}-${je}-alarms`,DisplayName:`${je} Queue Alarms`}}),bt.notificationEmails.forEach((er,Tr)=>{this.builder.addResource(`${Zt}Sub${Tr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Zt},Protocol:"email",Endpoint:er}})}),vt={Ref:Zt}}let Et=bt.queueDepthThreshold||1000;this.builder.addResource(`${z}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-${je}-queue-depth`,AlarmDescription:`Queue ${je} depth exceeds ${Et} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:Et,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[z,"QueueName"]}}],...vt&&{AlarmActions:[vt],OKActions:[vt]}}});let Ht=bt.messageAgeThreshold||3600;if(this.builder.addResource(`${z}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-${je}-message-age`,AlarmDescription:`Queue ${je} oldest message exceeds ${Ht} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:Ht,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[z,"QueueName"]}}],...vt&&{AlarmActions:[vt],OKActions:[vt]}}}),Xe&&bt.dlqAlarm!==!1)this.builder.addResource(`${Xe}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-${je}-dlq-messages`,AlarmDescription:`Dead letter queue for ${je} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[Xe,"QueueName"]}}],...vt&&{AlarmActions:[vt]}}})}if(K.subscribe){let bt=K.subscribe,vt=bt.topicArn;if(!vt&&bt.topicName)vt={Ref:bt.topicName};if(vt){this.builder.addResource(`${z}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:z}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[z,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":vt}}}]}}});let Et={TopicArn:vt,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[z,"Arn"]},RawMessageDelivery:bt.rawMessageDelivery||!1};if(bt.filterPolicy)Et.FilterPolicy=bt.filterPolicy,Et.FilterPolicyScope=bt.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${z}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:Et,DependsOn:`${z}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(u,g);else this.generateRealtimeResources(u,g);let Ae=this.mergedConfig.infrastructure?.redirects;if(Ae){let je=Ae.target||this.mergedConfig.infrastructure?.dns?.domain||"",K=Ae.protocol||"https";if(Ae.domains?.length&&je)for(let St of Ae.domains){let{bucket:z,bucketPolicy:Xe,logicalId:bt,policyLogicalId:vt}=Ot.createDomainRedirectBucket({slug:u,environment:g,sourceDomain:St,targetDomain:je,protocol:K});this.builder.addResource(bt,z),this.builder.addResource(vt,Xe)}if(Ae.paths&&Object.keys(Ae.paths).length>0){let St=Ot.fromMapping(Ae.paths,{statusCode:Ae.statusCode||301}),{function:z,logicalId:Xe}=Ot.createPathRedirectFunction({slug:u,environment:g,rules:St});this.builder.addResource(Xe,z)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[je,K]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:St,logicalId:z}=Yo.createAlarm({slug:u,environment:g,alarmName:`${u}-${g}-${je}`,metricName:K.metricName||"Errors",namespace:K.namespace||"AWS/Lambda",threshold:K.threshold||1,comparisonOperator:K.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(z,St)}let ye=this.mergedConfig.infrastructure?.cache;if(ye){let je=ye.type||"redis";if(je==="redis"){this.generateNetworkInfrastructure(u,g);let K=ye.redis||{},{replicationGroup:St,subnetGroup:z,logicalId:Xe,subnetGroupId:bt}=Xo.createRedis({slug:u,environment:g,nodeType:K.nodeType||ye.nodeType||"cache.t3.micro",engineVersion:K.engineVersion||"7.1",port:K.port||6379,numCacheClusters:K.numCacheNodes||2,automaticFailover:K.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:K.snapshotRetentionLimit||7,snapshotWindow:K.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Xe,St),z&&bt)this.builder.addResource(bt,z);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Xe,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[Xe,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(je==="memcached"){this.generateNetworkInfrastructure(u,g);let K=ye.elasticache||{},{cluster:St,subnetGroup:z,logicalId:Xe,subnetGroupId:bt}=Xo.createMemcached({slug:u,environment:g,nodeType:K.nodeType||ye.nodeType||"cache.t3.micro",engineVersion:K.engineVersion||"1.6.22",numCacheNodes:K.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Xe,St),z&&bt)this.builder.addResource(bt,z);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Xe,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let At=this.mergedConfig.infrastructure?.email;if(At){let je=At.domain||this.mergedConfig.infrastructure?.dns?.domain;if(je){let{emailIdentity:K,logicalId:St}=f.verifyDomain({domain:je,slug:u,environment:g,enableDkim:At.enableDkim!==!1,dkimKeyLength:At.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(St,K),At.configurationSet!==!1){let{configurationSet:bt,logicalId:vt}=f.createConfigurationSet({slug:u,environment:g});this.builder.addResource(vt,bt)}let z=At.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(z){if(At.enableDkim!==!1)for(let Zt=1;Zt<=3;Zt++){let er=`DkimRecord${Zt}${je.replace(/\./g,"")}`;this.builder.addResource(er,{Type:"AWS::Route53::RecordSet",DependsOn:[St],Properties:{HostedZoneId:z,Name:{"Fn::GetAtt":[St,`DkimDNSTokenName${Zt}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[St,`DkimDNSTokenValue${Zt}`]}]}})}let{record:bt,logicalId:vt}=f.createSpfRecord(je,z);this.builder.addResource(vt,bt);let{record:Et,logicalId:Ht}=f.createDmarcRecord(je,z,{policy:"none",reportingEmail:At.dmarcReportingEmail||`dmarc-reports@${je}`});this.builder.addResource(Ht,Et)}this.builder.addOutput("EmailDomain",{Value:je,Description:"SES verified email domain"});let Xe=At.server;if(Xe?.enabled&&z){let bt=this.mergedConfig.environments[g]?.region||this.mergedConfig.project.region||"us-east-1",vt=`${u}-${g}-email`,{role:Et,policy:Ht,roleLogicalId:Zt,policyLogicalId:er}=f.createEmailLambdaRole({slug:u,environment:g,s3BucketArn:`arn:aws:s3:::${vt}`,sesIdentityArn:`arn:aws:ses:${bt}:*:identity/${je}`});this.builder.addResource(Zt,Et),this.builder.addResource(er,Ht);let{function:Tr,permission:Yt,logicalId:tr,permissionLogicalId:_r}=f.createInboundEmailLambda({slug:u,environment:g,roleArn:{"Fn::GetAtt":[Zt,"Arn"]},s3BucketName:vt,organizedPrefix:"mailboxes/"});this.builder.addResource(tr,Tr),this.builder.addResource(_r,Yt);let Kr=f.createInboundEmailSetup({slug:u,environment:g,domain:je,s3BucketName:vt,s3KeyPrefix:"inbox/",region:bt,hostedZoneId:z,lambdaFunctionArn:{"Fn::GetAtt":[tr,"Arn"]}});for(let[$r,qr]of Object.entries(Kr.resources)){if(qr.Type==="AWS::SES::ReceiptRule")qr.DependsOn=[_r,tr];this.builder.addResource($r,qr)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:tr},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:vt,Description:"S3 bucket for email storage"});let zr=this.serverEipLogicalIds.get("app");if(zr&&z){let qr=`${Xe?.subdomain||"mail"}.${je}`,Qn=qr.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Qn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:z,Name:qr,Type:"A",TTL:"300",ResourceRecords:[{Ref:zr}]}})}this.builder.addOutput("MailHost",{Value:`mail.${je}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let Tt=this.mergedConfig.infrastructure?.search;if(Tt){let je=Tt.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(je)this.generateNetworkInfrastructure(u,g);let{domain:K,logicalId:St}=pr.createDomain({slug:u,environment:g,engineVersion:Tt.engineVersion||"OpenSearch_2.11",instanceType:Tt.instanceType||"t3.small.search",instanceCount:Tt.instanceCount||1,volumeSize:Tt.volumeSize||10,volumeType:Tt.volumeType||"gp3",dedicatedMaster:Tt.dedicatedMaster||!1,dedicatedMasterType:Tt.dedicatedMasterType,dedicatedMasterCount:Tt.dedicatedMasterCount||3,multiAz:Tt.multiAz||!1,encryption:Tt.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:Tt.advancedSecurity,autoTune:Tt.autoTune!==!1,vpc:je});this.builder.addResource(St,K),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[St,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[St,"Arn"]},Description:"OpenSearch domain ARN"})}let Je=this.mergedConfig.infrastructure?.fileSystem;if(Je&&Object.keys(Je).length>0){this.generateNetworkInfrastructure(u,g);for(let[je,K]of Object.entries(Je)){let{fileSystem:St,logicalId:z}=nt.createFileSystem({slug:`${u}-${je}`,environment:g,encrypted:K.encrypted!==!1,performanceMode:K.performanceMode||"generalPurpose",throughputMode:K.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(z,St);let{securityGroup:Xe,logicalId:bt}=nt.createEfsSecurityGroup({slug:`${u}-${je}`,environment:g,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(bt,Xe);let{mountTargets:vt,logicalIds:Et}=nt.createMultiAzMountTargets(z,{slug:`${u}-${je}`,environment:g,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:bt}});for(let Ht=0;Ht<vt.length;Ht++)this.builder.addResource(Et[Ht],vt[Ht]);this.builder.addOutput(`${je}FileSystemId`,{Value:{Ref:z},Description:`EFS file system ID for ${je}`})}}let Ue=this.mergedConfig.infrastructure?.ai;if(Ue){let je=Ue.service||"ecs",K=Ue.models||["*"],St=Ue.allowStreaming!==!1,z;if(je==="ecs")z=Le.enableBedrockForEcs({slug:u,environment:g,models:K,allowStreaming:St});else if(je==="ec2")z=Le.enableBedrockForEc2({slug:u,environment:g,models:K,allowStreaming:St});else if(je==="lambda")z=Le.enableBedrockForLambda({slug:u,environment:g,models:K,allowStreaming:St});else z=Le.createBedrockRole(je,{slug:u,environment:g,models:K,allowStreaming:St});if(this.builder.addResource(z.logicalId,z.role),Ue.allowAsync){let{policy:Xe,logicalId:bt}=Le.createBedrockPolicy({slug:u,environment:g,models:K,allowStreaming:St,allowAsync:!0});this.builder.addResource(bt,Xe)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[z.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(u,g){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let y=h.name||`${u}-${g}-realtime`,R=h.scaling||{},v=h.storage||{type:"dynamodb"},P=R.handlerMemory||256,M=R.handlerTimeout||30,V=`${u}${g}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),Ae=`${u}${g}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(v.type==="dynamodb"){let Et=v.dynamodb||{},Ht=Et.billingMode||"PAY_PER_REQUEST";this.builder.addResource(V,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${g}-realtime-connections`,BillingMode:Ht,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"},...Ht==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Et.readCapacity||5,WriteCapacityUnits:Et.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Ht==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Et.readCapacity||5,WriteCapacityUnits:Et.writeCapacity||5}},...Et.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${u}-${g}-realtime-connections`},{Key:"Environment",Value:g}]}}),this.builder.addResource(Ae,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${g}-realtime-channels`,BillingMode:Ht,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"},...Ht==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Et.readCapacity||5,WriteCapacityUnits:Et.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Ht==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:Et.readCapacity||5,WriteCapacityUnits:Et.writeCapacity||5}},Tags:[{Key:"Name",Value:`${u}-${g}-realtime-channels`},{Key:"Environment",Value:g}]}})}let ye=`${u}${g}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(ye,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-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":[V,"Arn"]},{"Fn::Sub":`\${${V}.Arn}/index/*`},{"Fn::GetAtt":[Ae,"Arn"]},{"Fn::Sub":`\${${Ae}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let At=`${u}${g}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),Tt=`${u}${g}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),Je=`${u}${g}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(At,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${g}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[ye,"Arn"]},MemorySize:P,Timeout:M,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:V},CHANNELS_TABLE:{Ref:Ae},ENVIRONMENT:g}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[ye,V]}),this.builder.addResource(Tt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${g}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[ye,"Arn"]},MemorySize:P,Timeout:M,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:V},CHANNELS_TABLE:{Ref:Ae},ENVIRONMENT:g}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[ye,V,Ae]}),this.builder.addResource(Je,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${g}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[ye,"Arn"]},MemorySize:P,Timeout:M,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:V},CHANNELS_TABLE:{Ref:Ae},ENVIRONMENT:g}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[ye,V,Ae]});let Ue=`${u}${g}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ue,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:y,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:y,Environment:g}}});let je=`${At}Permission`,K=`${Tt}Permission`,St=`${Je}Permission`;this.builder.addResource(je,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:At},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Ue}}/*/$connect`}}}),this.builder.addResource(K,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Tt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Ue}}/*/$disconnect`}}}),this.builder.addResource(St,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Je},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Ue}}/*/$default`}}});let z=`${Ue}ConnectInteg`,Xe=`${Ue}DisconnectInteg`,bt=`${Ue}MessageInteg`;this.builder.addResource(z,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Ue},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${At}.Arn}/invocations`}}}),this.builder.addResource(Xe,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Ue},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Tt}.Arn}/invocations`}}}),this.builder.addResource(bt,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Ue},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Je}.Arn}/invocations`}}}),this.builder.addResource(`${Ue}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Ue},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${z}}`}}}),this.builder.addResource(`${Ue}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Ue},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${Xe}}`}}}),this.builder.addResource(`${Ue}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Ue},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${bt}}`}}});let vt=`${Ue}Stage`;if(this.builder.addResource(vt,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Ue},StageName:g,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:R.messagesPerSecond||1000,ThrottlingRateLimit:R.messagesPerSecond||1000}}}),h.monitoring?.enabled){let Et=h.monitoring,Ht=Et.notificationTopicArn;if(!Ht&&Et.notificationEmails?.length){let Zt=`${Ue}AlarmTopic`;this.builder.addResource(Zt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${g}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),Et.notificationEmails.forEach((er,Tr)=>{this.builder.addResource(`${Zt}Sub${Tr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Zt},Protocol:"email",Endpoint:er}})}),Ht={Ref:Zt}}if(Et.connectionThreshold)this.builder.addResource(`${Ue}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${Et.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:Et.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Ue}}],...Ht&&{AlarmActions:[Ht]}}});if(Et.errorThreshold)this.builder.addResource(`${Ue}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${Et.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:Et.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Ue}}],...Ht&&{AlarmActions:[Ht]}}})}this.builder.addOutput(`${Ue}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${Ue}}.execute-api.\${AWS::Region}.amazonaws.com/${g}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${Ue}Id`,{Description:"WebSocket API ID",Value:{Ref:Ue},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
13
+ `:Tt,Ie=A.map(([,vt])=>vt.port).filter((vt)=>typeof vt==="number"&&![80,443].includes(vt)),z=this.resolveApiOriginPort(),Ye=`${u}${g}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),V=`${u}-${g}-deploy`;this.builder.addResource(Ye,{Type:"AWS::S3::Bucket",Properties:{BucketName:V,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"expire-old-releases",Status:"Enabled",ExpirationInDays:7,Prefix:"releases/"}]},Tags:[{Key:"Project",Value:u},{Key:"Environment",Value:g},{Key:"ManagedBy",Value:"ts-cloud"}]}});let Ke=a.createServerModeStack({slug:`${u}-app`,environment:g,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:K,keyName:h.allowSsh?`${u}-${g}`:void 0,domain:P,userData:Se,volumeSize:h.disk?.size||20,imageId:h.image,allowedPorts:[...h.allowSsh?[22]:[],80,443,z,...Ie]}),yt=Ke.resources[Ke.outputs.instanceLogicalId];if(yt?.Properties){let vt=yt.Properties.Tags||[];yt.Properties.Tags=[...vt,{Key:"Project",Value:u},{Key:"Environment",Value:g},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let It=Ke.resources[Ke.outputs.roleLogicalId];if(It?.Properties)It.Properties.Policies=It.Properties.Policies||[],It.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${V}`,`arn:aws:s3:::${V}/*`]}]}});for(let[vt,Ht]of Object.entries(Ke.resources))this.builder.addResource(vt,Ht);this.builder.addOutput("deployBucketName",{Value:{Ref:Ye},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:Ke.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:Ke.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",Ke.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",Ke.outputs.instanceLogicalId)}jumpBoxFileSystemId(u,g,h){let S=Object.keys(this.mergedConfig.infrastructure?.fileSystem??{});if(typeof h==="string")return S.includes(h)?{Ref:this.fileSystemLogicalId(u,g,h)}:h;if(S.length===1)return{Ref:this.fileSystemLogicalId(u,g,S[0])};throw Error(S.length===0?"infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares no file system. Declare one, or set mountEfs to an EFS id.":`infrastructure.jumpBox.mountEfs is true, but infrastructure.fileSystem declares ${S.length} (${S.join(", ")}). Set mountEfs to the name of the one to mount.`)}generateJumpBox(u,g){let h=this.mergedConfig.infrastructure?.jumpBox;if(!h)return;let S=h===!0?{}:h;if(S.enabled===!1)return;this.generateNetworkInfrastructure(u,g);let A=S.size||"micro",P=a.InstanceSize.specs[A]?.instanceType||A||"t3.micro",M=a.createJumpBox({slug:u,environment:g,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:S.keyName,instanceType:P,allowedCidrs:S.allowedCidrs,mountEfs:S.mountEfs?{fileSystemId:this.jumpBoxFileSystemId(u,g,S.mountEfs),mountPath:S.mountPath||"/mnt/efs"}:void 0,databaseTools:S.databaseTools});for(let[W,le]of Object.entries(M.resources))this.builder.addResource(W,le);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:M.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(u,g){let h=this.mergedConfig.infrastructure?.ssl,S=this.mergedConfig.infrastructure?.dns,A=S?.domain,T=S?.hostedZoneId,P=[],M,W;if(h?.certificateArn)W=h.certificateArn;else if(h?.enabled&&A&&T){let Ie=h.domains||[A],z=Ie[0],Ye=Ie.slice(1).map((yt)=>{if(yt.includes(".")&&yt.endsWith(z))return yt.replace(`.${z}`,"");return yt}),{certificate:V,logicalId:Ke}=v.createCertificate({domain:z,subdomains:Ye,slug:u,environment:g,validationMethod:"DNS",hostedZoneId:T});M=Ke,this.builder.addResource(Ke,V)}if(this.mergedConfig.infrastructure?.storage){let Ie=Object.entries(this.mergedConfig.infrastructure.storage).some(([,V])=>V.website),z;if(Ie&&(M||W))z=`${u}${g}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(z,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${u}-${g}-s3-oac`,Description:`OAC for ${u} ${g} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let Ye=Object.entries(this.mergedConfig.infrastructure.storage).map(([V,Ke])=>({name:V,config:Ke,mountPath:this.normalizeMountPath(Ke),rewriteStyle:Ke.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(u,g,V)})).filter((V)=>V.name!=="public"&&V.config.website&&V.mountPath);for(let[V,Ke]of Object.entries(this.mergedConfig.infrastructure.storage)){let yt=!!(Ke.website&&z),It=this.storageBucketName(u,g,V),{bucket:vt,logicalId:Ht}=$e.createBucket({slug:u,name:V,environment:g,bucketName:It,versioning:Ke.versioning,encryption:Ke.encryption,public:yt?!1:Ke.public}),Zt=this.normalizeMountPath(Ke),er;if(Ke.failover){let Yt=`infrastructure.storage.${V}`;if(!yt||!A||Zt&&V!=="public")throw Error(`${Yt}.failover needs this bucket to be served by its own CloudFront distribution: a website bucket (website: true), not mounted under the path of another site, with infrastructure.dns.domain set and SSL configured (infrastructure.ssl.certificateArn, or ssl.enabled with dns.hostedZoneId).`);if(er=Lm({failover:Ke.failover,primaryBucket:It,primaryRegion:this.mergedConfig.project.region||"us-east-1",where:Yt}),er.replicate&&vt.Properties){let tr=`${Ht}FailoverReplicationRole`;this.builder.addResource(tr,Mm({primaryBucket:It,replicaBucket:er.replicaBucket}));let _r=vt.Properties;_r.VersioningConfiguration={Status:"Enabled"},_r.ReplicationConfiguration=Fm({replicaBucket:er.replicaBucket,roleArn:{"Fn::GetAtt":[tr,"Arn"]}})}}if(yt&&vt.Properties)vt.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(Ht,vt),Ke.website){let Yt=typeof Ke.website==="object"?Ke.website:{},tr=$e.enableWebsiteHosting(vt,Yt.indexDocument||"index.html",Yt.errorDocument);this.builder.addResource(Ht,tr)}let Tr=this.normalizeMountPath(Ke);if(yt&&z&&A&&!(Tr&&V!=="public")){let Yt=`${u}${g}${V}CDN`.replace(/[^a-zA-Z0-9]/g,""),tr=[];if(Ke.aliases&&Ke.aliases.length>0)tr.push(...Ke.aliases);else if(V==="public"){if(tr.push(A),h?.domains?.includes(`www.${A}`))tr.push(`www.${A}`)}else if(V==="docs")tr.push(`docs.${A}`);else if(V==="blog")tr.push(`blog.${A}`);let _r=typeof Ke.website==="object"?Ke.website:{},Kr=Ke.spa===!0,zr=_r.errorDocument||(Kr?"index.html":"404.html"),$r=[];if(Kr)$r.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else $r.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${zr}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${zr}`,ErrorCachingMinTTL:300});let qr=W&&tr.length>0?{AcmCertificateArn:W,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:M&&tr.length>0?{AcmCertificateArn:{Ref:M},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},Qn=`S3-${u}-${g}-${V}`,qs=this.mergedConfig.project.region||"us-east-1",ti;if(!Kr)ti=`${u}${g}${V}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(ti,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${g}-${V}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${u} ${g} ${V} - 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 fi=[{Id:Qn,DomainName:{"Fn::Sub":`\${${Ht}}.s3.${qs}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:z}}],uo=[],ac=[];if(this.shouldRouteStorageBucketToCompute(V,Ke)){this.appendComputeAppOrigin(fi,uo,ac,u,g,this.resolveComputeCachePathPatterns(Ke.computeRoutes));for(let nr of Ye){let go=`S3-${u}-${g}-${nr.name}`,Oc=`${u}${g}${nr.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Oc,{Type:"AWS::CloudFront::Function",Properties:{Name:`${u}-${g}-${nr.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${u} ${g} ${nr.name} at ${nr.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(nr.mountPath,nr.rewriteStyle)}}),fi.push({Id:go,DomainName:{"Fn::Sub":`\${${nr.logicalId}}.s3.${qs}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:z}}),ac.push(nr.logicalId,Oc);for(let fp of[nr.mountPath,`${nr.mountPath}/*`])uo.push({PathPattern:fp,TargetOriginId:go,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":[Oc,"FunctionARN"]}}]})}}let mo,od=Qn;if(er){let nr=`${Qn}-failover`;Object.assign(fi[0],er.primaryConnection),fi.push({Id:nr,DomainName:$m(er.replicaBucket,er.replicaRegion),OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:z}}),mo=gn({primaryOriginId:Qn,secondaryOriginId:nr,statusCodes:er.statusCodes}),od=mo.Items[0].Id}let dc={Type:"AWS::CloudFront::Distribution",DependsOn:[Ht,z,...ti?[ti]:[],...ac],Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${g} ${V} site`,DefaultRootObject:"index.html",Origins:fi,...mo?{OriginGroups:mo}:{},DefaultCacheBehavior:{TargetOriginId:od,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...ti?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[ti,"FunctionARN"]}}]}:{}},...uo.length>0?{CacheBehaviors:uo}:{},...tr.length>0?{Aliases:tr}:{},ViewerCertificate:qr,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:$r}}};if(M)dc.DependsOn.push(M);if(er)Bt(dc.Properties.DistributionConfig,`infrastructure.storage.${V}`),this.storageFailoverReplicas.push({name:V,primaryBucket:It,primaryRegion:qs,replicaBucket:er.replicaBucket,replicaRegion:er.replicaRegion,replicate:er.replicate,distributionArnOutput:`${V}CloudFrontDistributionArn`}),this.builder.addOutput(`${V}CloudFrontDistributionArn`,{Value:{"Fn::Sub":`arn:\${AWS::Partition}:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`},Description:`CloudFront distribution ARN for ${V} (scopes the bucket policy of the failover replica)`}),this.builder.addOutput(`${V}FailoverBucketName`,{Value:er.replicaBucket,Description:`Failover replica bucket for ${V} (${er.replicaRegion}), outside this stack`});this.builder.addResource(Yt,dc);let gp=`${Ht}CloudFrontPolicy`;if(this.builder.addResource(gp,{Type:"AWS::S3::BucketPolicy",DependsOn:[Ht,Yt],Properties:{Bucket:{Ref:Ht},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${Ht}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(V,Ke))for(let nr of Ye){let go=`${nr.logicalId}CloudFrontPolicy`;this.builder.addResource(go,{Type:"AWS::S3::BucketPolicy",DependsOn:[nr.logicalId,Yt],Properties:{Bucket:{Ref:nr.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:::\${${nr.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${Yt}}`}}}}]}}})}if(tr.length>0)P.push({name:V,bucketLogicalId:Ht,distLogicalId:Yt,oacLogicalId:z,aliases:tr});this.builder.addOutput(`${V}CloudFrontDomain`,{Value:{"Fn::GetAtt":[Yt,"DomainName"]},Description:`CloudFront domain for ${V}`}),this.builder.addOutput(`${V}CloudFrontDistributionId`,{Value:{Ref:Yt},Description:`CloudFront distribution ID for ${V}`})}if(this.builder.addOutput(`${V}BucketName`,{Value:{Ref:Ht},Description:`S3 bucket name for ${V}`}),V==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:Ht},Description:"Frontend S3 bucket name"});if(V==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:Ht},Description:"Documentation S3 bucket name"});if(V==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:Ht},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let Ie=this.mergedConfig.infrastructure.sftp,z=El.create({...Ie,storage:this.resolveSftpStorage(Ie,u,g)??Ie.storage,slug:u,environment:g});for(let[Ye,V]of Object.entries(z.resources))this.builder.addResource(Ye,V);this.builder.addOutput("SftpServerId",{Value:{Ref:z.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${z.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:z.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(T&&P.length>0)for(let{name:Ie,distLogicalId:z,aliases:Ye}of P)for(let V of Ye){let Ke=V.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Ke}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[z],Properties:{HostedZoneId:T,Name:V,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[z,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${Ke}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[z],Properties:{HostedZoneId:T,Name:V,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[z,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[Ie,z]of Object.entries(this.mergedConfig.infrastructure.databases))if(z.engine==="dynamodb"){let{table:Ye,logicalId:V}=gr.createTable({slug:u,environment:g,tableName:`${u}-${g}-${Ie}`,partitionKey:z.partitionKey||{name:"id",type:"S"},sortKey:z.sortKey});this.builder.addResource(V,Ye)}else if(z.engine==="postgres"){let{dbInstance:Ye,logicalId:V}=gr.createPostgres({slug:u,environment:g,dbInstanceIdentifier:`${u}-${g}-${Ie}`,masterUsername:z.username||"admin",masterUserPassword:z.password||"changeme123",allocatedStorage:z.storage||20,dbInstanceClass:z.instanceClass||"db.t3.micro"});this.builder.addResource(V,Ye)}else if(z.engine==="mysql"){let{dbInstance:Ye,logicalId:V}=gr.createMysql({slug:u,environment:g,dbInstanceIdentifier:`${u}-${g}-${Ie}`,masterUsername:z.username||"admin",masterUserPassword:z.password||"changeme123",allocatedStorage:z.storage||20,dbInstanceClass:z.instanceClass||"db.t3.micro"});this.builder.addResource(V,Ye)}}if(this.mergedConfig.infrastructure?.cdn)for(let[Ie,z]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!z.origin)continue;let Ye=typeof z.customDomain==="string"?z.customDomain:z.customDomain?.domain||z.domain,V=typeof z.customDomain==="object"?z.customDomain?.certificateArn:z.certificateArn,Ke=V||W,yt=`${u}${g}${Ie}CDN`.replace(/[^a-zA-Z0-9]/g,""),It=`S3-${u}-${g}-${Ie}-cdn`,vt=[{Id:It,DomainName:z.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:z.originShield?{Enabled:!0,OriginShieldRegion:z.originShieldRegion||this.mergedConfig.environments[g]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1},...pe(z,`infrastructure.cdn.${Ie}`)}],Ht=[],Zt=[],er=["GET","HEAD","OPTIONS"],Tr=It,Yt;if(z.failoverOrigin){Nt(er,`the default cache behavior of infrastructure.cdn.${Ie}`);let zr=`${It}-failover`,$r=typeof z.failoverOrigin==="string"?{domain:z.failoverOrigin}:z.failoverOrigin;if(!$r.domain)throw Error(`infrastructure.cdn.${Ie}.failoverOrigin.domain is required`);if($r.domain===z.origin)throw Error(`infrastructure.cdn.${Ie}: failoverOrigin must differ from origin (both are ${z.origin})`);vt.push({Id:zr,DomainName:$r.domain,OriginPath:$r.originPath||"",...Jo($r.domain)?{S3OriginConfig:{OriginAccessIdentity:""}}:{CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"}},OriginShield:{Enabled:!1},...pe($r,`infrastructure.cdn.${Ie}.failoverOrigin`)}),Yt=gn({primaryOriginId:It,secondaryOriginId:zr,statusCodes:z.failoverStatusCodes}),Tr=Yt.Items[0].Id}else if(z.failoverStatusCodes)throw Error(`infrastructure.cdn.${Ie}: failoverStatusCodes needs failoverOrigin to fail over to`);if(z.routeCompute)this.appendComputeAppOrigin(vt,Ht,Zt,u,g,this.resolveComputeCachePathPatterns(z.computeRoutes));let tr=Ke&&Ye?{AcmCertificateArn:M&&!V?{Ref:M}:Ke,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},_r=[...Zt];if(M&&!V&&Ye)_r.push(M);let Kr={Type:"AWS::CloudFront::Distribution",..._r.length>0?{DependsOn:_r}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${u} ${g} ${Ie} CDN`,DefaultRootObject:"index.html",Origins:vt,...Yt?{OriginGroups:Yt}:{},DefaultCacheBehavior:{TargetOriginId:Tr,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:er,CachedMethods:["GET","HEAD","OPTIONS"],Compress:z.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...Ht.length>0?{CacheBehaviors:Ht}:{},...Ye&&Ke?{Aliases:[Ye]}:{},ViewerCertificate:tr,PriceClass:"PriceClass_100",HttpVersion:z.http3?"http2and3":"http2"}}};if(Bt(Kr.Properties.DistributionConfig,`infrastructure.cdn.${Ie}`),this.builder.addResource(yt,Kr),T&&Ye&&Ke){let zr=Ye.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${zr}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[yt,...M&&!V?[M]:[]],Properties:{HostedZoneId:T,Name:Ye,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[yt,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[Ie,z]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(z))continue;let{queue:Ye,logicalId:V}=Y.createQueue({slug:u,environment:g,name:`${u}-${g}-${Ie}`,fifo:z.fifo,visibilityTimeout:z.visibilityTimeout,messageRetentionPeriod:z.messageRetentionPeriod,delaySeconds:z.delaySeconds,maxMessageSize:z.maxMessageSize,receiveMessageWaitTime:z.receiveMessageWaitTime,contentBasedDeduplication:z.contentBasedDeduplication,encrypted:z.encrypted,kmsKeyId:z.kmsKeyId});this.builder.addResource(V,Ye);let Ke;if(z.deadLetterQueue){let{deadLetterQueue:yt,updatedSourceQueue:It,deadLetterLogicalId:vt}=Y.createDeadLetterQueue(V,{slug:u,environment:g,maxReceiveCount:z.maxReceiveCount});Ke=vt,this.builder.addResource(vt,yt);let Zt=this.builder.getResources()[V];if(Zt?.Properties)Zt.Properties.RedrivePolicy=It.Properties?.RedrivePolicy}if(z.trigger){let yt=z.trigger,It=`${u}${g}${yt.functionName}`.replace(/[^a-zA-Z0-9]/g,""),vt={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[V,"Arn"]},FunctionName:{Ref:It},BatchSize:yt.batchSize||10,MaximumBatchingWindowInSeconds:yt.batchWindow||0,Enabled:!0,...yt.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...yt.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:yt.maxConcurrency}},...yt.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(yt.filterPattern)}]}}},DependsOn:[V,It]};this.builder.addResource(`${V}Trigger`,vt)}if(z.alarms?.enabled){let yt=z.alarms,It=yt.notificationTopicArn;if(!It&&yt.notificationEmails?.length){let Zt=`${V}AlarmTopic`;this.builder.addResource(Zt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${g}-${Ie}-alarms`,DisplayName:`${Ie} Queue Alarms`}}),yt.notificationEmails.forEach((er,Tr)=>{this.builder.addResource(`${Zt}Sub${Tr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Zt},Protocol:"email",Endpoint:er}})}),It={Ref:Zt}}let vt=yt.queueDepthThreshold||1000;this.builder.addResource(`${V}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-${Ie}-queue-depth`,AlarmDescription:`Queue ${Ie} depth exceeds ${vt} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:vt,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[V,"QueueName"]}}],...It&&{AlarmActions:[It],OKActions:[It]}}});let Ht=yt.messageAgeThreshold||3600;if(this.builder.addResource(`${V}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-${Ie}-message-age`,AlarmDescription:`Queue ${Ie} oldest message exceeds ${Ht} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:Ht,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[V,"QueueName"]}}],...It&&{AlarmActions:[It],OKActions:[It]}}}),Ke&&yt.dlqAlarm!==!1)this.builder.addResource(`${Ke}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-${Ie}-dlq-messages`,AlarmDescription:`Dead letter queue for ${Ie} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[Ke,"QueueName"]}}],...It&&{AlarmActions:[It]}}})}if(z.subscribe){let yt=z.subscribe,It=yt.topicArn;if(!It&&yt.topicName)It={Ref:yt.topicName};if(It){this.builder.addResource(`${V}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:V}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[V,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":It}}}]}}});let vt={TopicArn:It,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[V,"Arn"]},RawMessageDelivery:yt.rawMessageDelivery||!1};if(yt.filterPolicy)vt.FilterPolicy=yt.filterPolicy,vt.FilterPolicyScope=yt.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${V}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:vt,DependsOn:`${V}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(u,g);else this.generateRealtimeResources(u,g);let le=this.mergedConfig.infrastructure?.redirects;if(le){let Ie=le.target||this.mergedConfig.infrastructure?.dns?.domain||"",z=le.protocol||"https";if(le.domains?.length&&Ie)for(let Ye of le.domains){let{bucket:V,bucketPolicy:Ke,logicalId:yt,policyLogicalId:It}=Ot.createDomainRedirectBucket({slug:u,environment:g,sourceDomain:Ye,targetDomain:Ie,protocol:z});this.builder.addResource(yt,V),this.builder.addResource(It,Ke)}if(le.paths&&Object.keys(le.paths).length>0){let Ye=Ot.fromMapping(le.paths,{statusCode:le.statusCode||301}),{function:V,logicalId:Ke}=Ot.createPathRedirectFunction({slug:u,environment:g,rules:Ye});this.builder.addResource(Ke,V)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[Ie,z]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:Ye,logicalId:V}=Zo.createAlarm({slug:u,environment:g,alarmName:`${u}-${g}-${Ie}`,metricName:z.metricName||"Errors",namespace:z.namespace||"AWS/Lambda",threshold:z.threshold||1,comparisonOperator:z.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(V,Ye)}let K=this.mergedConfig.infrastructure?.cache;if(K){let Ie=K.type||"redis";if(Ie==="redis"){this.generateNetworkInfrastructure(u,g);let z=K.redis||{},{replicationGroup:Ye,subnetGroup:V,logicalId:Ke,subnetGroupId:yt}=Yo.createRedis({slug:u,environment:g,nodeType:z.nodeType||K.nodeType||"cache.t3.micro",engineVersion:z.engineVersion||"7.1",port:z.port||6379,numCacheClusters:z.numCacheNodes||2,automaticFailover:z.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:z.snapshotRetentionLimit||7,snapshotWindow:z.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Ke,Ye),V&&yt)this.builder.addResource(yt,V);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Ke,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[Ke,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(Ie==="memcached"){this.generateNetworkInfrastructure(u,g);let z=K.elasticache||{},{cluster:Ye,subnetGroup:V,logicalId:Ke,subnetGroupId:yt}=Yo.createMemcached({slug:u,environment:g,nodeType:z.nodeType||K.nodeType||"cache.t3.micro",engineVersion:z.engineVersion||"1.6.22",numCacheNodes:z.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(Ke,Ye),V&&yt)this.builder.addResource(yt,V);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[Ke,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let Ct=this.mergedConfig.infrastructure?.email;if(Ct){let Ie=Ct.domain||this.mergedConfig.infrastructure?.dns?.domain;if(Ie){let{emailIdentity:z,logicalId:Ye}=f.verifyDomain({domain:Ie,slug:u,environment:g,enableDkim:Ct.enableDkim!==!1,dkimKeyLength:Ct.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(Ye,z),Ct.configurationSet!==!1){let{configurationSet:yt,logicalId:It}=f.createConfigurationSet({slug:u,environment:g});this.builder.addResource(It,yt)}let V=Ct.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(V){if(Ct.enableDkim!==!1)for(let Zt=1;Zt<=3;Zt++){let er=`DkimRecord${Zt}${Ie.replace(/\./g,"")}`;this.builder.addResource(er,{Type:"AWS::Route53::RecordSet",DependsOn:[Ye],Properties:{HostedZoneId:V,Name:{"Fn::GetAtt":[Ye,`DkimDNSTokenName${Zt}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[Ye,`DkimDNSTokenValue${Zt}`]}]}})}let{record:yt,logicalId:It}=f.createSpfRecord(Ie,V);this.builder.addResource(It,yt);let{record:vt,logicalId:Ht}=f.createDmarcRecord(Ie,V,{policy:"none",reportingEmail:Ct.dmarcReportingEmail||`dmarc-reports@${Ie}`});this.builder.addResource(Ht,vt)}this.builder.addOutput("EmailDomain",{Value:Ie,Description:"SES verified email domain"});let Ke=Ct.server;if(Ke?.enabled&&V){let yt=this.mergedConfig.environments[g]?.region||this.mergedConfig.project.region||"us-east-1",It=`${u}-${g}-email`,{role:vt,policy:Ht,roleLogicalId:Zt,policyLogicalId:er}=f.createEmailLambdaRole({slug:u,environment:g,s3BucketArn:`arn:aws:s3:::${It}`,sesIdentityArn:`arn:aws:ses:${yt}:*:identity/${Ie}`});this.builder.addResource(Zt,vt),this.builder.addResource(er,Ht);let{function:Tr,permission:Yt,logicalId:tr,permissionLogicalId:_r}=f.createInboundEmailLambda({slug:u,environment:g,roleArn:{"Fn::GetAtt":[Zt,"Arn"]},s3BucketName:It,organizedPrefix:"mailboxes/"});this.builder.addResource(tr,Tr),this.builder.addResource(_r,Yt);let Kr=f.createInboundEmailSetup({slug:u,environment:g,domain:Ie,s3BucketName:It,s3KeyPrefix:"inbox/",region:yt,hostedZoneId:V,lambdaFunctionArn:{"Fn::GetAtt":[tr,"Arn"]}});for(let[$r,qr]of Object.entries(Kr.resources)){if(qr.Type==="AWS::SES::ReceiptRule")qr.DependsOn=[_r,tr];this.builder.addResource($r,qr)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:tr},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:It,Description:"S3 bucket for email storage"});let zr=this.serverEipLogicalIds.get("app");if(zr&&V){let qr=`${Ke?.subdomain||"mail"}.${Ie}`,Qn=qr.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${Qn}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:V,Name:qr,Type:"A",TTL:"300",ResourceRecords:[{Ref:zr}]}})}this.builder.addOutput("MailHost",{Value:`mail.${Ie}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let Tt=this.mergedConfig.infrastructure?.search;if(Tt){let Ie=Tt.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(Ie)this.generateNetworkInfrastructure(u,g);let{domain:z,logicalId:Ye}=pr.createDomain({slug:u,environment:g,engineVersion:Tt.engineVersion||"OpenSearch_2.11",instanceType:Tt.instanceType||"t3.small.search",instanceCount:Tt.instanceCount||1,volumeSize:Tt.volumeSize||10,volumeType:Tt.volumeType||"gp3",dedicatedMaster:Tt.dedicatedMaster||!1,dedicatedMasterType:Tt.dedicatedMasterType,dedicatedMasterCount:Tt.dedicatedMasterCount||3,multiAz:Tt.multiAz||!1,encryption:Tt.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:Tt.advancedSecurity,autoTune:Tt.autoTune!==!1,vpc:Ie});this.builder.addResource(Ye,z),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[Ye,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[Ye,"Arn"]},Description:"OpenSearch domain ARN"})}let He=this.mergedConfig.infrastructure?.fileSystem;if(He&&Object.keys(He).length>0){this.generateNetworkInfrastructure(u,g);for(let[Ie,z]of Object.entries(He)){let{fileSystem:Ye,logicalId:V}=it.createFileSystem({slug:`${u}-${Ie}`,environment:g,encrypted:z.encrypted!==!1,performanceMode:z.performanceMode||"generalPurpose",throughputMode:z.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(V,Ye);let{securityGroup:Ke,logicalId:yt}=it.createEfsSecurityGroup({slug:`${u}-${Ie}`,environment:g,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(yt,Ke);let{mountTargets:It,logicalIds:vt}=it.createMultiAzMountTargets(V,{slug:`${u}-${Ie}`,environment:g,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:yt}});for(let Ht=0;Ht<It.length;Ht++)this.builder.addResource(vt[Ht],It[Ht]);this.builder.addOutput(`${Ie}FileSystemId`,{Value:{Ref:V},Description:`EFS file system ID for ${Ie}`})}}let Se=this.mergedConfig.infrastructure?.ai;if(Se){let Ie=Se.service||"ecs",z=Se.models||["*"],Ye=Se.allowStreaming!==!1,V;if(Ie==="ecs")V=Me.enableBedrockForEcs({slug:u,environment:g,models:z,allowStreaming:Ye});else if(Ie==="ec2")V=Me.enableBedrockForEc2({slug:u,environment:g,models:z,allowStreaming:Ye});else if(Ie==="lambda")V=Me.enableBedrockForLambda({slug:u,environment:g,models:z,allowStreaming:Ye});else V=Me.createBedrockRole(Ie,{slug:u,environment:g,models:z,allowStreaming:Ye});if(this.builder.addResource(V.logicalId,V.role),Se.allowAsync){let{policy:Ke,logicalId:yt}=Me.createBedrockPolicy({slug:u,environment:g,models:z,allowStreaming:Ye,allowAsync:!0});this.builder.addResource(yt,Ke)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[V.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(u,g){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let S=h.name||`${u}-${g}-realtime`,A=h.scaling||{},T=h.storage||{type:"dynamodb"},P=A.handlerMemory||256,M=A.handlerTimeout||30,W=`${u}${g}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),le=`${u}${g}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(T.type==="dynamodb"){let vt=T.dynamodb||{},Ht=vt.billingMode||"PAY_PER_REQUEST";this.builder.addResource(W,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${g}-realtime-connections`,BillingMode:Ht,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"},...Ht==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:vt.readCapacity||5,WriteCapacityUnits:vt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Ht==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:vt.readCapacity||5,WriteCapacityUnits:vt.writeCapacity||5}},...vt.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${u}-${g}-realtime-connections`},{Key:"Environment",Value:g}]}}),this.builder.addResource(le,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-${g}-realtime-channels`,BillingMode:Ht,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"},...Ht==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:vt.readCapacity||5,WriteCapacityUnits:vt.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...Ht==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:vt.readCapacity||5,WriteCapacityUnits:vt.writeCapacity||5}},Tags:[{Key:"Name",Value:`${u}-${g}-realtime-channels`},{Key:"Environment",Value:g}]}})}let K=`${u}${g}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(K,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-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":[W,"Arn"]},{"Fn::Sub":`\${${W}.Arn}/index/*`},{"Fn::GetAtt":[le,"Arn"]},{"Fn::Sub":`\${${le}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let Ct=`${u}${g}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),Tt=`${u}${g}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),He=`${u}${g}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ct,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${g}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[K,"Arn"]},MemorySize:P,Timeout:M,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:W},CHANNELS_TABLE:{Ref:le},ENVIRONMENT:g}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[K,W]}),this.builder.addResource(Tt,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${g}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[K,"Arn"]},MemorySize:P,Timeout:M,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:W},CHANNELS_TABLE:{Ref:le},ENVIRONMENT:g}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[K,W,le]}),this.builder.addResource(He,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-${g}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[K,"Arn"]},MemorySize:P,Timeout:M,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:W},CHANNELS_TABLE:{Ref:le},ENVIRONMENT:g}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[K,W,le]});let Se=`${u}${g}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Se,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:S,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:S,Environment:g}}});let Ie=`${Ct}Permission`,z=`${Tt}Permission`,Ye=`${He}Permission`;this.builder.addResource(Ie,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Ct},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Se}}/*/$connect`}}}),this.builder.addResource(z,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:Tt},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Se}}/*/$disconnect`}}}),this.builder.addResource(Ye,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:He},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${Se}}/*/$default`}}});let V=`${Se}ConnectInteg`,Ke=`${Se}DisconnectInteg`,yt=`${Se}MessageInteg`;this.builder.addResource(V,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Se},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Ct}.Arn}/invocations`}}}),this.builder.addResource(Ke,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Se},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${Tt}.Arn}/invocations`}}}),this.builder.addResource(yt,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:Se},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${He}.Arn}/invocations`}}}),this.builder.addResource(`${Se}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Se},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${V}}`}}}),this.builder.addResource(`${Se}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Se},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${Ke}}`}}}),this.builder.addResource(`${Se}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:Se},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${yt}}`}}});let It=`${Se}Stage`;if(this.builder.addResource(It,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:Se},StageName:g,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:A.messagesPerSecond||1000,ThrottlingRateLimit:A.messagesPerSecond||1000}}}),h.monitoring?.enabled){let vt=h.monitoring,Ht=vt.notificationTopicArn;if(!Ht&&vt.notificationEmails?.length){let Zt=`${Se}AlarmTopic`;this.builder.addResource(Zt,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${g}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),vt.notificationEmails.forEach((er,Tr)=>{this.builder.addResource(`${Zt}Sub${Tr}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Zt},Protocol:"email",Endpoint:er}})}),Ht={Ref:Zt}}if(vt.connectionThreshold)this.builder.addResource(`${Se}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${vt.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:vt.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Se}}],...Ht&&{AlarmActions:[Ht]}}});if(vt.errorThreshold)this.builder.addResource(`${Se}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${vt.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:vt.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:Se}}],...Ht&&{AlarmActions:[Ht]}}})}this.builder.addOutput(`${Se}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${Se}}.execute-api.\${AWS::Region}.amazonaws.com/${g}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${Se}Id`,{Description:"WebSocket API ID",Value:{Ref:Se},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
15
15
  const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
16
16
  const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb');
17
17
 
@@ -170,7 +170,7 @@ catch (error) {
170
170
  return { statusCode: 500, body: JSON.stringify({ error: 'Internal error' }) };
171
171
  }
172
172
  };
173
- `.trim()}generateRealtimeServerResources(u,g){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let y=h.server||{},R=y.port||6001,v=y.instances||1,P=`${u}${g}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${u} realtime WebSocket server`,GroupName:`${u}-${g}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:R,ToPort:R,CidrIp:"0.0.0.0/0",Description:"WebSocket connections"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS/WSS connections"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${g}-realtime-sg`},{Key:"Environment",Value:g}]}});let M=`${u}${g}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),V=`${u}${g}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),Ae=`${u}${g}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ae,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-realtime-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}}),this.builder.addResource(V,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-realtime-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RealtimeTaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},...y.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let ye=[{Name:"BROADCAST_HOST",Value:y.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(R)},{Name:"NODE_ENV",Value:g==="production"?"production":"development"}];if(y.redis?.enabled){if(y.redis.useElastiCache)ye.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),ye.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else ye.push({Name:"REDIS_HOST",Value:y.redis.host||"localhost"}),ye.push({Name:"REDIS_PORT",Value:String(y.redis.port||6379)});if(y.redis.keyPrefix)ye.push({Name:"REDIS_KEY_PREFIX",Value:y.redis.keyPrefix})}this.builder.addResource(M,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${g}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[Ae,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[V,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${u}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:R,Protocol:"tcp"}],Environment:ye,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${u}-${g}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${R}${y.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${g}-realtime`},{Key:"Environment",Value:g}]},DependsOn:[Ae,V]});let At=`${u}${g}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(At,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${u}-${g}-realtime`,RetentionInDays:30}});let Tt=`${u}${g}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Tt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${g}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:M},DesiredCount:v,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:P}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${u}-${g}-realtime`},{Key:"Environment",Value:g}]},DependsOn:[M,P,At]}),y.autoScaling){let Je=y.autoScaling,Ue=`${u}${g}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Ue,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:Je.max||10,MinCapacity:Je.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${u}-${g}-realtime`},RoleARN:{"Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"},ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},DependsOn:Tt}),Je.targetCPU)this.builder.addResource(`${u}${g}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${g}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Ue},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:Je.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(h.monitoring?.enabled){let Je=h.monitoring,Ue=Je.notificationTopicArn;if(!Ue&&Je.notificationEmails?.length){let je=`${u}${g}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(je,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${g}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),Je.notificationEmails.forEach((K,St)=>{this.builder.addResource(`${je}Sub${St}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:je},Protocol:"email",Endpoint:K}})}),Ue={Ref:je}}this.builder.addResource(`${u}${g}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-realtime-high-cpu`,AlarmDescription:"Realtime server CPU utilization is high",MetricName:"CPUUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${u}-${g}-realtime`}],...Ue&&{AlarmActions:[Ue]}},DependsOn:Tt}),this.builder.addResource(`${u}${g}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-realtime-high-memory`,AlarmDescription:"Realtime server memory utilization is high",MetricName:"MemoryUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${u}-${g}-realtime`}],...Ue&&{AlarmActions:[Ue]}},DependsOn:Tt})}this.builder.addOutput(`${u}${g}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${u}-${g}-realtime.\${AWS::Region}.elb.amazonaws.com:${R}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let u=this.mergedConfig.infrastructure?.realtime;if(!u||u.mode!=="server")return"";let g=u.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
173
+ `.trim()}generateRealtimeServerResources(u,g){let h=this.mergedConfig.infrastructure?.realtime;if(!h)return;let S=h.server||{},A=S.port||6001,T=S.instances||1,P=`${u}${g}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(P,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${u} realtime WebSocket server`,GroupName:`${u}-${g}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:A,ToPort:A,CidrIp:"0.0.0.0/0",Description:"WebSocket connections"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS/WSS connections"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${u}-${g}-realtime-sg`},{Key:"Environment",Value:g}]}});let M=`${u}${g}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),W=`${u}${g}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),le=`${u}${g}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(le,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-realtime-exec-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"]}}),this.builder.addResource(W,{Type:"AWS::IAM::Role",Properties:{RoleName:`${u}-${g}-realtime-task-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"RealtimeTaskPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogStream","logs:PutLogEvents"],Resource:"*"},...S.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let K=[{Name:"BROADCAST_HOST",Value:S.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(A)},{Name:"NODE_ENV",Value:g==="production"?"production":"development"}];if(S.redis?.enabled){if(S.redis.useElastiCache)K.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),K.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else K.push({Name:"REDIS_HOST",Value:S.redis.host||"localhost"}),K.push({Name:"REDIS_PORT",Value:String(S.redis.port||6379)});if(S.redis.keyPrefix)K.push({Name:"REDIS_KEY_PREFIX",Value:S.redis.keyPrefix})}this.builder.addResource(M,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${u}-${g}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[le,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[W,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${u}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:A,Protocol:"tcp"}],Environment:K,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${u}-${g}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${A}${S.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${u}-${g}-realtime`},{Key:"Environment",Value:g}]},DependsOn:[le,W]});let Ct=`${u}${g}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ct,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${u}-${g}-realtime`,RetentionInDays:30}});let Tt=`${u}${g}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Tt,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${u}-${g}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:M},DesiredCount:T,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:P}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${u}-${g}-realtime`},{Key:"Environment",Value:g}]},DependsOn:[M,P,Ct]}),S.autoScaling){let He=S.autoScaling,Se=`${u}${g}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(Se,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:He.max||10,MinCapacity:He.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${u}-${g}-realtime`},RoleARN:{"Fn::Sub":"arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"},ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},DependsOn:Tt}),He.targetCPU)this.builder.addResource(`${u}${g}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${u}-${g}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:Se},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:He.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(h.monitoring?.enabled){let He=h.monitoring,Se=He.notificationTopicArn;if(!Se&&He.notificationEmails?.length){let Ie=`${u}${g}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Ie,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-${g}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),He.notificationEmails.forEach((z,Ye)=>{this.builder.addResource(`${Ie}Sub${Ye}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:Ie},Protocol:"email",Endpoint:z}})}),Se={Ref:Ie}}this.builder.addResource(`${u}${g}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-realtime-high-cpu`,AlarmDescription:"Realtime server CPU utilization is high",MetricName:"CPUUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${u}-${g}-realtime`}],...Se&&{AlarmActions:[Se]}},DependsOn:Tt}),this.builder.addResource(`${u}${g}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${u}-${g}-realtime-high-memory`,AlarmDescription:"Realtime server memory utilization is high",MetricName:"MemoryUtilization",Namespace:"AWS/ECS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:80,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ClusterName",Value:{Ref:"ECSCluster"}},{Name:"ServiceName",Value:`${u}-${g}-realtime`}],...Se&&{AlarmActions:[Se]}},DependsOn:Tt})}this.builder.addOutput(`${u}${g}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${u}-${g}-realtime.\${AWS::Region}.elb.amazonaws.com:${A}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let u=this.mergedConfig.infrastructure?.realtime;if(!u||u.mode!=="server")return"";let g=u.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
174
174
 
175
175
  export default {
176
176
  verbose: ${this.environment!=="production"},
@@ -219,7 +219,7 @@ ${g.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 Dp(u){let g=[],h=[];if(!u.AWSTemplateFormatVersion)g.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(u.AWSTemplateFormatVersion!=="2010-09-09")h.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!u.Resources||Object.keys(u.Resources).length===0)g.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[y,R]of Object.entries(u.Resources))vp(y,R,g,h);if(u.Resources){let y=Np(u.Resources);if(y.length>0)g.push({path:"Resources",message:`Circular dependencies detected: ${y.join(" -> ")}`,severity:"error"})}if(u.Parameters)for(let[y,R]of Object.entries(u.Parameters))Ep(y,R,g,h);if(u.Outputs)for(let[y,R]of Object.entries(u.Outputs))Op(y,R,g,h);return{valid:g.length===0,errors:g,warnings:h}}function vp(u,g,h,y){if(!g.Type)h.push({path:`Resources.${u}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(u))y.push({path:`Resources.${u}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(g.Type&&!g.Type.startsWith("AWS::")&&!g.Type.startsWith("Custom::"))h.push({path:`Resources.${u}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(g.Properties){for(let[R,v]of Object.entries(g.Properties))if(v===void 0||v===null)y.push({path:`Resources.${u}.Properties.${R}`,message:"Property has undefined or null value",severity:"warning"})}if(g.DependsOn){if(typeof g.DependsOn==="string"){if(g.DependsOn===u)h.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(g.DependsOn)){if(g.DependsOn.includes(u))h.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function Ep(u,g,h,y){if(!g.Type)h.push({path:`Parameters.${u}.Type`,message:"Parameter Type is required",severity:"error"});let R=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(g.Type&&!R.includes(g.Type)&&!g.Type.startsWith("AWS::"))y.push({path:`Parameters.${u}.Type`,message:`Uncommon parameter type: ${g.Type}`,severity:"warning"});if(g.NoEcho&&g.Default)y.push({path:`Parameters.${u}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function Op(u,g,h,y){if(!g.Value)h.push({path:`Outputs.${u}.Value`,message:"Output Value is required",severity:"error"})}function Np(u){let g={};for(let[P,M]of Object.entries(u)){if(g[P]=[],M.DependsOn){if(typeof M.DependsOn==="string")g[P].push(M.DependsOn);else if(Array.isArray(M.DependsOn))g[P].push(...M.DependsOn)}let V=jc(M);g[P].push(...V)}let h=new Set,y=new Set,R=[];function v(P,M){h.add(P),y.add(P),M.push(P);let V=g[P]||[];for(let Ae of V)if(!h.has(Ae)){if(v(Ae,M))return!0}else if(y.has(Ae)){let ye=M.indexOf(Ae);return R.push(...M.slice(ye),Ae),!0}return M.pop(),y.delete(P),!1}for(let P of Object.keys(g))if(!h.has(P)){if(v(P,[]))return R}return[]}function jc(u,g=[]){if(typeof u!=="object"||u===null)return g;if(Array.isArray(u)){for(let h of u)jc(h,g);return g}if(u.Ref&&typeof u.Ref==="string"&&!u.Ref.startsWith("AWS::"))g.push(u.Ref);if(u["Fn::GetAtt"]){let h=u["Fn::GetAtt"];if(Array.isArray(h)&&h.length>0)g.push(h[0])}for(let h of Object.values(u))jc(h,g);return g}function xp(u){let g=[],h=[],y=new TextEncoder().encode(u).length,R=51200,v=460800;if(y>51200)if(y>460800)g.push({path:"template",message:`Template size (${y} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else h.push({path:"template",message:`Template size (${y} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:g.length===0,errors:g,warnings:h}}function _p(u){let g=[],h=[],y=u.Resources?Object.keys(u.Resources).length:0,R=u.Parameters?Object.keys(u.Parameters).length:0,v=u.Outputs?Object.keys(u.Outputs).length:0;if(y>500)g.push({path:"Resources",message:`Template has ${y} resources, exceeding the limit of 500`,severity:"error"});else if(y>200)h.push({path:"Resources",message:`Template has ${y} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(R>200)g.push({path:"Parameters",message:`Template has ${R} parameters, exceeding the limit of 200`,severity:"error"});if(v>200)g.push({path:"Outputs",message:`Template has ${v} outputs, exceeding the limit of 200`,severity:"error"});return{valid:g.length===0,errors:g,warnings:h}}function kR(u){let{domains:g,email:h,staging:y=!1,challengeType:R="http-01",certPath:v="/etc/letsencrypt/live",autoRenew:P=!0}=u,M=g[0],V=g.map((ye)=>`-d ${ye}`).join(" "),Ae=y?"--staging":"";if(R==="http-01")return Bp({domains:g,email:h,staging:y,certPath:v,autoRenew:P,domainFlags:V,stagingFlag:Ae,primaryDomain:M});else{let ye=u.dnsProvider?.provider||(u.hostedZoneId?"route53":void 0);return ag({domains:g,email:h,staging:y,certPath:v,autoRenew:P,domainFlags:V,stagingFlag:Ae,primaryDomain:M,hostedZoneId:u.hostedZoneId,dnsProvider:u.dnsProvider,dnsProviderType:ye})}}function Bp(u){let{email:g,certPath:h,autoRenew:y,domainFlags:R,stagingFlag:v,primaryDomain:P}=u;return`
222
+ `}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function Ip(u){let g=[],h=[];if(!u.AWSTemplateFormatVersion)g.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(u.AWSTemplateFormatVersion!=="2010-09-09")h.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!u.Resources||Object.keys(u.Resources).length===0)g.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[S,A]of Object.entries(u.Resources))Dp(S,A,g,h);if(u.Resources){let S=Ep(u.Resources);if(S.length>0)g.push({path:"Resources",message:`Circular dependencies detected: ${S.join(" -> ")}`,severity:"error"})}if(u.Parameters)for(let[S,A]of Object.entries(u.Parameters))kp(S,A,g,h);if(u.Outputs)for(let[S,A]of Object.entries(u.Outputs))vp(S,A,g,h);return{valid:g.length===0,errors:g,warnings:h}}function Dp(u,g,h,S){if(!g.Type)h.push({path:`Resources.${u}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(u))S.push({path:`Resources.${u}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(g.Type&&!g.Type.startsWith("AWS::")&&!g.Type.startsWith("Custom::"))h.push({path:`Resources.${u}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(g.Properties){for(let[A,T]of Object.entries(g.Properties))if(T===void 0||T===null)S.push({path:`Resources.${u}.Properties.${A}`,message:"Property has undefined or null value",severity:"warning"})}if(g.DependsOn){if(typeof g.DependsOn==="string"){if(g.DependsOn===u)h.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(g.DependsOn)){if(g.DependsOn.includes(u))h.push({path:`Resources.${u}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function kp(u,g,h,S){if(!g.Type)h.push({path:`Parameters.${u}.Type`,message:"Parameter Type is required",severity:"error"});let A=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(g.Type&&!A.includes(g.Type)&&!g.Type.startsWith("AWS::"))S.push({path:`Parameters.${u}.Type`,message:`Uncommon parameter type: ${g.Type}`,severity:"warning"});if(g.NoEcho&&g.Default)S.push({path:`Parameters.${u}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function vp(u,g,h,S){if(!g.Value)h.push({path:`Outputs.${u}.Value`,message:"Output Value is required",severity:"error"})}function Ep(u){let g={};for(let[P,M]of Object.entries(u)){if(g[P]=[],M.DependsOn){if(typeof M.DependsOn==="string")g[P].push(M.DependsOn);else if(Array.isArray(M.DependsOn))g[P].push(...M.DependsOn)}let W=zc(M);g[P].push(...W)}let h=new Set,S=new Set,A=[];function T(P,M){h.add(P),S.add(P),M.push(P);let W=g[P]||[];for(let le of W)if(!h.has(le)){if(T(le,M))return!0}else if(S.has(le)){let K=M.indexOf(le);return A.push(...M.slice(K),le),!0}return M.pop(),S.delete(P),!1}for(let P of Object.keys(g))if(!h.has(P)){if(T(P,[]))return A}return[]}function zc(u,g=[]){if(typeof u!=="object"||u===null)return g;if(Array.isArray(u)){for(let h of u)zc(h,g);return g}if(u.Ref&&typeof u.Ref==="string"&&!u.Ref.startsWith("AWS::"))g.push(u.Ref);if(u["Fn::GetAtt"]){let h=u["Fn::GetAtt"];if(Array.isArray(h)&&h.length>0)g.push(h[0])}for(let h of Object.values(u))zc(h,g);return g}function xp(u){let g=[],h=[],S=new TextEncoder().encode(u).length,A=51200,T=460800;if(S>51200)if(S>460800)g.push({path:"template",message:`Template size (${S} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else h.push({path:"template",message:`Template size (${S} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:g.length===0,errors:g,warnings:h}}function Lp(u){let g=[],h=[],S=u.Resources?Object.keys(u.Resources).length:0,A=u.Parameters?Object.keys(u.Parameters).length:0,T=u.Outputs?Object.keys(u.Outputs).length:0;if(S>500)g.push({path:"Resources",message:`Template has ${S} resources, exceeding the limit of 500`,severity:"error"});else if(S>200)h.push({path:"Resources",message:`Template has ${S} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(A>200)g.push({path:"Parameters",message:`Template has ${A} parameters, exceeding the limit of 200`,severity:"error"});if(T>200)g.push({path:"Outputs",message:`Template has ${T} outputs, exceeding the limit of 200`,severity:"error"});return{valid:g.length===0,errors:g,warnings:h}}function vR(u){let{domains:g,email:h,staging:S=!1,challengeType:A="http-01",certPath:T="/etc/letsencrypt/live",autoRenew:P=!0}=u,M=g[0],W=g.map((K)=>`-d ${K}`).join(" "),le=S?"--staging":"";if(A==="http-01")return _p({domains:g,email:h,staging:S,certPath:T,autoRenew:P,domainFlags:W,stagingFlag:le,primaryDomain:M});else{let K=u.dnsProvider?.provider||(u.hostedZoneId?"route53":void 0);return Bp({domains:g,email:h,staging:S,certPath:T,autoRenew:P,domainFlags:W,stagingFlag:le,primaryDomain:M,hostedZoneId:u.hostedZoneId,dnsProvider:u.dnsProvider,dnsProviderType:K})}}function _p(u){let{email:g,certPath:h,autoRenew:S,domainFlags:A,stagingFlag:T,primaryDomain:P}=u;return`
223
223
  # ==========================================
224
224
  # Let's Encrypt Certificate Setup (HTTP-01)
225
225
  # ==========================================
@@ -236,8 +236,8 @@ certbot certonly \\
236
236
  --non-interactive \\
237
237
  --agree-tos \\
238
238
  --email ${g} \\
239
- ${v} \\
240
- ${R}
239
+ ${T} \\
240
+ ${A}
241
241
 
242
242
  # Check if certificate was obtained
243
243
  if [ -f "${h}/${P}/fullchain.pem" ]; then
@@ -253,11 +253,11 @@ else
253
253
  echo "Failed to obtain certificate!"
254
254
  fi
255
255
 
256
- ${y?Zc(P):"# Auto-renewal disabled"}
256
+ ${S?Kc(P):"# Auto-renewal disabled"}
257
257
 
258
258
  # Restart the application
259
259
  systemctl start stacks
260
- `}function ag(u){let{email:g,certPath:h,autoRenew:y,domainFlags:R,stagingFlag:v,primaryDomain:P,hostedZoneId:M,dnsProvider:V,dnsProviderType:Ae}=u;if(Ae==="route53"||M){if(!M)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
260
+ `}function Bp(u){let{email:g,certPath:h,autoRenew:S,domainFlags:A,stagingFlag:T,primaryDomain:P,hostedZoneId:M,dnsProvider:W,dnsProviderType:le}=u;if(le==="route53"||M){if(!M)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
261
261
  # ==========================================
262
262
  # Let's Encrypt Certificate Setup (DNS-01 via Route53)
263
263
  # ==========================================
@@ -271,8 +271,8 @@ certbot certonly \\
271
271
  --non-interactive \\
272
272
  --agree-tos \\
273
273
  --email ${g} \\
274
- ${v} \\
275
- ${R}
274
+ ${T} \\
275
+ ${A}
276
276
 
277
277
  # Check if certificate was obtained
278
278
  if [ -f "${h}/${P}/fullchain.pem" ]; then
@@ -288,31 +288,31 @@ else
288
288
  echo "Failed to obtain certificate!"
289
289
  fi
290
290
 
291
- ${y?Zc(P):"# Auto-renewal disabled"}
292
- `}if(!V)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let ye=V.provider.toUpperCase(),At=cg(V);return`
291
+ ${S?Kc(P):"# Auto-renewal disabled"}
292
+ `}if(!W)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let K=W.provider.toUpperCase(),Ct=cg(W);return`
293
293
  # ==========================================
294
- # Let's Encrypt Certificate Setup (DNS-01 via ${ye})
294
+ # Let's Encrypt Certificate Setup (DNS-01 via ${K})
295
295
  # ==========================================
296
296
 
297
297
  # Install certbot
298
298
  dnf install -y certbot jq curl
299
299
 
300
- ${At}
300
+ ${Ct}
301
301
 
302
302
  # Create DNS challenge hook scripts directory
303
303
  mkdir -p /etc/letsencrypt/hooks
304
304
 
305
- # Create authenticator hook for ${ye}
305
+ # Create authenticator hook for ${K}
306
306
  cat > /etc/letsencrypt/hooks/auth-hook.sh << 'AUTHHOOK'
307
307
  #!/bin/bash
308
- # DNS-01 authenticator hook for ${ye}
308
+ # DNS-01 authenticator hook for ${K}
309
309
  # This creates the TXT record for ACME challenge
310
310
 
311
311
  DOMAIN="$CERTBOT_DOMAIN"
312
312
  VALIDATION="$CERTBOT_VALIDATION"
313
313
  RECORD_NAME="_acme-challenge.$DOMAIN"
314
314
 
315
- ${lg(V)}
315
+ ${lg(W)}
316
316
 
317
317
  # Wait for DNS propagation
318
318
  echo "Waiting 60 seconds for DNS propagation..."
@@ -321,17 +321,17 @@ AUTHHOOK
321
321
 
322
322
  chmod +x /etc/letsencrypt/hooks/auth-hook.sh
323
323
 
324
- # Create cleanup hook for ${ye}
324
+ # Create cleanup hook for ${K}
325
325
  cat > /etc/letsencrypt/hooks/cleanup-hook.sh << 'CLEANUPHOOK'
326
326
  #!/bin/bash
327
- # DNS-01 cleanup hook for ${ye}
327
+ # DNS-01 cleanup hook for ${K}
328
328
  # This removes the TXT record after validation
329
329
 
330
330
  DOMAIN="$CERTBOT_DOMAIN"
331
331
  VALIDATION="$CERTBOT_VALIDATION"
332
332
  RECORD_NAME="_acme-challenge.$DOMAIN"
333
333
 
334
- ${ug(V)}
334
+ ${ug(W)}
335
335
  CLEANUPHOOK
336
336
 
337
337
  chmod +x /etc/letsencrypt/hooks/cleanup-hook.sh
@@ -345,8 +345,8 @@ certbot certonly \\
345
345
  --non-interactive \\
346
346
  --agree-tos \\
347
347
  --email ${g} \\
348
- ${v} \\
349
- ${R}
348
+ ${T} \\
349
+ ${A}
350
350
 
351
351
  # Check if certificate was obtained
352
352
  if [ -f "${h}/${P}/fullchain.pem" ]; then
@@ -362,7 +362,7 @@ else
362
362
  echo "Failed to obtain certificate!"
363
363
  fi
364
364
 
365
- ${y?Zc(P):"# Auto-renewal disabled"}
365
+ ${S?Kc(P):"# Auto-renewal disabled"}
366
366
  `}function cg(u){switch(u.provider){case"porkbun":return`
367
367
  # Porkbun API credentials
368
368
  export PORKBUN_API_KEY="${u.apiKey}"
@@ -470,7 +470,7 @@ fi
470
470
 
471
471
  curl -s -X DELETE "$API_URL/v1/domains/$ROOT_DOMAIN/records/TXT/$RECORD_NAME" \\
472
472
  -H "Authorization: sso-key $GODADDY_API_KEY:$GODADDY_API_SECRET"
473
- `;default:return'echo "Unsupported DNS provider"'}}function Zc(u){return`
473
+ `;default:return'echo "Unsupported DNS provider"'}}function Kc(u){return`
474
474
  # ==========================================
475
475
  # Certificate Auto-Renewal Setup
476
476
  # ==========================================
@@ -515,11 +515,11 @@ systemctl enable certbot-renewal.timer
515
515
  systemctl start certbot-renewal.timer
516
516
 
517
517
  echo "Certificate auto-renewal configured"
518
- `}function vR(u){let{httpPort:g=80,httpsPort:h=443,certPath:y="/etc/ssl/stacks",redirectHttp:R=!0}=u;return`
518
+ `}function ER(u){let{httpPort:g=80,httpsPort:h=443,certPath:S="/etc/ssl/stacks",redirectHttp:A=!0}=u;return`
519
519
  // HTTPS Server with Let's Encrypt certificates
520
520
  import { existsSync } from 'node:fs'
521
521
 
522
- const CERT_PATH = '${y}'
522
+ const CERT_PATH = '${S}'
523
523
  const HTTP_PORT = ${g}
524
524
  const HTTPS_PORT = ${h}
525
525
 
@@ -541,7 +541,7 @@ if (hasCerts) {
541
541
  })
542
542
  console.log(\`HTTPS server running on port \${HTTPS_PORT}\`)
543
543
 
544
- ${R?`
544
+ ${A?`
545
545
  // Start HTTP server for redirect
546
546
  const httpServer = Bun.serve({
547
547
  port: HTTP_PORT,
@@ -601,5 +601,5 @@ async function handleRequest(request: Request): Promise<Response> {
601
601
  // Implement your request handling here
602
602
  return new Response('Hello from Stacks!')
603
603
  }
604
- `}async function dg(u,g,h){let y=`_acme-challenge.${g}`;if(await mg(u,g,y,h))return;let R=await u.createRecord(g,{name:y,type:"TXT",content:h,ttl:60});if(!R.success)throw Error(`Failed to create DNS challenge record: ${R.message}`)}async function pg(u,g,h){let y=await u.deleteRecord(g,{name:`_acme-challenge.${g}`,type:"TXT",content:h});if(!y.success)console.warn(`Failed to delete DNS challenge record: ${y.message}`)}async function mg(u,g,h,y){try{let R=await u.listRecords(g,"TXT"),v=h.replace(/\.$/,"").toLowerCase();return(R.records??[]).some((P)=>P.name.replace(/\.$/,"").toLowerCase()===v&&P.content.replace(/^"|"$/g,"")===y)}catch{return!1}}function yd(u){let{hostedZoneId:g,dnsProvider:h,region:y="us-east-1"}=u;if(h)return B(h);if(g)return new se(y,g);throw Error("Either dnsProvider or hostedZoneId must be provided")}async function ER(u){await dg(yd(u),u.domain,u.challengeValue)}async function OR(u){await pg(yd(u),u.domain,u.challengeValue)}function NR(u){try{let{execSync:g}=ls("node:child_process"),h=g(`openssl x509 -checkend 2592000 -noout -in ${u}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as Cd,createSign as fg,generateKeyPairSync as Sd}from"node:crypto";var bd={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class Cg{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(u){this.directoryUrl=u.staging?bd.staging:bd.production,this.email=u.email,this.accountKey=u.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:u}=Sd("ec",{namedCurve:"P-256"});return u.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let u=await fetch(this.directoryUrl);if(!u.ok)throw Error(`Failed to fetch ACME directory: ${u.status}`);return this.directory=await u.json(),this.directory}async getNonce(){if(this.nonce){let y=this.nonce;return this.nonce=null,y}let u=await this.getDirectory(),h=(await fetch(u.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!h)throw Error("Failed to get nonce from ACME server");return h}getJwk(){let u=this.accountKey.split(`
605
- `).filter((v)=>!v.startsWith("-----")).join(""),g=Buffer.from(u,"base64"),h=g.length-65,y=g.subarray(h+1,h+33),R=g.subarray(h+33,h+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(y),y:this.base64UrlEncode(R)}}getJwkThumbprint(){let u=this.getJwk(),g=JSON.stringify({crv:u.crv,kty:u.kty,x:u.x,y:u.y}),h=Cd("sha256").update(g).digest();return this.base64UrlEncode(h)}base64UrlEncode(u){return(typeof u==="string"?Buffer.from(u):u).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(u,g){let h=await this.getNonce(),y=this.getJwk(),R={alg:"ES256",nonce:h,url:u};if(this.accountUrl)R.kid=this.accountUrl;else R.jwk=y;let v=this.base64UrlEncode(JSON.stringify(R)),P=g===""?"":this.base64UrlEncode(JSON.stringify(g)),M=`${v}.${P}`,V=fg("SHA256");V.update(M);let Ae=V.sign(this.accountKey),ye=Ae.subarray(4,4+Ae[3]),At=4+Ae[3]+2,Tt=Ae.subarray(At,At+Ae[At-1]),Je=Buffer.alloc(32),Ue=Buffer.alloc(32);ye.copy(Je,32-ye.length),Tt.copy(Ue,32-Tt.length);let je=Buffer.concat([Je,Ue]);return JSON.stringify({protected:v,payload:P,signature:this.base64UrlEncode(je)})}async acmeRequest(u,g){let h=await this.signPayload(u,g),y=await fetch(u,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:h}),R=y.headers.get("replay-nonce");if(R)this.nonce=R;let v,P=y.headers.get("content-type");if(P?.includes("application/json")||P?.includes("application/problem+json"))v=await y.json();else v=await y.text();if(!y.ok)throw Error(`ACME request failed: ${JSON.stringify(v)}`);return{body:v,headers:y.headers}}async registerAccount(){let u=await this.getDirectory(),{body:g,headers:h}=await this.acmeRequest(u.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),y=h.get("location");if(!y)throw Error("No account URL returned");return this.accountUrl=y,y}async createOrder(u){if(!this.accountUrl)await this.registerAccount();let g=await this.getDirectory(),{body:h,headers:y}=await this.acmeRequest(g.newOrder,{identifiers:u.map((v)=>({type:"dns",value:v}))}),R=y.get("location");if(!R)throw Error("No order URL returned");return{orderUrl:R,authorizations:h.authorizations,finalize:h.finalize}}async getAuthorization(u){let{body:g}=await this.acmeRequest(u,""),h=g.identifier.value,y=this.getJwkThumbprint(),R=g.challenges.filter((v)=>v.type==="http-01"||v.type==="dns-01").map((v)=>{let P=`${v.token}.${y}`;if(v.type==="http-01")return{type:"http-01",token:v.token,keyAuthorization:P,identifier:`/.well-known/acme-challenge/${v.token}`};else{let M=this.base64UrlEncode(Cd("sha256").update(P).digest());return{type:"dns-01",token:v.token,keyAuthorization:P,identifier:`_acme-challenge.${h}`,dnsValue:M}}});return{domain:h,challenges:R}}async respondToChallenge(u){await this.acmeRequest(u,{})}async waitForAuthorization(u,g=30){for(let h=0;h<g;h++){let{body:y}=await this.acmeRequest(u,"");if(y.status==="valid")return;if(y.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(y)}`);await new Promise((R)=>setTimeout(R,2000))}throw Error("Authorization timed out")}generateCsr(u){let{privateKey:g}=Sd("rsa",{modulusLength:2048}),h=g.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(u,g),privateKey:h}}createSimpleCsr(u,g){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(u,g){let{csr:h,privateKey:y}=this.generateCsr(g),{body:R}=await this.acmeRequest(u,{csr:this.base64UrlEncode(Buffer.from(h,"base64"))}),v=R.certificate;if(!v)throw Error("Certificate not immediately available - polling not implemented");let M=await(await fetch(v)).text(),V=M.split(/(?=-----BEGIN CERTIFICATE-----)/g),Ae=V[0],ye=V.slice(1).join("");return{certificate:Ae,privateKey:y,chain:ye,fullchain:M,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var Ur=(u)=>u===void 0?void 0:u?"on":"off";function Jc(u){let g={ssl:u.ssl,always_use_https:Ur(u.alwaysUseHttps),automatic_https_rewrites:Ur(u.automaticHttpsRewrites),min_tls_version:u.minTlsVersion,tls_1_3:Ur(u.tls13),brotli:Ur(u.brotli),http3:Ur(u.http3),"0rtt":Ur(u.zeroRtt),early_hints:Ur(u.earlyHints),browser_cache_ttl:u.browserCacheTtl,always_online:Ur(u.alwaysOnline),websockets:Ur(u.websockets),email_obfuscation:Ur(u.emailObfuscation)};if(u.hsts)g.security_header={strict_transport_security:{enabled:u.hsts.enabled,max_age:u.hsts.maxAge??31536000,include_subdomains:u.hsts.includeSubdomains??!1,preload:u.hsts.preload??!1,nosniff:u.hsts.noSniff??!0}};for(let h of Object.keys(g))if(g[h]===void 0)delete g[h];return{...g,...u.raw??{}}}var Ei={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 bg}from"node:tls";async function Xc(u){let{address:g,serverName:h,port:y=443,timeoutMs:R=5000}=u;return new Promise((v)=>{let P=!1,M=(Ae)=>{if(P)return;P=!0;try{V.destroy()}catch{}v(Ae)},V=bg({host:g,port:y,servername:h,rejectUnauthorized:!1,timeout:R});V.once("secureConnect",()=>{if(V.authorized){M({reachable:!0,trusted:!0});return}M({reachable:!0,trusted:!1,reason:V.authorizationError?String(V.authorizationError):"origin certificate is not trusted for this hostname"})}),V.once("timeout",()=>{M({reachable:!1,trusted:!1,reason:`no TLS handshake within ${R}ms`})}),V.once("error",(Ae)=>{M({reachable:!1,trusted:!1,reason:Ae.message})})})}function kg(u,g){let h=g.replace(/\.$/,"").toLowerCase();return u.some((y)=>{let R=y.replace(/\.$/,"").toLowerCase();if(R===h)return!0;if(!R.startsWith("*."))return!1;let v=R.slice(2);if(!h.endsWith(`.${v}`))return!1;return!h.slice(0,h.length-v.length-1).includes(".")})}async function Og(u){let{provider:g,zone:h,hosts:y,ipv4:R,ipv6:v,proxied:P=!0,settings:M=Ei,cache:V,originGuard:Ae,purge:ye=!0,ttl:At=300,skipOriginProbe:Tt=!1,skipEdgeCertificateCheck:Je=!1}=u,Ue={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(y.length===0)return Ue;let je=[],K=P&&!Je?await g.listEdgeCertificateHosts(h):null;for(let z of y){let Xe=P;if(Xe&&K&&!kg(K,z)){Xe=!1;let vt=K.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${K.join(", ")})`;Ue.deferredProxy.push({host:z,reason:vt}),Ue.warnings.push(`${z}: publishing DNS-only — ${vt}. 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(Xe&&!Tt){let vt=await Xc({address:R,serverName:z});if(!vt.trusted){Xe=!1;let Et=vt.reason||"origin is not serving a trusted certificate";Ue.deferredProxy.push({host:z,reason:Et}),Ue.warnings.push(`${z}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${Et}). 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(Xe)je.push(z);let bt=[{type:"A",content:R}];if(v&&ei(z))bt.push({type:"AAAA",content:v});for(let{type:vt,content:Et}of bt){let Ht=await g.upsertRecord(h,{name:z,type:vt,content:Et,ttl:At,proxied:Xe});if(Ht.success)Ue.records.push({host:z,type:vt,content:Et,proxied:Xe});else Ue.warnings.push(`${z} ${vt} → ${Et} failed: ${Ht.message||"unknown provider error"}`)}}if(je.length===0){if(P)Ue.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return Ue}try{let z=Jc(M),Xe=await g.applyZoneSettings(h,z);Ue.settingsChanged=Xe.changed;for(let bt of Xe.failed)Ue.warnings.push(`zone setting '${bt.id}' could not be applied: ${bt.error}`)}catch(z){Ue.warnings.push(`zone settings could not be read: ${z instanceof Error?z.message:String(z)}`)}let St=Fc(je,V);if(St.length>0){let z=await g.putManagedPhaseRules(h,"http_request_cache_settings",St);if(z.success)Ue.cacheRules=St.length;else Ue.warnings.push(`cache rules could not be written: ${z.message}`)}if(Ae){let z=Uc(je,Ae.header,Ae.value);if(z.length>0){let Xe=await g.putManagedPhaseRules(h,"http_request_late_transform",z);if(Xe.success)Ue.originGuard=!0;else Ue.warnings.push(`origin guard header could not be written: ${Xe.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(ye){if(Ue.purged=await g.purgeCache(h,{hosts:je}),!Ue.purged)Ue.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Ue}var Ng=(u)=>process.env[u];function Id(u,g){let h=u.replace(/\.$/,"").toLowerCase();if(g){let y=g.replace(/\.$/,"").toLowerCase();if(h===y||h.endsWith(`.${y}`))return y}return h.split(".").slice(-2).join(".")}function xg(u,g={}){let h=g.env??Ng,y=u.infrastructure?.compute?.proxy?.cdn,R=[];if(!y||y.provider!=="cloudflare")return{plan:null,errors:R};if(y.originDomain)R.push(`compute.proxy.cdn.originDomain (${y.originDomain}) is ignored for Cloudflare: the proxy forwards to the address in the record it fronts, `+"so no separate origin hostname is needed — and publishing one gives clients a documented way around the edge.");let v=h("CLOUDFLARE_API_TOKEN");if(!v)return R.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:R};let P=u.sites??{},M=y.frontedHosts?.length?[...new Set(y.frontedHosts.map((Tt)=>Tt.toLowerCase()))]:bo(P,{autoWww:u.infrastructure?.compute?.proxy?.autoWww!==!1});if(M.length===0)return R.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:R};let V=u.infrastructure?.dns?.domain,Ae=new Set(M.map((Tt)=>Id(Tt,V)));if(Ae.size>1)return R.push(`Fronted hosts span more than one zone (${[...Ae].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:R};let ye=y.cloudflare??{},At=y.secret?{header:y.secretHeader??"X-Origin-Verify",value:y.secret}:void 0;return{plan:{zone:[...Ae][0],hosts:M,apiToken:v,zoneId:ye.zoneId??h("CLOUDFLARE_ZONE_ID"),accountId:ye.accountId??h("CLOUDFLARE_ACCOUNT_ID"),proxied:ye.proxied!==!1,settings:ye.settings??Ei,cache:ye.cache,originGuard:At,purge:ye.purgeOnDeploy!==!1,skipOriginProbe:ye.skipOriginProbe===!0},errors:R}}var Lg=26214400;var _g=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class ep{name="cloudflare-pages";apiToken;accountId;constructor(u){if(!u.apiToken)throw Error("Cloudflare Pages needs an API token");if(!u.accountId)throw Error("Cloudflare Pages needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId}async request(u,g,h){return Ds(u,`/accounts/${this.accountId}${g}`,`Bearer ${this.apiToken}`,h)}async getProject(u){try{return await this.request("GET",`/pages/projects/${u}`)}catch(g){if(g instanceof Error&&/\b8000007\b|not found/i.test(g.message))return null;throw g}}async ensureProject(u,g="main"){let h=await this.getProject(u);if(h)return h;return this.request("POST","/pages/projects",{name:u,production_branch:g})}async uploadToken(u){return(await this.request("GET",`/pages/projects/${u}/upload-token`)).jwt}async missingHashes(u,g){let h=await Ds("POST","/pages/assets/check-missing",`Bearer ${u}`,{hashes:g});return new Set(h)}async upsertHashes(u,g){await Ds("POST","/pages/assets/upsert-hashes",`Bearer ${u}`,{hashes:g})}async uploadBatch(u,g){let h=g.map((y)=>({key:y.hash,value:y.base64,metadata:{contentType:zg(y.extension)},base64:!0}));await Ds("POST","/pages/assets/upload",`Bearer ${u}`,h)}async createDeployment(u,g,h){let y={};for(let v of g)y[v.path]=v.hash;let R=new FormData;if(R.append("manifest",JSON.stringify(y)),h)R.append("branch",h);return this.request("POST",`/pages/projects/${u}/deployments`,R)}async deployDirectory(u){let g=await rp(u.directory);if(g.length===0)throw Error(`No files to deploy in ${u.directory}`);let h=await this.uploadToken(u.project),y=await this.missingHashes(h,g.map((V)=>V.hash)),R=g.filter((V)=>y.has(V.hash)),v=[];for(let V=0;V<R.length;V+=100)v.push(R.slice(V,V+100));let P=0;for(let V=0;V<v.length;V+=4){let Ae=v.slice(V,V+4);await Promise.all(Ae.map((ye)=>this.uploadBatch(h,ye))),P+=Ae.reduce((ye,At)=>ye+At.length,0),u.onProgress?.(P,R.length)}return await this.upsertHashes(h,g.map((V)=>V.hash)),{deployment:await this.createDeployment(u.project,g,u.branch),total:g.length,uploaded:R.length,uploadedBytes:R.reduce((V,Ae)=>V+Ae.size,0)}}async listCustomDomains(u){return(await this.request("GET",`/pages/projects/${u}/domains`)).map((h)=>h.name)}async attachCustomDomain(u,g){if((await this.listCustomDomains(u)).includes(g))return!1;return await this.request("POST",`/pages/projects/${u}/domains`,{name:g}),!0}}function Wg(u,g){return{type:"CNAME",name:u,value:g.endsWith(".pages.dev")?g:`${g}.pages.dev`,ttl:1,proxied:!0}}async function tp(u,g){let{blake3:h}=await import("./chunk-q7yf28cc.js").then((m)=>LS(m.default,1));return(await h(u+g)).slice(0,32)}async function rp(u){let{readdir:g}=await import("node:fs/promises"),{join:h,relative:y,sep:R}=await import("node:path"),v=[];async function P(M){let V=await g(M,{withFileTypes:!0});for(let Ae of V){let ye=h(M,Ae.name);if(Ae.isDirectory()){await P(ye);continue}if(!Ae.isFile())continue;let At=`/${y(u,ye).split(R).join("/")}`;if(_g.has(At))continue;let Tt=await Bun.file(ye).bytes();if(Tt.byteLength>26214400)throw Error(`${At} is ${Tt.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let Je=Buffer.from(Tt).toString("base64"),Ue=Ae.name.lastIndexOf("."),je=Ue>0?Ae.name.slice(Ue+1):"";v.push({path:At,hash:await tp(Je,je),base64:Je,extension:je,size:Tt.byteLength})}}return await P(u),v.sort((M,V)=>M.path.localeCompare(V.path)),v}function zg(u){return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",mjs:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",map:"application/json; charset=utf-8",xml:"application/xml; charset=utf-8",txt:"text/plain; charset=utf-8",svg:"image/svg+xml",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",avif:"image/avif",ico:"image/x-icon",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",pdf:"application/pdf",webmanifest:"application/manifest+json"}[u.toLowerCase()]||"application/octet-stream"}async function Ds(u,g,h,y){let R={Authorization:h},v;if(y instanceof FormData)v=y;else if(y!==void 0)R["Content-Type"]="application/json",v=JSON.stringify(y);let P=await fetch(`https://api.cloudflare.com/client/v4${g}`,{method:u,headers:R,body:v}),M=await P.text(),V;try{V=JSON.parse(M)}catch{throw Error(`Cloudflare Pages API returned ${P.status} with a non-JSON body: ${M.slice(0,200)}`)}if(!V.success){let Ae=(V.errors??[]).map((ye)=>`${ye.code}: ${ye.message}`).join(", ");throw Error(`Cloudflare Pages API error (${P.status}): ${Ae||M.slice(0,200)}`)}return V.result}import{createHash as jg}from"node:crypto";var ip="https://api.cloudflare.com/client/v4",op=10042,Kg=10006,qg=10059;class _n extends Error{status;errors;constructor(u,g,h=[]){super(u);this.name="R2ApiError",this.status=g,this.errors=h}hasCode(u){return this.errors.some((g)=>g.code===u)}}class Sn extends _n{accountId;constructor(u,g,h=[]){super(`R2 is not enabled on Cloudflare account ${u}. Enable it once in the Cloudflare dashboard (R2 Object Storage, then follow the prompt to activate it), then re-run the deploy.`,g,h);this.name="R2NotEnabledError",this.accountId=u}}class ui{name="cloudflare-r2";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare R2 needs an API token");if(!u.accountId)throw Error("Cloudflare R2 needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((g,h)=>fetch(g,h))}async requestEnvelope(u,g,h,y={}){let R={Authorization:`Bearer ${this.apiToken}`};if(h!==void 0)R["Content-Type"]="application/json";if(y.jurisdiction&&y.jurisdiction!=="default")R["cf-r2-jurisdiction"]=y.jurisdiction;let v=await this.fetchImpl(`${ip}/accounts/${this.accountId}/r2${g}`,{method:u,headers:R,body:h===void 0?void 0:JSON.stringify(h)}),P=await v.text(),M;try{M=JSON.parse(P)}catch{throw new _n(`Cloudflare R2 API returned ${v.status} with a non-JSON body: ${P.slice(0,200)}`,v.status)}if(!M.success){let V=M.errors??[];if(V.some((ye)=>ye.code===op))throw new Sn(this.accountId,v.status,V);let Ae=V.map((ye)=>`${ye.code}: ${ye.message}`).join(", ");throw new _n(`Cloudflare R2 API error (${v.status}) on ${u} ${g}: ${Ae||P.slice(0,200)}`,v.status,V)}return M}async request(u,g,h,y){return(await this.requestEnvelope(u,g,h,y)).result}bucketPath(u){return`/buckets/${encodeURIComponent(u)}`}async listBuckets(u={}){let g=[],h;do{let y=new URLSearchParams({per_page:"1000"});if(h)y.set("cursor",h);let R=await this.requestEnvelope("GET",`/buckets?${y}`,void 0,u),v=R.result?.buckets??[];g.push(...v),h=v.length>0?R.result_info?.cursor||void 0:void 0}while(h);return g}async getBucket(u,g={}){try{return await this.request("GET",this.bucketPath(u),void 0,g)}catch(h){if(h instanceof Sn)throw h;if(h instanceof _n&&(h.hasCode(Kg)||h.status===404))return null;throw h}}async ensureBucket(u,g={}){let h={jurisdiction:g.jurisdiction},y=await this.getBucket(u,h);if(y)return{bucket:y,created:!1};let R={name:u};if(g.locationHint)R.locationHint=g.locationHint;let v=await this.request("POST","/buckets",R,h);return{bucket:{...v,name:v?.name||u},created:!0}}async getCors(u,g={}){try{return(await this.request("GET",`${this.bucketPath(u)}/cors`,void 0,g))?.rules??[]}catch(h){if(h instanceof _n&&!(h instanceof Sn)&&(h.hasCode(qg)||h.status===404))return[];throw h}}async putCors(u,g,h={}){if(g.length===0){await this.request("DELETE",`${this.bucketPath(u)}/cors`,void 0,h);return}await this.request("PUT",`${this.bucketPath(u)}/cors`,{rules:g},h)}async ensureCors(u,g,h={}){let y=await this.getCors(u,h);if(ks(y,g))return!1;return await this.putCors(u,g,h),!0}async getLifecycle(u,g={}){return(await this.request("GET",`${this.bucketPath(u)}/lifecycle`,void 0,g))?.rules??[]}async putLifecycle(u,g,h={}){await this.request("PUT",`${this.bucketPath(u)}/lifecycle`,{rules:g},h)}async ensureLifecycle(u,g,h={}){let y=await this.getLifecycle(u,h);if(Fs(y,g))return!1;return await this.putLifecycle(u,g,h),!0}async listCustomDomains(u,g={}){return(await this.request("GET",`${this.bucketPath(u)}/domains/custom`,void 0,g))?.domains??[]}async attachCustomDomain(u,g,h={}){return this.request("POST",`${this.bucketPath(u)}/domains/custom`,{domain:g.domain,zoneId:g.zoneId,enabled:g.enabled??!0,minTLS:g.minTLS??"1.2"},h)}async updateCustomDomain(u,g,h,y={}){return this.request("PUT",`${this.bucketPath(u)}/domains/custom/${encodeURIComponent(g)}`,h,y)}async ensureCustomDomain(u,g,h={},y){let R=g.minTLS??"1.2",P=(y??await this.listCustomDomains(u,h)).find((Ae)=>Ae.domain.toLowerCase()===g.domain.toLowerCase());if(!P){let Ae=await this.attachCustomDomain(u,{...g,minTLS:R,enabled:!0},h);return{action:"attached",domain:{...Ae,domain:Ae?.domain||g.domain}}}let M=P.minTLS??"1.0";if(P.enabled&&M===R)return{action:"unchanged",domain:P};let V=await this.updateCustomDomain(u,P.domain,{enabled:!0,minTLS:R},h);return{action:"updated",domain:{...P,...V}}}async getManagedDomain(u,g={}){return this.request("GET",`${this.bucketPath(u)}/domains/managed`,void 0,g)}async setManagedDomain(u,g,h={}){let y=await this.getManagedDomain(u,h);if(y?.enabled===g)return{changed:!1,domain:y};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(u)}/domains/managed`,{enabled:g},h)}}}function sp(u){return`https://${u}.r2.cloudflarestorage.com`}async function Zg(u){let{apiToken:g,accountId:h}=u;if(!g)throw Error("r2S3Credentials needs an API token");if(!h)throw Error("r2S3Credentials needs an account id");let y=u.fetch??((P,M)=>fetch(P,M)),R=[],v;for(let P of[`/accounts/${h}/tokens/verify`,"/user/tokens/verify"]){let M=await y(`${ip}${P}`,{method:"GET",headers:{Authorization:`Bearer ${g}`}}),V=await M.json().catch(()=>null);if(M.ok&&V?.success&&V.result?.id){v=V.result.id;break}let Ae=V?.errors?.map((ye)=>`${ye.code}: ${ye.message}`).join(", ");R.push(`${P} -> ${M.status}${Ae?` (${Ae})`:""}`)}if(!v)throw Error(`Could not verify the Cloudflare API token to derive R2 credentials: ${R.join("; ")}`);return{accessKeyId:v,secretAccessKey:jg("sha256").update(g).digest("hex"),endpoint:sp(h),region:"auto"}}function xi(u){if(Array.isArray(u))return`[${u.map(xi).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${xi(y)}`).join(",")}}`;return JSON.stringify(u)}function np(u,g){let h=(y)=>y&&y.length>0?[...y].map(String).sort():void 0;return{id:g?u.id:void 0,allowed:{origins:h(u.allowed?.origins),methods:h(u.allowed?.methods?.map((y)=>y.toUpperCase())),headers:h(u.allowed?.headers?.map((y)=>y.toLowerCase()))},exposeHeaders:h(u.exposeHeaders?.map((y)=>y.toLowerCase())),maxAgeSeconds:u.maxAgeSeconds}}function ks(u,g){if(u.length!==g.length)return!1;return g.every((h,y)=>{let R=h.id!==void 0;return xi(np(u[y],R))===xi(np(h,R))})}function Fs(u,g){if(u.length!==g.length)return!1;let h=(y)=>xi([...y].map((R)=>({...R,storageClassTransitions:R.storageClassTransitions?.length?R.storageClassTransitions:void 0})).sort((R,v)=>R.id.localeCompare(v.id)));return h(u)===h(g)}var Jg="r2 cache",Yg=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function Xg(u,g={}){let h=g.log??(()=>{}),y={buckets:[],warnings:[]},R=u.infrastructure?.r2??u.r2,v=Object.entries(R?.buckets??{});if(v.length===0)return h("R2: no buckets declared, skipping."),y;if(!g.apiToken||!g.accountId){let ye=[!g.apiToken&&"CLOUDFLARE_API_TOKEN",!g.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),At=`R2: ${v.length} bucket(s) declared but ${ye} is not set, skipping.`;return h(At),y.warnings.push(At),y}let P=g.dryRun===!0,M=new ui({apiToken:g.apiToken,accountId:g.accountId,fetch:g.fetch}),V=new G(g.apiToken,{zoneId:g.zoneId,accountId:g.accountId}),Ae=new Map;for(let[ye,At]of v){let Tt=At?.name;if(!Tt||!Yg.test(Tt)){y.warnings.push(`R2: bucket '${ye}' has an invalid name '${Tt??""}' (3-63 chars: lowercase letters, digits, hyphens), skipping.`);continue}h(`R2: ${P?"checking":"reconciling"} bucket ${Tt}...`);let Je={name:Tt,changes:[],domains:[]};if(y.buckets.push(Je),await Rh(At,{r2:M,cloudflare:V,dryRun:P,summary:Je,warnings:y.warnings,claimed:Ae,log:h}),Je.changes.length===0)h(`R2: ${Tt} is in sync.`);else for(let Ue of Je.changes)h(`R2: ${Tt}: ${Ue}`)}return y}async function Rh(u,g){let{r2:h,dryRun:y,summary:R,warnings:v}=g,P=u.name,M={jurisdiction:u.jurisdiction},V=(Je,Ue)=>{let je=y?Ue&&`would ${Ue}`:Je;if(je)R.changes.push(je)},Ae;if(y)Ae=await h.getBucket(P,M)!==null;else{let{created:Je}=await h.ensureBucket(P,{locationHint:u.locationHint,jurisdiction:u.jurisdiction});if(Ae=!0,Je)V("created","")}if(!Ae)V("","create bucket");let ye=$h(u.customDomains);await so(g,`cors on ${P}`,async()=>{if(!u.cors)return;if(!Ae){V("cors updated","set cors");return}let Je=await h.getCors(P,M);if(ks(Je,u.cors))return;if(!y)await h.putCors(P,u.cors,M);V(u.cors.length===0?"cors removed":"cors updated",u.cors.length===0?"remove cors":"update cors")}),await so(g,`lifecycle on ${P}`,async()=>{if(!u.lifecycle)return;let Je=u.lifecycle.map(lp);if(Ae){let Ue=await h.getLifecycle(P,M);if(Fs(Ue,Je))return}if(!y)await h.putLifecycle(P,Je,M);V("lifecycle updated","update lifecycle")}),await so(g,`r2.dev URL on ${P}`,async()=>{let Je=u.publicDevUrl===!0;if(!Ae){if(Je)V("r2.dev URL enabled","enable r2.dev URL");return}if((await h.getManagedDomain(P,M))?.enabled===Je)return;if(!y)await h.setManagedDomain(P,Je,M);V(Je?"r2.dev URL enabled":"r2.dev URL disabled",Je?"enable r2.dev URL":"disable r2.dev URL")});let At=[];if(ye.length>0&&Ae)try{At=await h.listCustomDomains(P,M)}catch(Je){if(Je instanceof Sn)throw Je;v.push(`R2: could not list custom domains on ${P}: ${td(Je)}`)}let Tt=new Map;for(let{domain:Je,minTLS:Ue}of ye){let je=g.claimed.get(Je);if(je&&je!==P){v.push(`R2: ${Je} is declared on both ${je} and ${P}; leaving it on ${je}.`);continue}g.claimed.set(Je,P);let K=At.find((z)=>z.domain.toLowerCase()===Je),St=Ue??"1.2";if(K&&K.enabled&&(K.minTLS??"1.0")===St){if(R.domains.push({domain:Je,status:ed(K)}),K.zoneId)Tt.set(Je,K.zoneId);continue}await so(g,`custom domain ${Je} on ${P}`,async()=>{if(K){if(!y)await h.updateCustomDomain(P,K.domain,{enabled:!0,minTLS:St},M);if(V(`custom domain ${Je} updated`,`update custom domain ${Je}`),R.domains.push({domain:Je,status:ed({...K,enabled:!0})}),K.zoneId)Tt.set(Je,K.zoneId);return}let z=await g.cloudflare.zoneIdFor(Je);if(Tt.set(Je,z),!y)await h.ensureCustomDomain(P,{domain:Je,zoneId:z,minTLS:St},M,At);V(`custom domain ${Je} attached`,`attach custom domain ${Je}`),R.domains.push({domain:Je,status:y?"not attached":"pending"})},()=>R.domains.push({domain:Je,status:"error"}))}if(u.cache&&ye.length>0)await Ph(u,ye.map((Je)=>Je.domain).filter((Je)=>g.claimed.get(Je)===P),Tt,g,V)}async function Ph(u,g,h,y,R){let v=ap(u.cache);if(!v||g.length===0)return;let P=new Map;for(let M of g){let V=h.get(M);if(!V)try{V=await y.cloudflare.zoneIdFor(M)}catch(Ae){y.warnings.push(`R2: could not resolve the zone for ${M}, cache rule skipped: ${td(Ae)}`);continue}P.set(V,[...P.get(V)??[],M])}for(let M of P.values()){let V={action:"set_cache_settings",description:`${Wt} ${Jg}`,expression:`(${Kt(M)})`,enabled:!0,action_parameters:v};await so(y,`cache rule for ${M.join(", ")}`,async()=>{let Ae=await y.cloudflare.getPhaseRules(M[0],"http_request_cache_settings");if(cp(Ae,V))return;if(!y.dryRun){let ye=await y.cloudflare.putManagedPhaseRules(M[0],"http_request_cache_settings",[V]);if(!ye.success)throw Error(ye.message||"cache rule write failed")}R(`cache rule updated for ${M.join(", ")}`,`update cache rule for ${M.join(", ")}`)})}}function ap(u){if(u.edgeTtl===void 0&&u.browserTtl===void 0)return null;let g={cache:!0};if(u.edgeTtl!==void 0)g.edge_ttl={mode:"override_origin",default:u.edgeTtl};if(u.browserTtl!==void 0)g.browser_ttl={mode:"override_origin",default:u.browserTtl};return g}function cp(u,g){let h=Jt(g.expression),y=Jn(g.expression),R=(M)=>(M.description||"").startsWith(Wt),v=(M)=>M.action===g.action&&M.description===g.description&&(M.enabled??!0)===(g.enabled??!0)&&Jn(M.expression)===y&&Ms(M.action_parameters)===Ms(g.action_parameters),P=!1;for(let M of u){if(!R(M))continue;let V=Jt(M.expression);if(!h.some((ye)=>V.includes(ye)))continue;if(v(M)&&h.every((ye)=>V.includes(ye))&&!P){P=!0;continue}return!1}return P}function lp(u){let g={id:u.id,enabled:u.enabled??!0,conditions:{prefix:u.prefix??""}};if(u.expireAfterDays!==void 0)g.deleteObjectsTransition={condition:{type:"Age",maxAge:cu(u.expireAfterDays)}};else if(u.expireOn!==void 0)g.deleteObjectsTransition={condition:{type:"Date",date:u.expireOn}};if(u.abortMultipartUploadsAfterDays!==void 0)g.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:cu(u.abortMultipartUploadsAfterDays)}};if(u.infrequentAccessAfterDays!==void 0)g.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:cu(u.infrequentAccessAfterDays)}}];return g}function cu(u){return Math.round(u*86400)}function $h(u){let g=new Set,h=[];for(let y of u??[]){let R=typeof y==="string"?{domain:y}:y,v=R.domain?.trim().replace(/\.$/,"").toLowerCase();if(!v||g.has(v))continue;g.add(v),h.push({domain:v,minTLS:R.minTLS})}return h}function ed(u){if(!u.enabled)return"disabled";let g=u.status?.ownership,h=u.status?.ssl;if(g==="active"&&h==="active")return"active";for(let y of[g,h])if(y==="error"||y==="blocked"||y==="deactivated")return y;return"pending"}async function so(u,g,h,y){try{await h()}catch(R){if(R instanceof Sn)throw R;u.warnings.push(`R2: ${g} failed: ${td(R)}`),y?.()}}function td(u){return u instanceof Error?u.message:String(u)}function Ms(u){if(Array.isArray(u))return`[${u.map(Ms).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${Ms(y)}`).join(",")}}`;return JSON.stringify(u)}import{basename as Bh,extname as Vh}from"node:path";import{createHash as Dh}from"node:crypto";var kh="https://api.cloudflare.com/client/v4",Fn="TS_CLOUD_CONTENT_HASH",co="2025-09-01",nd="application/javascript+module",Nh=10007,xh=[1e4,9109];class di extends Error{status;errors;constructor(u,g,h=[]){super(u);this.name="WorkersApiError",this.status=g,this.errors=h}hasCode(u){return this.errors.some((g)=>g.code===u)}}class Vs extends di{permission;constructor(u,g,h,y=[]){super(`The Cloudflare API token is missing the "${u}" permission (${g}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,h,y);this.name="WorkersPermissionError",this.permission=u}}class Gs{name="cloudflare-workers";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare Workers needs an API token");if(!u.accountId)throw Error("Cloudflare Workers needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((g,h)=>fetch(g,h))}async request(u,g,h){let y={Authorization:`Bearer ${this.apiToken}`},R;if(h instanceof FormData)R=h;else if(h!==void 0)y["Content-Type"]="application/json",R=JSON.stringify(h);let v=await this.fetchImpl(`${kh}/accounts/${this.accountId}/workers${g}`,{method:u,headers:y,body:R}),P=await v.text(),M;try{M=JSON.parse(P)}catch{throw new di(`Cloudflare Workers API returned ${v.status} with a non-JSON body: ${P.slice(0,200)}`,v.status)}if(!M.success){let V=M.errors??[],Ae=V.map((ye)=>`${ye.code}: ${ye.message}`).join(", ");if(Fh(v.status,V))throw new Vs(Mh(g),`${u} ${g} -> ${v.status}${Ae?`, ${Ae}`:""}`,v.status,V);throw new di(`Cloudflare Workers API error (${v.status}) on ${u} ${g}: ${Ae||P.slice(0,200)}`,v.status,V)}return M.result}scriptPath(u){return`/scripts/${encodeURIComponent(u)}`}async getSettings(u){try{return await this.request("GET",`${this.scriptPath(u)}/settings`)}catch(g){if(g instanceof Vs)throw g;if(g instanceof di&&(g.hasCode(Nh)||g.status===404))return null;throw g}}async getScript(u){return this.getSettings(u)}async uploadModuleScript(u,g){return this.request("PUT",this.scriptPath(u),dp(g))}async ensureModuleScript(u,g){let h=lo(g),y=await this.getSettings(u);if(y&&qs(y,g,h))return{action:"unchanged",hash:h};return await this.uploadModuleScript(u,pp(g,h)),{action:y?"updated":"created",hash:h}}async listCustomDomains(u={}){let g=new URLSearchParams;if(u.service)g.set("service",u.service);if(u.hostname)g.set("hostname",u.hostname);if(u.zoneId)g.set("zone_id",u.zoneId);let h=g.toString(),y=h?`?${h}`:"";return await this.request("GET",`/domains${y}`)??[]}async attachCustomDomain(u,g){let h={hostname:u,service:g.service,environment:g.environment??"production"};if(g.zoneId)h.zone_id=g.zoneId;return this.request("PUT","/domains",h)}async detachCustomDomain(u){await this.request("DELETE",`/domains/${encodeURIComponent(u)}`)}async ensureCustomDomain(u,g,h){let R=(h??await this.listCustomDomains({hostname:u})).find((P)=>P.hostname.toLowerCase()===u.toLowerCase());if(R&&R.service===g.service)return{action:"unchanged",domain:R};if(R)throw Error(`${u} is attached to the Worker '${R.service}'. Detach it there first (Workers & Pages, ${R.service}, Settings, Domains & Routes); ts-cloud does not move it.`);let v=await this.attachCustomDomain(u,g);return{action:"attached",domain:{...v,hostname:v?.hostname||u}}}}function Fh(u,g){if(g.some((h)=>xh.includes(h.code)))return!0;return(u===401||u===403)&&g.length===0}function Mh(u){if(u.startsWith("/domains"))return"Workers Routes: Edit (zone, for Workers custom domains) and Workers Scripts: Edit (account)";return"Workers Scripts: Edit (account)"}function dp(u){if(!u.modules.some((y)=>y.name===u.mainModule))throw Error(`Worker main module '${u.mainModule}' is not one of the uploaded modules`);let g={main_module:u.mainModule,bindings:u.bindings??[],compatibility_date:u.compatibilityDate??co,compatibility_flags:u.compatibilityFlags??[],keep_bindings:["secret_text"]},h=new FormData;h.append("metadata",JSON.stringify(g));for(let y of u.modules)h.append(y.name,new Blob([y.content],{type:y.type}),y.name);return h}function lo(u){let g={mainModule:u.mainModule,modules:[...u.modules].sort((h,y)=>h.name.localeCompare(y.name)).map((h)=>({name:h.name,type:h.type,sha256:up(h.content)})),bindings:[...u.bindings??[]].filter((h)=>h.name!==Fn).sort((h,y)=>h.name.localeCompare(y.name)),compatibilityDate:u.compatibilityDate??co,compatibilityFlags:[...u.compatibilityFlags??[]].sort()};return up(rd(g))}function pp(u,g=lo(u)){return{...u,bindings:[...(u.bindings??[]).filter((h)=>h.name!==Fn),{type:"plain_text",name:Fn,text:g}]}}function qs(u,g,h){let y=u.bindings??[],R=y.find((v)=>v.name===Fn&&v.type==="plain_text");if(!R||R.text!==h)return!1;return(g.bindings??[]).every((v)=>{let P=y.find((V)=>V.name===v.name);if(!P||P.type!==v.type)return!1;let M=v.type==="r2_bucket"?"bucket_name":v.type==="plain_text"?"text":void 0;return!M||P[M]===v[M]})}function up(u){return Dh("sha256").update(u).digest("hex")}function rd(u){if(Array.isArray(u))return`[${u.map(rd).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[y])=>h.localeCompare(y)).map(([h,y])=>`${JSON.stringify(h)}:${rd(y)}`).join(",")}}`;return JSON.stringify(u)}async function id(u){if(!await Bun.file(u).exists())throw Error(`Worker entry not found: ${u}`);let g;try{g=await Bun.build({entrypoints:[u],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(R){throw Error(`Bundling Worker ${u} failed: ${zh(R)}`)}if(!g.success)throw Error(`Bundling Worker ${u} failed: ${g.logs.map((R)=>String(R.message??R)).join("; ")}`);if(g.outputs.length!==1)throw Error(`Bundling Worker ${u} produced ${g.outputs.length} files (${g.outputs.map((R)=>R.path).join(", ")}); a Worker is uploaded as a single module, so remove the dynamic imports or asset imports that split it.`);let h=g.outputs[0];if(h.kind!=="entry-point")throw Error(`Bundling Worker ${u} produced a ${h.kind} instead of an entry module`);let y=await h.text();return{name:`${Bh(u,Vh(u))}.js`,content:y,type:nd,size:new TextEncoder().encode(y).byteLength}}function zh(u){if(u instanceof AggregateError&&u.errors.length>0)return u.errors.map((g)=>g instanceof Error?g.message:String(g?.message??g)).join("; ");return u instanceof Error?u.message:String(u)}import{isAbsolute as Hh,resolve as Uh}from"node:path";var Gh="https://api.cloudflare.com/client/v4",jh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function Kh(u,g={}){let h=g.log??(()=>{}),y={workers:[],warnings:[]},R=Object.entries(u.infrastructure?.workers??u.workers??{});if(R.length===0)return h("Workers: none declared, skipping."),y;if(!g.apiToken||!g.accountId){let M=[!g.apiToken&&"CLOUDFLARE_API_TOKEN",!g.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),V=`Workers: ${R.length} Worker(s) declared but ${M} is not set, skipping.`;return h(V),y.warnings.push(V),y}let v=u.infrastructure?.r2??u.r2,P={workers:new Gs({apiToken:g.apiToken,accountId:g.accountId,fetch:g.fetch}),r2:new ui({apiToken:g.apiToken,accountId:g.accountId,fetch:g.fetch}),cloudflare:new G(g.apiToken,{zoneId:g.zoneId,accountId:g.accountId}),apiToken:g.apiToken,fetch:g.fetch??((M,V)=>fetch(M,V)),projectRoot:g.projectRoot??process.cwd(),dryRun:g.dryRun===!0,warnings:y.warnings,log:h,r2ConfigDomains:Qh(v),r2Buckets:v,claimed:new Map};for(let[M,V]of R){let Ae=V?.name;if(!Ae||!jh.test(Ae)){y.warnings.push(`Workers: '${M}' has an invalid name '${Ae??""}' (1-63 chars: lowercase letters, digits, '-' and '_'), skipping.`);continue}if(!V.entry){y.warnings.push(`Workers: ${Ae} has no entry, skipping.`);continue}h(`Workers: ${P.dryRun?"checking":"reconciling"} ${Ae}...`);let ye={name:Ae,changes:[],domains:[]};y.workers.push(ye),await qh(V,ye,P);for(let At of ye.changes)h(`Workers: ${Ae}: ${At}`)}return y}async function qh(u,g,h){let y=u.name,R=Hh(u.entry)?u.entry:Uh(h.projectRoot,u.entry),v;try{v=await id(R)}catch(M){throw Error(`Worker ${y}: ${gi(M)}`)}g.changes.push(`bundled ${zS(v.size)}`);let P={mainModule:v.name,modules:[{name:v.name,content:v.content,type:v.type}],bindings:mp(u,h),compatibilityDate:u.compatibilityDate??co,compatibilityFlags:u.compatibilityFlags??[]};if(h.dryRun){let M=await h.workers.getSettings(y);g.changes.push(M&&qs(M,P,lo(P))?"unchanged":"would upload")}else{let{action:M}=await h.workers.ensureModuleScript(y,P);g.changes.push(M==="unchanged"?"unchanged":"uploaded")}for(let M of $S(u.customDomains))await Zh(y,M,g,h)}async function Zh(u,g,h,y){let R=(Je)=>{h.domains.push({domain:g,status:Je})},v=(Je)=>{y.warnings.push(`Workers: ${Je}`),R("conflict")},P=y.claimed.get(g);if(P&&P!==u){v(`${g} is declared on both ${P} and ${u}; leaving it on ${P}.`);return}y.claimed.set(g,u);let M=y.r2ConfigDomains.get(g);if(M){v(`${g} is also declared as a custom domain of the R2 bucket '${M}' (r2.buckets). A hostname serves either a bucket or a Worker. Remove it from the bucket's customDomains and detach it in the dashboard (R2, ${M}, Settings, Custom Domains) first; to serve the bucket through the Worker, bind it with bindings.r2Buckets instead.`);return}let V=await Jh(y);if(V===null){R("error");return}let Ae=V.find((Je)=>Je.hostname.toLowerCase()===g);if(Ae?.service===u){R("active");return}if(Ae){v(`${g} is attached to the Worker '${Ae.service}'. Detach it there first (Workers & Pages, ${Ae.service}, Settings, Domains & Routes); it is not moved automatically.`);return}let ye=(await Yh(y))?.get(g);if(ye){v(`${g} is attached to the R2 bucket '${ye}' as a custom domain. Detach it first (R2, ${ye}, Settings, Custom Domains, then re-run the deploy); it is not detached automatically. To serve the bucket through the Worker, bind it with bindings.r2Buckets.`);return}let At;try{At=await y.cloudflare.zoneIdFor(g)}catch(Je){y.warnings.push(`Workers: could not resolve the zone for ${g}, not attached: ${gi(Je)}`),R("error");return}let Tt=await Xh(y,At,g);if(Tt.length>0){let Je=Tt.map((Ue)=>`${Ue.type} ${Ue.content}`).join(", ");v(`${g} already has a DNS record (${Je}). A Worker custom domain creates its own record, so Cloudflare will not attach over it. Delete the record first (DNS, Records), then re-run the deploy; it is not deleted automatically.`);return}if(y.dryRun){h.changes.push(`would attach custom domain ${g}`),R("not attached");return}try{await y.workers.ensureCustomDomain(g,{service:u,zoneId:At},V),h.changes.push(`custom domain ${g} attached`),V.push({id:"",hostname:g,service:u,zone_id:At}),R("pending")}catch(Je){y.warnings.push(`Workers: custom domain ${g} on ${u} failed: ${gi(Je)}`),R("error")}}async function Jh(u){if(u.attached!==void 0)return u.attached;try{u.attached=await u.workers.listCustomDomains()}catch(g){u.warnings.push(`Workers: could not list Worker custom domains, none attached: ${gi(g)}`),u.attached=null}return u.attached}async function Yh(u){if(u.r2AccountDomains!==void 0)return u.r2AccountDomains;let g=new Map;try{let h=(await u.r2.listBuckets()).map((y)=>({name:y.name}));for(let y of Object.values(u.r2Buckets?.buckets??{}))if(y.jurisdiction&&y.jurisdiction!=="default")h.push({name:y.name,jurisdiction:y.jurisdiction});for(let y of h){let R=await u.r2.listCustomDomains(y.name,{jurisdiction:y.jurisdiction}).catch(()=>[]);for(let v of R)g.set(v.domain.toLowerCase(),y.name)}u.r2AccountDomains=g}catch(h){u.log(`Workers: could not check R2 custom domains (${gi(h)}); relying on the DNS check.`),u.r2AccountDomains=null}return u.r2AccountDomains}async function Xh(u,g,h){try{let y=await u.fetch(`${Gh}/zones/${g}/dns_records?name=${encodeURIComponent(h)}&per_page=100`,{method:"GET",headers:{Authorization:`Bearer ${u.apiToken}`}}),R=await y.json();if(!R?.success)throw Error(`HTTP ${y.status}`);return(R.result??[]).filter((v)=>v.name?.toLowerCase()===h).map((v)=>({type:v.type??"?",content:v.content??""}))}catch(y){return u.log(`Workers: could not read DNS records for ${h} (${gi(y)}); attaching anyway.`),[]}}function mp(u,g){let h=[],y=new Set,R=(P)=>{if(P===Fn)return g.warnings.push(`Workers: ${u.name}: binding name ${Fn} is reserved for ts-cloud, ignored.`),!1;if(y.has(P))return g.warnings.push(`Workers: ${u.name}: binding ${P} is declared twice; the first one wins.`),!1;return y.add(P),!0},v=new Map;for(let P of Object.values(g.r2Buckets?.buckets??{}))if(P.jurisdiction&&P.jurisdiction!=="default")v.set(P.name,P.jurisdiction);for(let[P,M]of Object.entries(u.bindings?.r2Buckets??{})){if(!R(P))continue;let V=v.get(M);h.push(V?{type:"r2_bucket",name:P,bucket_name:M,jurisdiction:V}:{type:"r2_bucket",name:P,bucket_name:M})}for(let[P,M]of Object.entries(u.bindings?.vars??{}))if(R(P))h.push({type:"plain_text",name:P,text:String(M)});return h}function Qh(u){let g=new Map;for(let h of Object.values(u?.buckets??{}))for(let y of h?.customDomains??[]){let R=gp(typeof y==="string"?y:y.domain);if(R)g.set(R,h.name)}return g}function $S(u){return[...new Set((u??[]).map(gp).filter(Boolean))]}function gp(u){return(u??"").trim().replace(/\.$/,"").toLowerCase()}function zS(u){if(u<1024)return`${u} B`;if(u<1048576)return`${(u/1024).toFixed(1)} KB`;return`${(u/1024/1024).toFixed(1)} MB`}function gi(u){return u instanceof Error?u.message:String(u)}export{Ml as ABTestManager,be as ACMClient,Or as ACMDnsValidator,bd as ACME_DIRECTORIES,Le as AI,bu as API_IDEMPOTENCY_TTL_MS,Su as API_TOKEN_DEFAULT_TTL_MS,Iu as API_TOKEN_MAX_TTL_MS,Is as API_VERSION,Ee as AUTHORIZATION_CAPABILITIES,fu as AUTH_ACTION_TOKEN_TTL_MS,hu as AUTH_MFA_CHALLENGE_TTL_MS,Au as AUTH_OIDC_TRANSACTION_TTL_MS,at as AUTH_SESSION_ABSOLUTE_TTL_MS,mu as AUTH_SESSION_IDLE_TTL_MS,Ly as AWSAPIError,n as AWSClient,A as AWSCloudFormationClient,I as AWSCloudFrontClient,Ol as AWSConfigManager,db as AWS_PSEUDO_PARAMETERS,$e as AWS_REGIONS,Cg as AcmeClient,on as AlertEvaluator,qi as AlertStore,Mo as AnomalyConfigStore,El as ApiGateway,i as ApiServiceError,Oc as ApplicationAutoScalingClient,pn as Arn,L as AssetHasher,Z as Auth,fs as AuthenticationStore,Ji as AutomationApiService,hs as AutomationIdentityStore,Ha as AwsAuroraDataAdapter,za as AwsAuroraTransport,uc as AwsDatabaseBackupSource,Mr as AwsDriver,Ga as AwsElastiCacheDataAdapter,Ka as AwsElastiCacheTransport,lh as AwsIamCapabilityScanner,hc as AwsInfrastructureBackupSource,Qa as AwsRdsDataAdapter,ja as AwsRdsTransport,Eh as AwsRegionalDriver,yc as AwsSecretsManagerConfigurationBackend,Tm as AwsSpendTransport,Sc as AwsSsmConfigurationBackend,Ns as BackupCoordinator,Bl as BackupManager,dc as BackupStore,Ff as BatchProcessingManager,qn as BedrockClient,Vn as BedrockRuntimeClient,Du as BitbucketSourceAdapter,$l as BlueGreenManager,Pf as BounceComplaintHandler,If as BuildOptimizationManager,Ju as BunDockerRuntime,wg as BunDockerVolumeRuntime,Tg as BunFilesystemArchiveRuntime,ve as CDN,oa as CHAIN_HEADER,Wt as CLOUDFLARE_MANAGED_RULE_PREFIX,yl as CLOUDFRONT_FAILOVER_STATUS_CODES,JC as COMMON_CROSS_ACCOUNT_ROLES,Fn as CONTENT_HASH_BINDING,Ye as CONTROL_PLANE_SCHEMA_VERSION,jm as CREDENTIAL_PROCESS_TIMEOUT_MS,Xo as Cache,as as CanaryManager,Af as CertificateManager,qA as CloudBlockVolumeDriver,go as CloudDriverFactory,st as CloudError,Hm as CloudFormationBuilder,A as CloudFormationClient,I as CloudFrontClient,_l as CloudTrailManager,Pe as CloudWatchLogsClient,ep as CloudflarePagesProvider,G as CloudflareProvider,nS as CommandHistory,te as Communication,en as ComposeApplicationService,ar as ComposeApplicationStore,Vt as ComprehendClient,a as Compute,wm as ComputeSpendTransport,na as ConfigurationError,bc as ConfigurationService,Ac as ConfigurationStore,Hn as ConnectClient,qa as ContainerDataAdapter,Gl as ContainerRegistryManager,fc as ControlPlaneBackupSource,sc as ControlPlaneCleanupDriver,Mi as ControlPlaneStore,_o as CounterTracker,_t as CredentialError,k as CredentialProcessError,sf as CrossRegionReferenceManager,Iy as DASHBOARD_ENTRY,by as DASHBOARD_PORT_BASE,Cy as DASHBOARD_PORT_SPAN,Sy as DASHBOARD_STATE_DIR,fa as DEFAULT_ATTACK_MODE_HOURS,co as DEFAULT_COMPATIBILITY_DATE,al as DEFAULT_DDOS_THRESHOLDS,km as DEFAULT_FAILOVER_STATUS_CODES,Hd as DEFAULT_METER_MAPPINGS,Ud as DEFAULT_PRICE_BOOK,An as DEFAULT_RECURSION_LIMITS,yo as DEFAULT_RPX_CERTS_DIR,re as DEFAULT_SERVICE_LIMITS,ul as DEFAULT_STATE_DIR,Fg as DEFAULT_STATIC_ASSET_EXTENSIONS,fy as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,iy as DEFAULT_TELEMETRY_POLICY,dm as DEFAULT_THRESHOLDS,UA as DEPLOYMENT_QUEUE_KINDS,sa as DEPTH_HEADER,nn as DETECTABLE_SIGNALS,qu as DIAGNOSTIC_PRESETS,Mf as DLQMonitoringManager,J as DNS,Rf as DNSSECManager,vs as DataServiceLifecycle,Ua as DataServiceStore,gr as Database,ff as DatabaseUserManager,j as DebugLogger,my as DependencyGraph,ee as Deployment,_y as DeploymentError,xl as DisasterRecoveryManager,Zn as DnsProviderFactory,br as DockerDataTransport,Oa as DockerDiscoveryAdapter,Zr as DockerNamedVolumeDriver,mc as DockerVolumeBackupSource,c as DurableOperationQueue,Do as DurableQueueWorker,He as DynamoDBClient,jr as EC2Client,Ve as ECRClient,gt as ECSClient,kr as EFSClient,kc as ELBv2Client,zA as ENFORCEMENT_ACTIONS,Gi as ENFORCEMENT_DESCRIPTIONS,_ as ENFORCEMENT_SEVERITY,$p as ENVIRONMENT_LABEL,Gu as EcsRuntimeAdapter,ma as EdgeRateLimiter,mt as ElastiCacheClient,f as Email,xf as EmailAdvanced,kf as EmailAnalyticsManager,Wn as EmailClient,Of as EmailHandlers,Bf as EmailTemplateManager,Wa as EncryptedDataSecretStore,$y as ErrorCodes,Dr as EventBridgeClient,Ih as EventBridgeJobAdapter,Ic as ExternalConfigurationBackend,Jo as FAILOVER_REPLICA_POLICY_SID,$f as FIFOQueueManager,eR as FLY_MACHINES_API,Am as FOCUS_VERSION,wl as FileCache,nt as FileSystem,gc as FilesystemBackupSource,Xa as FleetService,Ja as FleetStore,So as FlyApiError,Cp as FlyClient,e as Fn,Pu as GiteaSourceAdapter,wu as GithubSourceAdapter,Ru as GitlabSourceAdapter,of as GlobalResourceManager,qe as GoDaddyProvider,Ll as GuardDutyManager,wt as HOST_SITES_DIR,Qy as HashCache,Xf as HealthCheckManager,et as HealthCheckRunner,Gr as HetznerClient,Ne as HetznerDriver,ke as IAMClient,Vc as IPV6_EXCLUDED_HOST_LABELS,Sf as ImageScanningManager,Ip as InfrastructureGenerator,Pd as InvalidOperationTransitionError,xt as JobLoader,bh as JobProviderReconciler,Ma as JobService,Fa as JobStore,Rr as KendraClient,Wf as LARAVEL_SERVERLESS_BUILD_STEPS,T as LambdaClient,Ef as LambdaConcurrencyManager,wf as LambdaDLQManager,vf as LambdaDestinationsManager,bf as LambdaLayersManager,Vu as LambdaRuntimeAdapter,Tf as LambdaVPCManager,Cf as LambdaVersionsManager,Ln as LocalEncryptedConfigurationBackend,pc as LogicalDatabaseBackupSource,Ul as LogsManager,vS as MANAGED_NODE_VERSIONS,pd as MANAGEMENT_DASHBOARD_SITE,Gm as MANAGEMENT_DASHBOARD_SITE_PREFIX,ps as MAX_CONTROL_HOURS,kd as MAX_CONTROL_PLANE_ERROR_BYTES,im as MAX_CONTROL_PLANE_JSON_BYTES,Bo as METERS,jA as METER_KEYS,KA as MICRO_CENTS,lm as MIN_PROJECTION_CONFIDENCE,Vg as MTA_STS_PORT,ic as MaintenanceService,nc as MaintenanceStore,pe as Messaging,gf as MetricsManager,pf as MigrationManager,Zm as MockCloudFormation,tf as MockDynamoDB,ef as MockS3,Yo as Monitoring,df as MultiAccountManager,nf as MultiRegionManager,Xy as MultiStepProgress,S as Network,Yf as NetworkSecurityManager,ji as NotificationRouter,xm as ORIGIN_CONNECTION_ATTEMPTS,Om as ORIGIN_CONNECTION_TIMEOUT,Nm as ORIGIN_GROUP_ALLOWED_METHODS,ob as ORIGIN_GROUP_ID_SUFFIX,Bm as ORIGIN_GROUP_SELECTION_CRITERIA,Nc as OpenSearchClient,Rt as OptimisticConcurrencyError,lf as OrganizationManager,Lg as PAGES_MAX_FILE_BYTES,OS as PHP_DEFAULT_EXCLUDES,TS as PHP_LAYER_EXTENSIONS,Lp as PROJECT_LABEL,ht as PROXIABLE_RECORD_TYPES,D as ParameterStore,mf as PerformanceManager,ge as Permissions,Bc as PersonalizeClient,it as Phone,_f as PhoneAdvanced,Um as PhoneHandlers,Za as PlacementService,Ya as PlacementStore,jn as PollyClient,Se as PorkbunProvider,Tn as PreDeployScanner,kl as PreviewEnvironmentManager,Yr as PreviewEnvironmentService,Ze as PreviewEnvironmentStore,Nl as PreviewNotificationService,Jy as ProgressBar,Fl as ProgressiveDeploymentManager,ha as ProtectionControlStore,py as Pseudo,X as Queue,Fi as QueueCancellationError,Uf as QueueManagementManager,WI as QueuePresets,Ro as QueueTimeoutError,_n as R2ApiError,Sn as R2NotEnabledError,ui as R2Provider,op as R2_NOT_ENABLED_ERROR_CODE,su as RATE_LIMIT_KEY_SEPARATOR,ie as RDSClient,sS as RECOMMENDED_ACCOUNT_STRUCTURES,WC as RECOMMENDED_SCPS,oh as RELEASE_QUEUE_KINDS,eS as REPL,rS as REPLCommandBuilder,tS as REPLContext,Mp as ROLE_LABEL,Hy as RateLimiter,JI as RealtimePresets,ym as RecordingSpendTransport,ds as RecursionGuard,Ot as Redirects,af as RegionPairManager,tc as RegionService,ec as RegionStore,rt as Registry,qt as RekognitionClient,Lt as ReleaseService,Ta as ReleaseStore,Ch as RemoteBuildService,Ql as ReplicaManager,Zf as ResourceManagementManager,de as RetryableOperationError,C as Route53Client,Pc as Route53DomainsClient,se as Route53Provider,Df as Route53ResolverManager,ql as Route53RoutingManager,Re as RuntimeOperationService,La as RuntimeStreamRegistry,lc as S3BackupDestinationAdapter,o as S3Client,q as S3Error,Bu as SECRET_PATTERNS,fm as SENSITIVITY_THRESHOLDS,ft as SESClient,Y as SMS,pt as SNSClient,vm as SPEND_CYCLE_SECONDS,tl as SPEND_GATE_SETTING,cy as SPEND_LEASE_SETTING,he as SQSClient,Be as SSH_BOOTSTRAP_VERSION,yi as SSH_PREFLIGHT_SCRIPT,Oe as SSMClient,Dm as STATE_DIR_ENV_VAR,Ei as STATIC_SITE_ZONE_SETTINGS,Il as STORAGE_FAILOVER_METADATA_KEY,De as STSClient,zn as SchedulerClient,pr as Search,wn as SecretFindingScanner,es as Secrets,Hl as SecretsManager,ne as SecretsManagerClient,hf as SecretsRotationManager,E as Security,hr as SecurityHubManager,vn as SecurityPostureStore,$t as SecurityScannerRunner,yf as SecurityScanningManager,Nf as SenderReputationManager,Sh as ServerCronJobAdapter,Va as ServerDataAdapter,No as ServerPathVolumeDriver,Vl as ServiceMeshManager,Cl as Sftp,Uo as SignalSource,Lf as SmsAdvanced,zt as SmsClient,Qm as SmsHandlers,$c as SmsVoiceClient,wa as SourceConnectionStore,Sr as SourceProviderError,rl as SpendCapError,sn as SpendGate,Cm as SpendLoopLease,qo as SpendNotificationRouter,Em as SpendRunner,dr as SpendService,Qi as SpendStore,Yy as Spinner,Vr as SshDriver,Pn as SshFleetDriver,cf as StackDependencyManager,cb as StacksIntegration,Jf as StaticSiteManager,_e as Storage,ru as StorageAdvancedManager,Kn as SupportClient,Ar as SyntheticsManager,Xu as SystemFleetSshTransport,Ct as SystemSshTransport,_a as SystemdDiscoveryAdapter,aa as TRACE_HEADER,Zy as TaskList,kt as TelemetryStore,hl as TemplateBuilder,Rl as TemplateCache,jt as TextractClient,Gn as TranscribeClient,wr as TranslateClient,wh as TransportDisasterRecoveryDriver,Th as TransportPlatformMaintenanceDriver,Ts as TransportRemoteBuildDriver,Ba as TrivyImageScanner,va as TsCloudApiError,Cu as TsCloudClient,ay as URGENT_SPEND_EVENTS,um as USER_VISIBLE_ACTIONS,rc as UnavailableRegionalDriver,Ie as UnifiedDnsValidator,vo as UnsupportedSchemaVersionError,Km as ValidationError,Pr as VoiceClient,ko as VolumeService,or as VolumeStore,nd as WORKER_MODULE_TYPE,di as WorkersApiError,Vs as WorkersPermissionError,Gs as WorkersProvider,yy as Workflow,uf as XRayManager,mS as abTestManager,Eu as activateImmutableRelease,dg as addDns01ChallengeRecord,Nn as addSiteToCloudConfig,Ft as ageSeconds,Vd as aggregateDeltas,tm as allocateSitePorts,Fm as amazonLinuxImageId,Ay as amazonLinuxImageParameter,ib as analyzeStackDiff,Vi as anomalyOptionsForSignal,Aa as applyControlsToDdos,lu as applyControlsToRateLimits,Js as applyDeclaredZoneSettings,mi as applyHetznerVolumes,dn as applyMitigationFactor,bA as applyPlan,eo as applyZoneMigration,jl as artifactKey,uu as assertComputeResidency,Nt as assertOriginGroupMethods,As as assertReleaseStrategy,ny as assertSpendAllows,wA as attachConflicts,RA as attachIsViable,TA as attachPreconditions,$u as attachProvenanceToRelease,xa as attachSbomToRelease,_u as attachVulnerabilitySummary,ih as authEncryptionKeyFile,O as authorizeOrganization,Ah as authorizeRuntimePath,TC as autocomplete,cS as awsConfigManager,Eg as backupCredentialStatus,oS as backupManager,Jb as batch,UE as batchProcessingManager,Ca as beginOidcAuthorization,gS as blueGreenManager,OE as bounceComplaintHandler,Dt as budgetWindow,wc as buildAndPushServerlessImage,GE as buildBunRuntimeLayerZip,xA as buildCertificatePackScript,kA as buildCertificateStateScript,OA as buildCertificateUnpackScript,vl as buildCloudFormationTemplate,ad as buildCloudInitFirstBoot,Od as buildComposeLogsCommand,zI as buildComposeRuntimeCommand,KI as buildComposeScaleCommand,_d as buildComposeShellCommand,ni as buildComputeStorageInstallScript,Fr as buildComputeStorageSiteScript,Yp as buildDrainSourceScript,gA as buildDrainedSiteScanScript,bl as buildFailoverReplicaPolicyStatement,Er as buildFunctionEnv,Xp as buildHealthGateScript,si as buildHostCleanupDeployScript,ao as buildHostCleanupInstallScript,ii as buildHostCleanupScript,Li as buildHostSitePortsScript,Yi as buildMailEnv,fo as buildManagementDashboardArtifact,fR as buildMediaCdnPlan,Gg as buildMtaStsPolicy,Wh as buildMtaStsServer,HE as buildNodeRuntimeLayerZip,TE as buildOptimizationManager,Sl as buildOriginGroup,gn as buildOriginGroups,Uc as buildOriginGuardRule,Vp as buildPauseWorkersScript,zE as buildPhpRuntimeLayerZip,Mm as buildReplicationConfiguration,$m as buildReplicationRole,Kp as buildRestoreScript,x as buildRpxConfig,xe as buildRpxFragmentRefreshScript,EA as buildSetHostnameScript,ai as buildSiteDeployScript,zp as buildSnapshotScript,Zp as buildSourceStateScript,li as buildSshArgs,hi as buildSshBootstrapScript,Fc as buildStaticSiteCacheRules,ci as buildStaticSiteDeployScript,Wp as buildTargetStateScript,dp as buildUploadForm,qp as buildWorkersStateScript,id as bundleWorker,Fu as bytes,ap as cacheRuleParameters,pS as canaryManager,kn as canonicalJson,Mt as capabilities,Cr as capacity,sC as categorizeChanges,CE as certificateManager,BA as certificatesMatch,Ub as checkIAMPermissions,qf as checkInvocation,Hb as checkServiceQuotas,Gy as chunk,OR as cleanupDns01Challenge,_b as clearCredentialProcessCache,GS as clearSigningKeyCache,Da as cloneSourceBinding,Vy as cloudConfigSchema,hp as cloudDrivers,dS as cloudTrailManager,rp as collectAssets,ua as collectPhpAppEntries,Ug as collectServerDnsDomains,sm as completeComposeVolumeDeletion,Ea as completeOidcAuthorization,Rb as composePresets,wo as composeProjectName,Kl as composeServerlessAppTemplate,ly as compositeSpendTransport,Gt as compressBackup,KS as config,Mc as configOrigins,Ku as connectionGuidance,IS as containerRegistryManager,MA as controlPlaneDatabaseFile,Rd as controlPlaneMigrations,fb as createApiBackendPreset,Na as createApiV1Handler,nI as createAsgBuildDriver,vg as createBackupQueueHandlers,xS as createCliHandler,U as createCloudDriver,gd as createCloudFrontPolicy,Lb as createCredentialProvider,Tb as createDashboardSite,Ib as createDataPipelinePreset,Wu as createDataServiceQueueHandlers,Ld as createDeploymentQueueHandlers,B as createDnsProvider,rI as createEcsBuildDriver,nl as createEnforcementHandlers,Wm as createError,Tl as createExistingStaticFullStackPreset,Yu as createFleetQueueHandlers,mb as createFullStackAppPreset,no as createGoDaddyValidator,jE as createHandlers,NS as createHttpHandler,Ab as createJamstackPreset,zu as createJobQueueHandlers,Eb as createLaravelPreset,bb as createMLApiPreset,sg as createMaintenanceQueueHandlers,pR as createMediaAccessToken,yb as createMicroservicesPreset,pC as createMockAWS,ub as createNodeJsServerPreset,gb as createNodeJsServerlessPreset,Hs as createObjectStorageClient,ro as createPorkbunValidator,Db as createPreset,ga as createPresignedUrl,MS as createPresignedUrlAsync,BS as createQueueHandler,Sb as createRealtimeAppPreset,eg as createRegionQueueHandlers,Lu as createReleaseProvenance,Tu as createReleaseQueueHandlers,eI as createRemoteBuildQueueHandlers,io as createRoute53Validator,hh as createRuntimeAdapters,Oy as createS3Client,tI as createServerBuildDriver,vb as createServerlessLaravelPreset,pb as createServerlessNodePreset,Mg as createSmsInfrastructure,dt as createSourceAdapter,lb as createStaticSitePreset,Cb as createTraditionalWebAppPreset,$d as createVolumeQueueHandlers,hb as createWordPressPreset,ot as createZip,xC as crossRegionReferenceManager,$n as dashboardActions,mo as dashboardCredentialsFile,Dn as dataServiceCapabilities,IE as databaseUserManager,pu as decodeBase32,Qe as decompressBackup,Lh as decryptBackup,ya as defaultConfig,Ym as defaultLocalConfig,au as defaultRateLimitRules,xr as delegateZone,Ks as delegateZoneFromConfig,Sg as deleteFailoverReplicaBuckets,vc as deleteStaticSite,fd as deployAllComputeSites,ac as deployServerlessApp,Ig as deploySite,ho as deploySiteRelease,_s as deployStaticSite,Tc as deployStaticSiteFull,Mn as deployStaticSiteWithExternalDns,Un as deployStaticSiteWithExternalDnsFull,iR as deployToFly,fl as deploymentCoexistenceError,Ey as deriveManagementDashboardPort,Ws as describeDelegation,du as describePosture,Xs as describeZoneSettings,yh as desiredJobProviderState,mm as detectAnomalies,Pm as detectDeploymentTargets,Qc as detectDnsProvider,Yd as detectLatestAnomaly,Mb as detectMisconfigurations,nu as detectServiceRegion,Bd as diffCompose,rC as diffTemplates,Ra as discoverGitRefs,ba as discoverOidcProvider,Uu as discoverRuntimeInventory,FE as dlqMonitoringManager,Hc as dnsProviders,BE as dnssecManager,ph as dockerWorkloads,ws as documentDigest,ed as domainStatus,aS as drManager,Ke as driverStatePath,Qu as ecsWorkloads,sr as effectiveCapabilities,_E as emailAnalyticsManager,$E as emailTemplateManager,ms as encodeBase32,_h as encryptBackup,Mu as ensureDefaultSecurityPolicies,hg as ensureFailoverReplicaBuckets,Ti as ensureFirewall,Pi as ensureManagementDashboard,wi as ensureServer,vi as ensureSshKey,ce as escapeSecLang,jd as evaluateBudget,Ii as evaluatePreflight,Vo as evaluateTelemetryAlertRules,ju as eventBridgeScheduleInput,kS as eventToRequest,ey as ewma,Nd as exportCompose,Ys as exportRoute53Zone,qm as extendPreset,ME as fifoQueueManager,Wb as findChangedFiles,am as findMapping,om as findPriceEntry,nR as flyDeployOptions,sd as flyIpType,Rp as flyMachineConfig,eE as formatAccountStructure,DA as formatAttachPlan,AC as formatBytes,an as formatCents,sb as formatDiff,mA as formatDrainedSiteRefusal,yC as formatDuration,RC as formatFlagSuggestions,kC as formatHistory,NC as formatHistoryStats,yA as formatInventory,IC as formatKeyValue,SC as formatList,IA as formatPlan,Ci as formatPreflightFindings,hC as formatProgressBar,iS as formatRegion,qC as formatRegionList,dh as formatScanResults,bC as formatSuggestion,mC as formatTable,rn as formatTimeToExhaustion,fC as formatTree,Py as fromCredentialProcess,ky as fromEC2Metadata,Ny as fromECSMetadata,Ry as fromEnvironment,Dy as fromSharedCredentials,By as fromWebIdentity,Xl as functionFingerprint,bo as gatewayHostnames,Jl as generateAppImageDockerfile,mE as generateApprovalConfig,Qf as generateBootstrap,zy as generateCleanupWorkflow,Ky as generateCostReportWorkflow,YC as generateCrossAccountRoleCF,xu as generateCycloneDxSbom,uE as generateDeploymentConfig,oE as generateDeploymentPipeline,tE as generateDeploymentWorkflow,Ec as generateExternalDnsStaticSiteTemplate,vR as generateHttpsServerCode,Ou as generateImageSbom,kR as generateLetsEncryptUserData,t as generateLogicalId,lE as generateManualPipeline,sE as generateMatrixWorkflow,gE as generateMultiEnvConfig,aE as generateMultiEnvPipeline,rE as generateMultiEnvWorkflow,nE as generatePRPreviewWorkflow,fE as generateParallelConfig,Kf as generatePhpFpmConfig,Hf as generatePhpLayerDockerfile,cE as generatePreviewPipeline,jy as generatePreviewWorkflow,r as generateResourceName,pE as generateScheduledConfig,dE as generateScheduledPipeline,iE as generateScheduledWorkflow,Os as generateStaticSiteTemplate,F as generateUbuntuAppCloudInit,zm as getAccountId,$C as getAllRegions,HC as getClosestRegion,DC as getCommandUsage,FA as getComposeTemplate,th as getConfig,EC as getContextualHelp,ss as getCredentials,oC as getDeploymentStrategy,aC as getDiffStats,nC as getDiffSummary,My as getErrorDetails,Pl as getLocalConfig,uC as getLocalCredentials,lC as getLocalEndpoint,gC as getLocalEnvVars,Gb as getQuotaUsageSummary,XC as getRecommendedStructure,os as getRegion,jC as getRegionStats,FC as getRegionsByCompliance,MC as getRegionsByLocation,UC as getRegionsByPricingTier,Fy as getRequiredPermissions,VS as getSigningKeyCacheSize,$g as getSmsInfrastructureStatus,XI as getTimestamp,pa as globMatches,Ao as globToRegex,OC as globalResourceManager,Hi as governingLimitCents,Ag as grantFailoverReplicaAccess,lS as guardDutyManager,jo as handleSpendRequest,Io as hasAutoWwwVariant,mr as hasManagementDashboardSite,wd as hasProxyUpstream,qb as hashBuffer,jb as hashDirectory,Jm as hashFile,zb as hashManifest,Xm as hashString,WE as healthCheckManager,ei as hostAcceptsIpv6,Kt as hostCondition,Sa as hotp,tn as hourBucket,ZA as hourBucketsBetween,vE as imageScanningManager,Ps as infraEnvFromOutputs,Zl as inspectInvocation,DS as installRecursionFetch,$s as invalidateCache,Vf as invocationContext,hy as isArmInstanceType,CC as isLikelyTypo,Lr as isLocalDatabase,dC as isLocalDevelopment,fr as isManagementDashboardSiteName,Nr as isNameserverRegistrar,qS as isNodeCryptoAvailable,Xd as isOperationAllowed,Go as isQuietHours,Wo as isS3RestEndpoint,Ni as isSafePattern,pl as isStateDirConfigured,ml as isStatePath,cn as isValidCidr,QC as isValidRegion,Ui as isValidTimeZone,jS as isWebCryptoAvailable,Br as isZoneHost,Rn as jobProviderCapability,Qs as keyMatchesFilters,DE as lambdaConcurrencyManager,NE as lambdaDLQManager,PE as lambdaDestinationsManager,wE as lambdaLayersManager,kE as lambdaVPCManager,RE as lambdaVersionsManager,Hu as lambdaWorkloads,eu as laravelServerlessEnvDefaults,Xr as listComposeTemplates,Ss as listSourceReferences,gu as loadCloudConfig,is as loadProfileCredentials,ta as loadProfileCredentialsSync,ns as loadStaticProfileCredentials,lr as loadTelemetryPolicy,hS as logsManager,Zd as lookbackHoursForSignal,gy as mailEnabled,tt as mailFirewallPorts,un as mailWebmailSites,vh as maintenanceWindowOpen,eh as makeAWSRequest,US as makeAWSRequestAsync,FS as makeAWSRequestOnce,cp as managedRuleInSync,Vm as managementDashboardSiteName,tg as manifestDigest,In as matchTotpCounter,gR as mediaObjectHeaders,$o as median,gm as medianAbsoluteDeviation,zd as mergeDecisions,mn as mergeInfrastructure,XA as mergePriceBooks,Gd as meterTelemetry,AE as metricsManager,Bg as migrateObjectStorage,yE as migrationManager,zC as multiAccountManager,BC as multiRegionManager,NR as needsRenewal,JE as networkSecurityManager,Ut as nextScheduleRuns,oe as normalizePublicIpv6,Me as normalizeRuntimeStatus,lt as normalizeScheduleExpression,ah as normalizeSourceEvent,ze as normalizeSshPublicKey,Sm as normalizeTelemetryPolicy,_i as occupiedHostPorts,ka as openApiDocument,Qo as optionsForSignal,KC as organizationManager,tu as packagePhpApp,hn as packageServerlessApp,tp as pagesAssetHash,Wg as pagesDnsRecord,Dl as parallel,Xb as parallelMap,Yb as parallelWithRetry,NA as parseCertificateState,Yl as parseChain,Jr as parseCompose,qI as parseComposeCatalog,gh as parseDockerInspect,Rg as parseDotenv,pA as parseDrainedSites,$i as parseHostSiteFragments,HS as parseJSONResponse,Si as parsePreflightFacts,em as parseSourceDrained,mh as parseSystemdRecords,Jp as parseTargetReady,Td as parseUpstreamPort,jp as parseWorkersPaused,QS as parseXMLResponse,Ki as pathTemplate,Ed as pendingSteps,Lo as percentOfLimit,SE as performanceManager,Wl as phpLayerBuildStage,wS as phpLayerPackages,yn as phpRuntimeLayerAssets,jI as planComposeTemplateUpgrade,Kd as planEnforcement,pi as planHetznerVolumes,Hp as planIsDestructive,Rm as planMitigation,CA as planServerRename,_A as planSiteMove,Zs as planZoneMigration,Xt as policyTag,bi as preflightFailed,qy as previewManager,Wy as previewNotifications,Qt as previewSchedule,YA as previousBudgetWindow,xo as priceUsage,WA as priceUsageLines,hA as probeHostRoutes,Xc as probeOriginTls,tC as processInChunks,ku as processSourceWebhook,Cs as productionChangeReview,ea as profileCredentialProcess,fS as progressiveDeploymentManager,qd as projectSpend,ca as propagationHeaders,Rc as providerEndpoint,rg as publicKeyFingerprint,Xn as qualifyName,QE as queueManagementManager,Kb as quickHash,sp as r2Endpoint,Zg as r2S3Credentials,ou as rateLimitHeaders,gs as rateLimitKey,We as readDriverState,fn as readSharedProfile,AA as reconcile,Hg as reconcileAddressRecords,Og as reconcileCloudflareCdn,Kh as reconcileCloudflareWorkers,zs as reconcileDeclaredRecords,ZS as reconcileJobObservation,Xg as reconcileR2Buckets,En as reconcileSourceWebhook,bs as recordDashboardHostPosture,JS as recordPreDeploySecretScan,XS as recordSkippedSecretScan,da as recursionBlockedResponse,Fe as redactRuntimeConfig,ol as redactTelemetryText,zi as redactTelemetryValue,xn as redeployServerlessApp,_C as regionPairManager,Cn as releaseStrategyCapabilities,sh as releaseTrafficPlan,ki as reloadRpxGateway,Us as remapKey,Qg as removeAddressRecords,pg as removeDns01ChallengeRecord,Bn as removeSiteFromCloudConfig,Nu as removeSourceWebhook,Gc as removeStaleServerAddressRecords,xd as renderComposeTemplate,Xi as renderDdosInstallScript,ll as renderNftablesRuleset,Es as renderServerCron,dl as renderSysctlFile,Ad as renderWafConfig,Bi as renderWafInstallScript,hd as renewRpxCertificates,yS as replicaManager,uy as requestHash,iC as requiresReplacement,VE as resetRecursionRuntime,qE as resolveApp,p as resolveAppDatabase,vA as resolveAttachTarget,ct as resolveAuthEncryptionKey,le as resolveCloudProvider,xg as resolveCloudflareCdnPlan,ri as resolveComputeVolumes,ra as resolveCredentials,xs as resolveDashboardAction,md as resolveDashboardAuth,vy as resolveDashboardDomain,Ty as resolveDashboardDomains,js as resolveDeclaredRecords,nb as resolveDeployBucketName,W as resolveDeploymentMode,oi as resolveExecStart,Ko as resolveFailoverStatusCodes,Yc as resolveHetznerApiToken,Qr as resolveHostCleanupConfig,w as resolveMailProxy,b as resolveMailService,wb as resolveManagementDashboardSite,ts as resolveManagementDashboardSites,Dc as resolveObjectStorage,ue as resolveOriginConnection,SA as resolvePlan,Te as resolveProfileName,m as resolveProjectStackName,Wr as resolveProxyUpstreams,zl as resolveQueueNames,QA as resolveQueuedDeploymentCommand,yr as resolveQueues,RS as resolveRecursionConfig,xy as resolveRegion,fe as resolveRuntimeInventory,ur as resolveServerlessAppStackName,Al as resolveServerlessArtifactBucketName,Zi as resolveServerlessAssetBucketName,cs as resolveServerlessRuntime,tb as resolveSiteBucketName,Eo as resolveSiteDeployTarget,d as resolveSiteKind,eb as resolveSiteResourceName,ZI as resolveSiteStackName,Ai as resolveSshSettings,l as resolveStatePath,rb as resolveStorageBucketName,_m as resolveStorageFailover,rr as resolveUiSource,Id as resolveZoneApex,XE as resourceManagementManager,zf as responseToResult,pm as robustZScore,ir as roleCapabilities,vu as rollbackImmutableRelease,On as rollbackServerlessApp,JA as roundCents,xE as route53ResolverManager,CS as route53RoutingManager,hm as routeMatches,Fp as routesFromFragments,us as ruleMatches,ES as runBuildHooks,Wd as runEnforcement,la as runPhpBuildHooks,ut as runRemoteCommand,we as runtimeId,Ge as s3OriginBucket,Lm as s3RegionalDomain,ks as sameCorsRules,Fs as sameLifecycleRules,Yn as sameNameservers,Bs as sanitizeCloudConfig,s as sanitizeControlPlaneValue,YI as sanitizeName,yu as sanitizeOidcReturnPath,il as saveTelemetryPolicy,ch as scanForSecrets,Dd as scopeContains,Pt as scopeKey,Kc as scpUpload,vC as searchCommands,To as searchControlPlane,SS as secretsManager,bE as secretsRotationManager,YS as secureContainerRelease,uS as securityHubManager,EE as securityScanningManager,me as securityScope,yg as seedFailoverReplicas,bn as sendAuthenticationEmail,LE as senderReputationManager,Zb as sequence,Dg as serializeDotenv,Ri as serverPublicIpv4,bS as serviceMeshManager,gg as setAttachToInCloudConfig,vr as setMaintenance,Rs as setSitePropertyInCloudConfig,gl as setStateDir,ER as setupDns01Challenge,Lc as setupSmsInfrastructure,ia as sha256,Zo as sharedConfigPath,rs as sharedCredentialsPath,PS as sharedRecursionGuard,Gf as sharedRuntimeLoop,nm as shipsARelease,dR as signCloudFrontCookies,uR as signCloudFrontUrl,N as signRequest,iu as signRequestAsync,Fo as signalDefinition,Q as siteInstallBase,Oi as siteMoveArchivePath,PA as siteMoveCertArchivePath,vd as siteUnitGlob,bm as spendNotificationText,zo as spendOpenApiPaths,wy as splitCommandLine,Hr as sshExec,Ce as sshExecOrThrow,LC as stackDependencyManager,Cc as startLocalDashboardServer,dy as startSpendLoop,ln as stateDir,H as statePath,KE as staticSiteManager,_S as storageAdvancedManager,ab as storageFailoverReplicasFromTemplate,ty as streamFocusJsonl,Jd as strongestActiveAction,rf as suggestCommand,wC as suggestFlags,Qb as suggestIAMPolicy,Vb as suggestQuotaIncrease,VC as suggestRegionPairs,GC as suggestRegions,ys as syncSourceRepositories,Md as synchronizeComposeVolumes,Pg as synchronizeConfiguredConfiguration,$a as synchronizeConfiguredJobs,AS as syntheticsManager,cl as sysctlHardening,fh as systemdWorkloads,oy as telemetryBucketLabel,Wi as telemetryCursor,sl as telemetryEstimatedMonthlyCost,sy as telemetryPercentile,Im as telemetryPolicyKey,Uy as templateCache,Up as tenantsOf,Pa as testSourceConnection,Fd as tieredMicroCents,lp as toApiLifecycleRule,Jc as toCloudflareZoneSettings,Ho as toFocusJsonl,el as toFocusRecords,fA as toInventoryServer,rh as totp,Ia as totpUri,Qp as unaccountedSites,uh as unsupportedCapabilities,HA as unsupportedVolumeCapabilities,ig as updateCompatibility,og as updateSiteInCloudConfig,Ls as uploadStaticFiles,cm as usageDeltaKey,cr as utcInstantOfLocal,ZC as validateAccountStructure,cC as validateAgainstSchema,VA as validateAttachment,Oh as validateBackupDestination,PC as validateCommand,$b as validateConfiguration,Fb as validateCredentials,rm as validateDeploymentConfig,GA as validateMountPath,Bt as validateOriginGroups,_p as validateResourceLimits,Gp as validateServerName,Dp as validateTemplate,xp as validateTemplateSize,qc as verifyAddressRecord,WS as verifyArtifactSignature,mR as verifyMediaAccessToken,nh as verifyTotp,ng as verifyUpdateSignature,to as verifyZoneParity,Po as volumeCapabilities,kp as wafEventTelemetry,Wc as waitForCloudInit,yt as waitForSsh,Ir as webhookEndpoint,xb as withCDN,Bb as withCache,pp as withContentHash,Nb as withDatabase,jf as withInvocation,Pb as withMonitoring,Ob as withQueue,kb as withSecurity,eC as withTimeout,mp as workerBindings,lo as workerContentHash,qs as workerInSync,ae as wrapCloudInitUserData,It as writeDriverState,hE as xrayManager,Zu as zeroCapacity,ry as zeroFill,Qd as zoneOffsetMs,Oo as zonedParts};
604
+ `}async function dg(u,g,h){let S=`_acme-challenge.${g}`;if(await gg(u,g,S,h))return;let A=await u.createRecord(g,{name:S,type:"TXT",content:h,ttl:60});if(!A.success)throw Error(`Failed to create DNS challenge record: ${A.message}`)}async function mg(u,g,h){let S=await u.deleteRecord(g,{name:`_acme-challenge.${g}`,type:"TXT",content:h});if(!S.success)console.warn(`Failed to delete DNS challenge record: ${S.message}`)}async function gg(u,g,h,S){try{let A=await u.listRecords(g,"TXT"),T=h.replace(/\.$/,"").toLowerCase();return(A.records??[]).some((P)=>P.name.replace(/\.$/,"").toLowerCase()===T&&P.content.replace(/^"|"$/g,"")===S)}catch{return!1}}function gd(u){let{hostedZoneId:g,dnsProvider:h,region:S="us-east-1"}=u;if(h)return B(h);if(g)return new oe(S,g);throw Error("Either dnsProvider or hostedZoneId must be provided")}async function OR(u){await dg(gd(u),u.domain,u.challengeValue)}async function NR(u){await mg(gd(u),u.domain,u.challengeValue)}function xR(u){try{let{execSync:g}=us("node:child_process"),h=g(`openssl x509 -checkend 2592000 -noout -in ${u}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as Cd,createSign as fg,generateKeyPairSync as Sd}from"node:crypto";var bd={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class hg{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(u){this.directoryUrl=u.staging?bd.staging:bd.production,this.email=u.email,this.accountKey=u.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:u}=Sd("ec",{namedCurve:"P-256"});return u.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let u=await fetch(this.directoryUrl);if(!u.ok)throw Error(`Failed to fetch ACME directory: ${u.status}`);return this.directory=await u.json(),this.directory}async getNonce(){if(this.nonce){let S=this.nonce;return this.nonce=null,S}let u=await this.getDirectory(),h=(await fetch(u.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!h)throw Error("Failed to get nonce from ACME server");return h}getJwk(){let u=this.accountKey.split(`
605
+ `).filter((T)=>!T.startsWith("-----")).join(""),g=Buffer.from(u,"base64"),h=g.length-65,S=g.subarray(h+1,h+33),A=g.subarray(h+33,h+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(S),y:this.base64UrlEncode(A)}}getJwkThumbprint(){let u=this.getJwk(),g=JSON.stringify({crv:u.crv,kty:u.kty,x:u.x,y:u.y}),h=Cd("sha256").update(g).digest();return this.base64UrlEncode(h)}base64UrlEncode(u){return(typeof u==="string"?Buffer.from(u):u).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(u,g){let h=await this.getNonce(),S=this.getJwk(),A={alg:"ES256",nonce:h,url:u};if(this.accountUrl)A.kid=this.accountUrl;else A.jwk=S;let T=this.base64UrlEncode(JSON.stringify(A)),P=g===""?"":this.base64UrlEncode(JSON.stringify(g)),M=`${T}.${P}`,W=fg("SHA256");W.update(M);let le=W.sign(this.accountKey),K=le.subarray(4,4+le[3]),Ct=4+le[3]+2,Tt=le.subarray(Ct,Ct+le[Ct-1]),He=Buffer.alloc(32),Se=Buffer.alloc(32);K.copy(He,32-K.length),Tt.copy(Se,32-Tt.length);let Ie=Buffer.concat([He,Se]);return JSON.stringify({protected:T,payload:P,signature:this.base64UrlEncode(Ie)})}async acmeRequest(u,g){let h=await this.signPayload(u,g),S=await fetch(u,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:h}),A=S.headers.get("replay-nonce");if(A)this.nonce=A;let T,P=S.headers.get("content-type");if(P?.includes("application/json")||P?.includes("application/problem+json"))T=await S.json();else T=await S.text();if(!S.ok)throw Error(`ACME request failed: ${JSON.stringify(T)}`);return{body:T,headers:S.headers}}async registerAccount(){let u=await this.getDirectory(),{body:g,headers:h}=await this.acmeRequest(u.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),S=h.get("location");if(!S)throw Error("No account URL returned");return this.accountUrl=S,S}async createOrder(u){if(!this.accountUrl)await this.registerAccount();let g=await this.getDirectory(),{body:h,headers:S}=await this.acmeRequest(g.newOrder,{identifiers:u.map((T)=>({type:"dns",value:T}))}),A=S.get("location");if(!A)throw Error("No order URL returned");return{orderUrl:A,authorizations:h.authorizations,finalize:h.finalize}}async getAuthorization(u){let{body:g}=await this.acmeRequest(u,""),h=g.identifier.value,S=this.getJwkThumbprint(),A=g.challenges.filter((T)=>T.type==="http-01"||T.type==="dns-01").map((T)=>{let P=`${T.token}.${S}`;if(T.type==="http-01")return{type:"http-01",token:T.token,keyAuthorization:P,identifier:`/.well-known/acme-challenge/${T.token}`};else{let M=this.base64UrlEncode(Cd("sha256").update(P).digest());return{type:"dns-01",token:T.token,keyAuthorization:P,identifier:`_acme-challenge.${h}`,dnsValue:M}}});return{domain:h,challenges:A}}async respondToChallenge(u){await this.acmeRequest(u,{})}async waitForAuthorization(u,g=30){for(let h=0;h<g;h++){let{body:S}=await this.acmeRequest(u,"");if(S.status==="valid")return;if(S.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(S)}`);await new Promise((A)=>setTimeout(A,2000))}throw Error("Authorization timed out")}generateCsr(u){let{privateKey:g}=Sd("rsa",{modulusLength:2048}),h=g.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(u,g),privateKey:h}}createSimpleCsr(u,g){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(u,g){let{csr:h,privateKey:S}=this.generateCsr(g),{body:A}=await this.acmeRequest(u,{csr:this.base64UrlEncode(Buffer.from(h,"base64"))}),T=A.certificate;if(!T)throw Error("Certificate not immediately available - polling not implemented");let M=await(await fetch(T)).text(),W=M.split(/(?=-----BEGIN CERTIFICATE-----)/g),le=W[0],K=W.slice(1).join("");return{certificate:le,privateKey:S,chain:K,fullchain:M,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var Ur=(u)=>u===void 0?void 0:u?"on":"off";function Yc(u){let g={ssl:u.ssl,always_use_https:Ur(u.alwaysUseHttps),automatic_https_rewrites:Ur(u.automaticHttpsRewrites),min_tls_version:u.minTlsVersion,tls_1_3:Ur(u.tls13),brotli:Ur(u.brotli),http3:Ur(u.http3),"0rtt":Ur(u.zeroRtt),early_hints:Ur(u.earlyHints),browser_cache_ttl:u.browserCacheTtl,always_online:Ur(u.alwaysOnline),websockets:Ur(u.websockets),email_obfuscation:Ur(u.emailObfuscation)};if(u.hsts)g.security_header={strict_transport_security:{enabled:u.hsts.enabled,max_age:u.hsts.maxAge??31536000,include_subdomains:u.hsts.includeSubdomains??!1,preload:u.hsts.preload??!1,nosniff:u.hsts.noSniff??!0}};for(let h of Object.keys(g))if(g[h]===void 0)delete g[h];return{...g,...u.raw??{}}}var Ei={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 Cg}from"node:tls";async function Xc(u){let{address:g,serverName:h,port:S=443,timeoutMs:A=5000}=u;return new Promise((T)=>{let P=!1,M=(le)=>{if(P)return;P=!0;try{W.destroy()}catch{}T(le)},W=Cg({host:g,port:S,servername:h,rejectUnauthorized:!1,timeout:A});W.once("secureConnect",()=>{if(W.authorized){M({reachable:!0,trusted:!0});return}M({reachable:!0,trusted:!1,reason:W.authorizationError?String(W.authorizationError):"origin certificate is not trusted for this hostname"})}),W.once("timeout",()=>{M({reachable:!1,trusted:!1,reason:`no TLS handshake within ${A}ms`})}),W.once("error",(le)=>{M({reachable:!1,trusted:!1,reason:le.message})})})}function $g(u,g){let h=g.replace(/\.$/,"").toLowerCase();return u.some((S)=>{let A=S.replace(/\.$/,"").toLowerCase();if(A===h)return!0;if(!A.startsWith("*."))return!1;let T=A.slice(2);if(!h.endsWith(`.${T}`))return!1;return!h.slice(0,h.length-T.length-1).includes(".")})}async function Eg(u){let{provider:g,zone:h,hosts:S,ipv4:A,ipv6:T,proxied:P=!0,settings:M=Ei,cache:W,originGuard:le,purge:K=!0,ttl:Ct=300,skipOriginProbe:Tt=!1,skipEdgeCertificateCheck:He=!1}=u,Se={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(S.length===0)return Se;let Ie=[],z=P&&!He?await g.listEdgeCertificateHosts(h):null;for(let V of S){let Ke=P;if(Ke&&z&&!$g(z,V)){Ke=!1;let It=z.length===0?"the zone has no active edge certificate yet":`no active edge certificate covers it (${z.join(", ")})`;Se.deferredProxy.push({host:V,reason:It}),Se.warnings.push(`${V}: publishing DNS-only — ${It}. 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(Ke&&!Tt){let It=await Xc({address:A,serverName:V});if(!It.trusted){Ke=!1;let vt=It.reason||"origin is not serving a trusted certificate";Se.deferredProxy.push({host:V,reason:vt}),Se.warnings.push(`${V}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${vt}). 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(Ke)Ie.push(V);let yt=[{type:"A",content:A}];if(T&&ei(V))yt.push({type:"AAAA",content:T});for(let{type:It,content:vt}of yt){let Ht=await g.upsertRecord(h,{name:V,type:It,content:vt,ttl:Ct,proxied:Ke});if(Ht.success)Se.records.push({host:V,type:It,content:vt,proxied:Ke});else Se.warnings.push(`${V} ${It} → ${vt} failed: ${Ht.message||"unknown provider error"}`)}}if(Ie.length===0){if(P)Se.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return Se}try{let V=Yc(M),Ke=await g.applyZoneSettings(h,V);Se.settingsChanged=Ke.changed;for(let yt of Ke.failed)Se.warnings.push(`zone setting '${yt.id}' could not be applied: ${yt.error}`)}catch(V){Se.warnings.push(`zone settings could not be read: ${V instanceof Error?V.message:String(V)}`)}let Ye=Uc(Ie,W);if(Ye.length>0){let V=await g.putManagedPhaseRules(h,"http_request_cache_settings",Ye);if(V.success)Se.cacheRules=Ye.length;else Se.warnings.push(`cache rules could not be written: ${V.message}`)}if(le){let V=Qc(Ie,le.header,le.value);if(V.length>0){let Ke=await g.putManagedPhaseRules(h,"http_request_late_transform",V);if(Ke.success)Se.originGuard=!0;else Se.warnings.push(`origin guard header could not be written: ${Ke.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(K){if(Se.purged=await g.purgeCache(h,{hosts:Ie}),!Se.purged)Se.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return Se}var Og=(u)=>process.env[u];function Id(u,g){let h=u.replace(/\.$/,"").toLowerCase();if(g){let S=g.replace(/\.$/,"").toLowerCase();if(h===S||h.endsWith(`.${S}`))return S}return h.split(".").slice(-2).join(".")}function Ng(u,g={}){let h=g.env??Og,S=u.infrastructure?.compute?.proxy?.cdn,A=[];if(!S||S.provider!=="cloudflare")return{plan:null,errors:A};if(S.originDomain)A.push(`compute.proxy.cdn.originDomain (${S.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 T=h("CLOUDFLARE_API_TOKEN");if(!T)return A.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:A};let P=u.sites??{},M=S.frontedHosts?.length?[...new Set(S.frontedHosts.map((Tt)=>Tt.toLowerCase()))]:Co(P,{autoWww:u.infrastructure?.compute?.proxy?.autoWww!==!1});if(M.length===0)return A.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:A};let W=u.infrastructure?.dns?.domain,le=new Set(M.map((Tt)=>Id(Tt,W)));if(le.size>1)return A.push(`Fronted hosts span more than one zone (${[...le].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:A};let K=S.cloudflare??{},Ct=S.secret?{header:S.secretHeader??"X-Origin-Verify",value:S.secret}:void 0;return{plan:{zone:[...le][0],hosts:M,apiToken:T,zoneId:K.zoneId??h("CLOUDFLARE_ZONE_ID"),accountId:K.accountId??h("CLOUDFLARE_ACCOUNT_ID"),proxied:K.proxied!==!1,settings:K.settings??Ei,cache:K.cache,originGuard:Ct,purge:K.purgeOnDeploy!==!1,skipOriginProbe:K.skipOriginProbe===!0},errors:A}}var Lg=26214400;var _g=new Set(["/_headers","/_redirects","/_routes.json","/_worker.js"]);class Ed{name="cloudflare-pages";apiToken;accountId;constructor(u){if(!u.apiToken)throw Error("Cloudflare Pages needs an API token");if(!u.accountId)throw Error("Cloudflare Pages needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId}async request(u,g,h){return Eo(u,`/accounts/${this.accountId}${g}`,`Bearer ${this.apiToken}`,h)}async getProject(u){try{return await this.request("GET",`/pages/projects/${u}`)}catch(g){if(g instanceof Error&&/\b8000007\b|not found/i.test(g.message))return null;throw g}}async ensureProject(u,g="main"){let h=await this.getProject(u);if(h)return h;return this.request("POST","/pages/projects",{name:u,production_branch:g})}async uploadToken(u){return(await this.request("GET",`/pages/projects/${u}/upload-token`)).jwt}async missingHashes(u,g){let h=await Eo("POST","/pages/assets/check-missing",`Bearer ${u}`,{hashes:g});return new Set(h)}async upsertHashes(u,g){await Eo("POST","/pages/assets/upsert-hashes",`Bearer ${u}`,{hashes:g})}async uploadBatch(u,g){let h=g.map((S)=>({key:S.hash,value:S.base64,metadata:{contentType:Wg(S.extension)},base64:!0}));await Eo("POST","/pages/assets/upload",`Bearer ${u}`,h)}async createDeployment(u,g,h){let S={};for(let T of g)S[T.path]=T.hash;let A=new FormData;if(A.append("manifest",JSON.stringify(S)),h)A.append("branch",h);return this.request("POST",`/pages/projects/${u}/deployments`,A)}async deployDirectory(u){let g=await tp(u.directory);if(g.length===0)throw Error(`No files to deploy in ${u.directory}`);let h=await this.uploadToken(u.project),S=await this.missingHashes(h,g.map((W)=>W.hash)),A=g.filter((W)=>S.has(W.hash)),T=[];for(let W=0;W<A.length;W+=100)T.push(A.slice(W,W+100));let P=0;for(let W=0;W<T.length;W+=4){let le=T.slice(W,W+4);await Promise.all(le.map((K)=>this.uploadBatch(h,K))),P+=le.reduce((K,Ct)=>K+Ct.length,0),u.onProgress?.(P,A.length)}return await this.upsertHashes(h,g.map((W)=>W.hash)),{deployment:await this.createDeployment(u.project,g,u.branch),total:g.length,uploaded:A.length,uploadedBytes:A.reduce((W,le)=>W+le.size,0)}}async listCustomDomains(u){return(await this.request("GET",`/pages/projects/${u}/domains`)).map((h)=>h.name)}async attachCustomDomain(u,g){if((await this.listCustomDomains(u)).includes(g))return!1;return await this.request("POST",`/pages/projects/${u}/domains`,{name:g}),!0}}function Bg(u,g){return{type:"CNAME",name:u,value:g.endsWith(".pages.dev")?g:`${g}.pages.dev`,ttl:1,proxied:!0}}async function ep(u,g){let{blake3:h}=await import("./chunk-7zjf2493.js").then((m)=>$S(m.default,1));return(await h(u+g)).slice(0,32)}async function tp(u){let{readdir:g}=await import("node:fs/promises"),{join:h,relative:S,sep:A}=await import("node:path"),T=[];async function P(M){let W=await g(M,{withFileTypes:!0});for(let le of W){let K=h(M,le.name);if(le.isDirectory()){await P(K);continue}if(!le.isFile())continue;let Ct=`/${S(u,K).split(A).join("/")}`;if(_g.has(Ct))continue;let Tt=await Bun.file(K).bytes();if(Tt.byteLength>26214400)throw Error(`${Ct} is ${Tt.byteLength} bytes, over the Cloudflare Pages limit of 26214400`);let He=Buffer.from(Tt).toString("base64"),Se=le.name.lastIndexOf("."),Ie=Se>0?le.name.slice(Se+1):"";T.push({path:Ct,hash:await ep(He,Ie),base64:He,extension:Ie,size:Tt.byteLength})}}return await P(u),T.sort((M,W)=>M.path.localeCompare(W.path)),T}function Wg(u){return{html:"text/html; charset=utf-8",css:"text/css; charset=utf-8",js:"application/javascript; charset=utf-8",mjs:"application/javascript; charset=utf-8",json:"application/json; charset=utf-8",map:"application/json; charset=utf-8",xml:"application/xml; charset=utf-8",txt:"text/plain; charset=utf-8",svg:"image/svg+xml",png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp",avif:"image/avif",ico:"image/x-icon",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",pdf:"application/pdf",webmanifest:"application/manifest+json"}[u.toLowerCase()]||"application/octet-stream"}async function Eo(u,g,h,S){let A={Authorization:h},T;if(S instanceof FormData)T=S;else if(S!==void 0)A["Content-Type"]="application/json",T=JSON.stringify(S);let P=await fetch(`https://api.cloudflare.com/client/v4${g}`,{method:u,headers:A,body:T}),M=await P.text(),W;try{W=JSON.parse(M)}catch{throw Error(`Cloudflare Pages API returned ${P.status} with a non-JSON body: ${M.slice(0,200)}`)}if(!W.success){let le=(W.errors??[]).map((K)=>`${K.code}: ${K.message}`).join(", ");throw Error(`Cloudflare Pages API error (${P.status}): ${le||M.slice(0,200)}`)}return W.result}import{createHash as zg}from"node:crypto";var np="https://api.cloudflare.com/client/v4",ip=10042,jg=10006,Kg=10059;class _n extends Error{status;errors;constructor(u,g,h=[]){super(u);this.name="R2ApiError",this.status=g,this.errors=h}hasCode(u){return this.errors.some((g)=>g.code===u)}}class Sn extends _n{accountId;constructor(u,g,h=[]){super(`R2 is not enabled on Cloudflare account ${u}. Enable it once in the Cloudflare dashboard (R2 Object Storage, then follow the prompt to activate it), then re-run the deploy.`,g,h);this.name="R2NotEnabledError",this.accountId=u}}class ui{name="cloudflare-r2";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare R2 needs an API token");if(!u.accountId)throw Error("Cloudflare R2 needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((g,h)=>fetch(g,h))}async requestEnvelope(u,g,h,S={}){let A={Authorization:`Bearer ${this.apiToken}`};if(h!==void 0)A["Content-Type"]="application/json";if(S.jurisdiction&&S.jurisdiction!=="default")A["cf-r2-jurisdiction"]=S.jurisdiction;let T=await this.fetchImpl(`${np}/accounts/${this.accountId}/r2${g}`,{method:u,headers:A,body:h===void 0?void 0:JSON.stringify(h)}),P=await T.text(),M;try{M=JSON.parse(P)}catch{throw new _n(`Cloudflare R2 API returned ${T.status} with a non-JSON body: ${P.slice(0,200)}`,T.status)}if(!M.success){let W=M.errors??[];if(W.some((K)=>K.code===ip))throw new Sn(this.accountId,T.status,W);let le=W.map((K)=>`${K.code}: ${K.message}`).join(", ");throw new _n(`Cloudflare R2 API error (${T.status}) on ${u} ${g}: ${le||P.slice(0,200)}`,T.status,W)}return M}async request(u,g,h,S){return(await this.requestEnvelope(u,g,h,S)).result}bucketPath(u){return`/buckets/${encodeURIComponent(u)}`}async listBuckets(u={}){let g=[],h;do{let S=new URLSearchParams({per_page:"1000"});if(h)S.set("cursor",h);let A=await this.requestEnvelope("GET",`/buckets?${S}`,void 0,u),T=A.result?.buckets??[];g.push(...T),h=T.length>0?A.result_info?.cursor||void 0:void 0}while(h);return g}async getBucket(u,g={}){try{return await this.request("GET",this.bucketPath(u),void 0,g)}catch(h){if(h instanceof Sn)throw h;if(h instanceof _n&&(h.hasCode(jg)||h.status===404))return null;throw h}}async ensureBucket(u,g={}){let h={jurisdiction:g.jurisdiction},S=await this.getBucket(u,h);if(S)return{bucket:S,created:!1};let A={name:u};if(g.locationHint)A.locationHint=g.locationHint;let T=await this.request("POST","/buckets",A,h);return{bucket:{...T,name:T?.name||u},created:!0}}async getCors(u,g={}){try{return(await this.request("GET",`${this.bucketPath(u)}/cors`,void 0,g))?.rules??[]}catch(h){if(h instanceof _n&&!(h instanceof Sn)&&(h.hasCode(Kg)||h.status===404))return[];throw h}}async putCors(u,g,h={}){if(g.length===0){await this.request("DELETE",`${this.bucketPath(u)}/cors`,void 0,h);return}await this.request("PUT",`${this.bucketPath(u)}/cors`,{rules:g},h)}async ensureCors(u,g,h={}){let S=await this.getCors(u,h);if(Ps(S,g))return!1;return await this.putCors(u,g,h),!0}async getLifecycle(u,g={}){return(await this.request("GET",`${this.bucketPath(u)}/lifecycle`,void 0,g))?.rules??[]}async putLifecycle(u,g,h={}){await this.request("PUT",`${this.bucketPath(u)}/lifecycle`,{rules:g},h)}async ensureLifecycle(u,g,h={}){let S=await this.getLifecycle(u,h);if(Ns(S,g))return!1;return await this.putLifecycle(u,g,h),!0}async listCustomDomains(u,g={}){return(await this.request("GET",`${this.bucketPath(u)}/domains/custom`,void 0,g))?.domains??[]}async attachCustomDomain(u,g,h={}){return this.request("POST",`${this.bucketPath(u)}/domains/custom`,{domain:g.domain,zoneId:g.zoneId,enabled:g.enabled??!0,minTLS:g.minTLS??"1.2"},h)}async updateCustomDomain(u,g,h,S={}){return this.request("PUT",`${this.bucketPath(u)}/domains/custom/${encodeURIComponent(g)}`,h,S)}async ensureCustomDomain(u,g,h={},S){let A=g.minTLS??"1.2",P=(S??await this.listCustomDomains(u,h)).find((le)=>le.domain.toLowerCase()===g.domain.toLowerCase());if(!P){let le=await this.attachCustomDomain(u,{...g,minTLS:A,enabled:!0},h);return{action:"attached",domain:{...le,domain:le?.domain||g.domain}}}let M=P.minTLS??"1.0";if(P.enabled&&M===A)return{action:"unchanged",domain:P};let W=await this.updateCustomDomain(u,P.domain,{enabled:!0,minTLS:A},h);return{action:"updated",domain:{...P,...W}}}async getManagedDomain(u,g={}){return this.request("GET",`${this.bucketPath(u)}/domains/managed`,void 0,g)}async setManagedDomain(u,g,h={}){let S=await this.getManagedDomain(u,h);if(S?.enabled===g)return{changed:!1,domain:S};return{changed:!0,domain:await this.request("PUT",`${this.bucketPath(u)}/domains/managed`,{enabled:g},h)}}}function op(u){return`https://${u}.r2.cloudflarestorage.com`}async function Zg(u){let{apiToken:g,accountId:h}=u;if(!g)throw Error("r2S3Credentials needs an API token");if(!h)throw Error("r2S3Credentials needs an account id");let S=u.fetch??((P,M)=>fetch(P,M)),A=[],T;for(let P of[`/accounts/${h}/tokens/verify`,"/user/tokens/verify"]){let M=await S(`${np}${P}`,{method:"GET",headers:{Authorization:`Bearer ${g}`}}),W=await M.json().catch(()=>null);if(M.ok&&W?.success&&W.result?.id){T=W.result.id;break}let le=W?.errors?.map((K)=>`${K.code}: ${K.message}`).join(", ");A.push(`${P} -> ${M.status}${le?` (${le})`:""}`)}if(!T)throw Error(`Could not verify the Cloudflare API token to derive R2 credentials: ${A.join("; ")}`);return{accessKeyId:T,secretAccessKey:zg("sha256").update(g).digest("hex"),endpoint:op(h),region:"auto"}}function Oi(u){if(Array.isArray(u))return`[${u.map(Oi).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[S])=>h.localeCompare(S)).map(([h,S])=>`${JSON.stringify(h)}:${Oi(S)}`).join(",")}}`;return JSON.stringify(u)}function rp(u,g){let h=(S)=>S&&S.length>0?[...S].map(String).sort():void 0;return{id:g?u.id:void 0,allowed:{origins:h(u.allowed?.origins),methods:h(u.allowed?.methods?.map((S)=>S.toUpperCase())),headers:h(u.allowed?.headers?.map((S)=>S.toLowerCase()))},exposeHeaders:h(u.exposeHeaders?.map((S)=>S.toLowerCase())),maxAgeSeconds:u.maxAgeSeconds}}function Ps(u,g){if(u.length!==g.length)return!1;return g.every((h,S)=>{let A=h.id!==void 0;return Oi(rp(u[S],A))===Oi(rp(h,A))})}function Ns(u,g){if(u.length!==g.length)return!1;let h=(S)=>Oi([...S].map((A)=>({...A,storageClassTransitions:A.storageClassTransitions?.length?A.storageClassTransitions:void 0})).sort((A,T)=>A.id.localeCompare(T.id)));return h(u)===h(g)}var Jg="r2 cache",Yg=/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;async function Xg(u,g={}){let h=g.log??(()=>{}),S={buckets:[],warnings:[]},A=u.infrastructure?.r2??u.r2,T=Object.entries(A?.buckets??{});if(T.length===0)return h("R2: no buckets declared, skipping."),S;if(!g.apiToken||!g.accountId){let K=[!g.apiToken&&"CLOUDFLARE_API_TOKEN",!g.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),Ct=`R2: ${T.length} bucket(s) declared but ${K} is not set, skipping.`;return h(Ct),S.warnings.push(Ct),S}let P=g.dryRun===!0,M=new ui({apiToken:g.apiToken,accountId:g.accountId,fetch:g.fetch}),W=new G(g.apiToken,{zoneId:g.zoneId,accountId:g.accountId}),le=new Map;for(let[K,Ct]of T){let Tt=Ct?.name;if(!Tt||!Yg.test(Tt)){S.warnings.push(`R2: bucket '${K}' has an invalid name '${Tt??""}' (3-63 chars: lowercase letters, digits, hyphens), skipping.`);continue}h(`R2: ${P?"checking":"reconciling"} bucket ${Tt}...`);let He={name:Tt,changes:[],domains:[]};if(S.buckets.push(He),await Ph(Ct,{r2:M,cloudflare:W,dryRun:P,summary:He,warnings:S.warnings,claimed:le,log:h}),He.changes.length===0)h(`R2: ${Tt} is in sync.`);else for(let Se of He.changes)h(`R2: ${Tt}: ${Se}`)}return S}async function Ph(u,g){let{r2:h,dryRun:S,summary:A,warnings:T}=g,P=u.name,M={jurisdiction:u.jurisdiction},W=(He,Se)=>{let Ie=S?Se&&`would ${Se}`:He;if(Ie)A.changes.push(Ie)},le;if(S)le=await h.getBucket(P,M)!==null;else{let{created:He}=await h.ensureBucket(P,{locationHint:u.locationHint,jurisdiction:u.jurisdiction});if(le=!0,He)W("created","")}if(!le)W("","create bucket");let K=kh(u.customDomains);await xi(g,`cors on ${P}`,async()=>{if(!u.cors)return;if(!le){W("cors updated","set cors");return}let He=await h.getCors(P,M);if(Ps(He,u.cors))return;if(!S)await h.putCors(P,u.cors,M);W(u.cors.length===0?"cors removed":"cors updated",u.cors.length===0?"remove cors":"update cors")}),await xi(g,`lifecycle on ${P}`,async()=>{if(!u.lifecycle)return;let He=u.lifecycle.map(cp);if(le){let Se=await h.getLifecycle(P,M);if(Ns(Se,He))return}if(!S)await h.putLifecycle(P,He,M);W("lifecycle updated","update lifecycle")}),await xi(g,`r2.dev URL on ${P}`,async()=>{let He=u.publicDevUrl===!0;if(!le){if(He)W("r2.dev URL enabled","enable r2.dev URL");return}if((await h.getManagedDomain(P,M))?.enabled===He)return;if(!S)await h.setManagedDomain(P,He,M);W(He?"r2.dev URL enabled":"r2.dev URL disabled",He?"enable r2.dev URL":"disable r2.dev URL")});let Ct=[];if(K.length>0&&le)try{Ct=await h.listCustomDomains(P,M)}catch(He){if(He instanceof Sn)throw He;T.push(`R2: could not list custom domains on ${P}: ${td(He)}`)}let Tt=new Map;for(let{domain:He,minTLS:Se}of K){let Ie=g.claimed.get(He);if(Ie&&Ie!==P){T.push(`R2: ${He} is declared on both ${Ie} and ${P}; leaving it on ${Ie}.`);continue}g.claimed.set(He,P);let z=Ct.find((V)=>V.domain.toLowerCase()===He),Ye=Se??"1.2";if(z&&z.enabled&&(z.minTLS??"1.0")===Ye){if(A.domains.push({domain:He,status:ed(z)}),z.zoneId)Tt.set(He,z.zoneId);continue}await xi(g,`custom domain ${He} on ${P}`,async()=>{if(z){if(!S)await h.updateCustomDomain(P,z.domain,{enabled:!0,minTLS:Ye},M);if(W(`custom domain ${He} updated`,`update custom domain ${He}`),A.domains.push({domain:He,status:ed({...z,enabled:!0})}),z.zoneId)Tt.set(He,z.zoneId);return}let V=await g.cloudflare.zoneIdFor(He);if(Tt.set(He,V),!S)await h.ensureCustomDomain(P,{domain:He,zoneId:V,minTLS:Ye},M,Ct);W(`custom domain ${He} attached`,`attach custom domain ${He}`),A.domains.push({domain:He,status:S?"not attached":"pending"})},()=>A.domains.push({domain:He,status:"error"}))}if(u.cache&&K.length>0)await Dh(u,K.map((He)=>He.domain).filter((He)=>g.claimed.get(He)===P),Tt,g,W)}async function Dh(u,g,h,S,A){let T=sp(u.cache);if(!T||g.length===0)return;let P=new Map;for(let M of g){let W=h.get(M);if(!W)try{W=await S.cloudflare.zoneIdFor(M)}catch(le){S.warnings.push(`R2: could not resolve the zone for ${M}, cache rule skipped: ${td(le)}`);continue}P.set(W,[...P.get(W)??[],M])}for(let M of P.values()){let W={action:"set_cache_settings",description:`${Wt} ${Jg}`,expression:`(${Kt(M)})`,enabled:!0,action_parameters:T};await xi(S,`cache rule for ${M.join(", ")}`,async()=>{let le=await S.cloudflare.getPhaseRules(M[0],"http_request_cache_settings");if(ap(le,W))return;if(!S.dryRun){let K=await S.cloudflare.putManagedPhaseRules(M[0],"http_request_cache_settings",[W]);if(!K.success)throw Error(K.message||"cache rule write failed")}A(`cache rule updated for ${M.join(", ")}`,`update cache rule for ${M.join(", ")}`)})}}function sp(u){if(u.edgeTtl===void 0&&u.browserTtl===void 0)return null;let g={cache:!0};if(u.edgeTtl!==void 0)g.edge_ttl={mode:"override_origin",default:u.edgeTtl};if(u.browserTtl!==void 0)g.browser_ttl={mode:"override_origin",default:u.browserTtl};return g}function ap(u,g){let h=Jt(g.expression),S=Jn(g.expression),A=(M)=>(M.description||"").startsWith(Wt),T=(M)=>M.action===g.action&&M.description===g.description&&(M.enabled??!0)===(g.enabled??!0)&&Jn(M.expression)===S&&Fs(M.action_parameters)===Fs(g.action_parameters),P=!1;for(let M of u){if(!A(M))continue;let W=Jt(M.expression);if(!h.some((K)=>W.includes(K)))continue;if(T(M)&&h.every((K)=>W.includes(K))&&!P){P=!0;continue}return!1}return P}function cp(u){let g={id:u.id,enabled:u.enabled??!0,conditions:{prefix:u.prefix??""}};if(u.expireAfterDays!==void 0)g.deleteObjectsTransition={condition:{type:"Age",maxAge:du(u.expireAfterDays)}};else if(u.expireOn!==void 0)g.deleteObjectsTransition={condition:{type:"Date",date:u.expireOn}};if(u.abortMultipartUploadsAfterDays!==void 0)g.abortMultipartUploadsTransition={condition:{type:"Age",maxAge:du(u.abortMultipartUploadsAfterDays)}};if(u.infrequentAccessAfterDays!==void 0)g.storageClassTransitions=[{storageClass:"InfrequentAccess",condition:{type:"Age",maxAge:du(u.infrequentAccessAfterDays)}}];return g}function du(u){return Math.round(u*86400)}function kh(u){let g=new Set,h=[];for(let S of u??[]){let A=typeof S==="string"?{domain:S}:S,T=A.domain?.trim().replace(/\.$/,"").toLowerCase();if(!T||g.has(T))continue;g.add(T),h.push({domain:T,minTLS:A.minTLS})}return h}function ed(u){if(!u.enabled)return"disabled";let g=u.status?.ownership,h=u.status?.ssl;if(g==="active"&&h==="active")return"active";for(let S of[g,h])if(S==="error"||S==="blocked"||S==="deactivated")return S;return"pending"}async function xi(u,g,h,S){try{await h()}catch(A){if(A instanceof Sn)throw A;u.warnings.push(`R2: ${g} failed: ${td(A)}`),S?.()}}function td(u){return u instanceof Error?u.message:String(u)}function Fs(u){if(Array.isArray(u))return`[${u.map(Fs).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[S])=>h.localeCompare(S)).map(([h,S])=>`${JSON.stringify(h)}:${Fs(S)}`).join(",")}}`;return JSON.stringify(u)}import{basename as Wh,extname as Vh}from"node:path";import{createHash as Oh}from"node:crypto";var Nh="https://api.cloudflare.com/client/v4",Fn="TS_CLOUD_CONTENT_HASH",oo="2025-09-01",nd="application/javascript+module",xh=10007,Fh=[1e4,9109];class di extends Error{status;errors;constructor(u,g,h=[]){super(u);this.name="WorkersApiError",this.status=g,this.errors=h}hasCode(u){return this.errors.some((g)=>g.code===u)}}class Vs extends di{permission;constructor(u,g,h,S=[]){super(`The Cloudflare API token is missing the "${u}" permission (${g}). Edit the token in the Cloudflare dashboard (My Profile, API Tokens), add it, then re-run the deploy.`,h,S);this.name="WorkersPermissionError",this.permission=u}}class Us{name="cloudflare-workers";apiToken;accountId;fetchImpl;constructor(u){if(!u.apiToken)throw Error("Cloudflare Workers needs an API token");if(!u.accountId)throw Error("Cloudflare Workers needs an account id");this.apiToken=u.apiToken,this.accountId=u.accountId,this.fetchImpl=u.fetch??((g,h)=>fetch(g,h))}async request(u,g,h){let S={Authorization:`Bearer ${this.apiToken}`},A;if(h instanceof FormData)A=h;else if(h!==void 0)S["Content-Type"]="application/json",A=JSON.stringify(h);let T=await this.fetchImpl(`${Nh}/accounts/${this.accountId}/workers${g}`,{method:u,headers:S,body:A}),P=await T.text(),M;try{M=JSON.parse(P)}catch{throw new di(`Cloudflare Workers API returned ${T.status} with a non-JSON body: ${P.slice(0,200)}`,T.status)}if(!M.success){let W=M.errors??[],le=W.map((K)=>`${K.code}: ${K.message}`).join(", ");if(Mh(T.status,W))throw new Vs(Bh(g),`${u} ${g} -> ${T.status}${le?`, ${le}`:""}`,T.status,W);throw new di(`Cloudflare Workers API error (${T.status}) on ${u} ${g}: ${le||P.slice(0,200)}`,T.status,W)}return M.result}scriptPath(u){return`/scripts/${encodeURIComponent(u)}`}async getSettings(u){try{return await this.request("GET",`${this.scriptPath(u)}/settings`)}catch(g){if(g instanceof Vs)throw g;if(g instanceof di&&(g.hasCode(xh)||g.status===404))return null;throw g}}async getScript(u){return this.getSettings(u)}async uploadModuleScript(u,g){return this.request("PUT",this.scriptPath(u),up(g))}async ensureModuleScript(u,g){let h=lo(g),S=await this.getSettings(u);if(S&&js(S,g,h))return{action:"unchanged",hash:h};return await this.uploadModuleScript(u,dp(g,h)),{action:S?"updated":"created",hash:h}}async listCustomDomains(u={}){let g=new URLSearchParams;if(u.service)g.set("service",u.service);if(u.hostname)g.set("hostname",u.hostname);if(u.zoneId)g.set("zone_id",u.zoneId);let h=g.toString(),S=h?`?${h}`:"";return await this.request("GET",`/domains${S}`)??[]}async attachCustomDomain(u,g){let h={hostname:u,service:g.service,environment:g.environment??"production"};if(g.zoneId)h.zone_id=g.zoneId;return this.request("PUT","/domains",h)}async detachCustomDomain(u){await this.request("DELETE",`/domains/${encodeURIComponent(u)}`)}async ensureCustomDomain(u,g,h){let A=(h??await this.listCustomDomains({hostname:u})).find((P)=>P.hostname.toLowerCase()===u.toLowerCase());if(A&&A.service===g.service)return{action:"unchanged",domain:A};if(A)throw Error(`${u} is attached to the Worker '${A.service}'. Detach it there first (Workers & Pages, ${A.service}, Settings, Domains & Routes); ts-cloud does not move it.`);let T=await this.attachCustomDomain(u,g);return{action:"attached",domain:{...T,hostname:T?.hostname||u}}}}function Mh(u,g){if(g.some((h)=>Fh.includes(h.code)))return!0;return(u===401||u===403)&&g.length===0}function Bh(u){if(u.startsWith("/domains"))return"Workers Routes: Edit (zone, for Workers custom domains) and Workers Scripts: Edit (account)";return"Workers Scripts: Edit (account)"}function up(u){if(!u.modules.some((S)=>S.name===u.mainModule))throw Error(`Worker main module '${u.mainModule}' is not one of the uploaded modules`);let g={main_module:u.mainModule,bindings:u.bindings??[],compatibility_date:u.compatibilityDate??oo,compatibility_flags:u.compatibilityFlags??[],keep_bindings:["secret_text"]},h=new FormData;h.append("metadata",JSON.stringify(g));for(let S of u.modules)h.append(S.name,new Blob([S.content],{type:S.type}),S.name);return h}function lo(u){let g={mainModule:u.mainModule,modules:[...u.modules].sort((h,S)=>h.name.localeCompare(S.name)).map((h)=>({name:h.name,type:h.type,sha256:lp(h.content)})),bindings:[...u.bindings??[]].filter((h)=>h.name!==Fn).sort((h,S)=>h.name.localeCompare(S.name)),compatibilityDate:u.compatibilityDate??oo,compatibilityFlags:[...u.compatibilityFlags??[]].sort()};return lp(rd(g))}function dp(u,g=lo(u)){return{...u,bindings:[...(u.bindings??[]).filter((h)=>h.name!==Fn),{type:"plain_text",name:Fn,text:g}]}}function js(u,g,h){let S=u.bindings??[],A=S.find((T)=>T.name===Fn&&T.type==="plain_text");if(!A||A.text!==h)return!1;return(g.bindings??[]).every((T)=>{let P=S.find((W)=>W.name===T.name);if(!P||P.type!==T.type)return!1;let M=T.type==="r2_bucket"?"bucket_name":T.type==="plain_text"?"text":void 0;return!M||P[M]===T[M]})}function lp(u){return Oh("sha256").update(u).digest("hex")}function rd(u){if(Array.isArray(u))return`[${u.map(rd).join(",")}]`;if(u&&typeof u==="object")return`{${Object.entries(u).filter(([,h])=>h!==void 0).sort(([h],[S])=>h.localeCompare(S)).map(([h,S])=>`${JSON.stringify(h)}:${rd(S)}`).join(",")}}`;return JSON.stringify(u)}async function id(u){if(!await Bun.file(u).exists())throw Error(`Worker entry not found: ${u}`);let g;try{g=await Bun.build({entrypoints:[u],target:"browser",format:"esm",minify:!0,external:["cloudflare:*"]})}catch(A){throw Error(`Bundling Worker ${u} failed: ${zh(A)}`)}if(!g.success)throw Error(`Bundling Worker ${u} failed: ${g.logs.map((A)=>String(A.message??A)).join("; ")}`);if(g.outputs.length!==1)throw Error(`Bundling Worker ${u} produced ${g.outputs.length} files (${g.outputs.map((A)=>A.path).join(", ")}); a Worker is uploaded as a single module, so remove the dynamic imports or asset imports that split it.`);let h=g.outputs[0];if(h.kind!=="entry-point")throw Error(`Bundling Worker ${u} produced a ${h.kind} instead of an entry module`);let S=await h.text();return{name:`${Wh(u,Vh(u))}.js`,content:S,type:nd,size:new TextEncoder().encode(S).byteLength}}function zh(u){if(u instanceof AggregateError&&u.errors.length>0)return u.errors.map((g)=>g instanceof Error?g.message:String(g?.message??g)).join("; ");return u instanceof Error?u.message:String(u)}import{isAbsolute as Hh,resolve as Uh}from"node:path";var Gh="https://api.cloudflare.com/client/v4",jh=/^[a-z0-9][a-z0-9_-]{0,62}$/;async function Kh(u,g={}){let h=g.log??(()=>{}),S={workers:[],warnings:[]},A=Object.entries(u.infrastructure?.workers??u.workers??{});if(A.length===0)return h("Workers: none declared, skipping."),S;if(!g.apiToken||!g.accountId){let M=[!g.apiToken&&"CLOUDFLARE_API_TOKEN",!g.accountId&&"CLOUDFLARE_ACCOUNT_ID"].filter(Boolean).join(" and "),W=`Workers: ${A.length} Worker(s) declared but ${M} is not set, skipping.`;return h(W),S.warnings.push(W),S}let T=u.infrastructure?.r2??u.r2,P={workers:new Us({apiToken:g.apiToken,accountId:g.accountId,fetch:g.fetch}),r2:new ui({apiToken:g.apiToken,accountId:g.accountId,fetch:g.fetch}),cloudflare:new G(g.apiToken,{zoneId:g.zoneId,accountId:g.accountId}),apiToken:g.apiToken,fetch:g.fetch??((M,W)=>fetch(M,W)),projectRoot:g.projectRoot??process.cwd(),dryRun:g.dryRun===!0,warnings:S.warnings,log:h,r2ConfigDomains:MS(T),r2Buckets:T,claimed:new Map};for(let[M,W]of A){let le=W?.name;if(!le||!jh.test(le)){S.warnings.push(`Workers: '${M}' has an invalid name '${le??""}' (1-63 chars: lowercase letters, digits, '-' and '_'), skipping.`);continue}if(!W.entry){S.warnings.push(`Workers: ${le} has no entry, skipping.`);continue}h(`Workers: ${P.dryRun?"checking":"reconciling"} ${le}...`);let K={name:le,changes:[],domains:[]};S.workers.push(K),await qh(W,K,P);for(let Ct of K.changes)h(`Workers: ${le}: ${Ct}`)}return S}async function qh(u,g,h){let S=u.name,A=Hh(u.entry)?u.entry:Uh(h.projectRoot,u.entry),T;try{T=await id(A)}catch(M){throw Error(`Worker ${S}: ${gi(M)}`)}g.changes.push(`bundled ${eR(T.size)}`);let P={mainModule:T.name,modules:[{name:T.name,content:T.content,type:T.type}],bindings:pp(u,h),compatibilityDate:u.compatibilityDate??oo,compatibilityFlags:u.compatibilityFlags??[]};if(h.dryRun){let M=await h.workers.getSettings(S);g.changes.push(M&&js(M,P,lo(P))?"unchanged":"would upload")}else{let{action:M}=await h.workers.ensureModuleScript(S,P);g.changes.push(M==="unchanged"?"unchanged":"uploaded")}for(let M of KS(u.customDomains))await Zh(S,M,g,h)}async function Zh(u,g,h,S){let A=(He)=>{h.domains.push({domain:g,status:He})},T=(He)=>{S.warnings.push(`Workers: ${He}`),A("conflict")},P=S.claimed.get(g);if(P&&P!==u){T(`${g} is declared on both ${P} and ${u}; leaving it on ${P}.`);return}S.claimed.set(g,u);let M=S.r2ConfigDomains.get(g);if(M){T(`${g} is also declared as a custom domain of the R2 bucket '${M}' (r2.buckets). A hostname serves either a bucket or a Worker. Remove it from the bucket's customDomains and detach it in the dashboard (R2, ${M}, Settings, Custom Domains) first; to serve the bucket through the Worker, bind it with bindings.r2Buckets instead.`);return}let W=await Yh(S);if(W===null){A("error");return}let le=W.find((He)=>He.hostname.toLowerCase()===g);if(le?.service===u){A("active");return}if(le){T(`${g} is attached to the Worker '${le.service}'. Detach it there first (Workers & Pages, ${le.service}, Settings, Domains & Routes); it is not moved automatically.`);return}let K=(await Xh(S))?.get(g);if(K){T(`${g} is attached to the R2 bucket '${K}' as a custom domain. Detach it first (R2, ${K}, Settings, Custom Domains, then re-run the deploy); it is not detached automatically. To serve the bucket through the Worker, bind it with bindings.r2Buckets.`);return}let Ct;try{Ct=await S.cloudflare.zoneIdFor(g)}catch(He){S.warnings.push(`Workers: could not resolve the zone for ${g}, not attached: ${gi(He)}`),A("error");return}let Tt=await Qh(S,Ct,g);if(Tt.length>0){let He=Tt.map((Se)=>`${Se.type} ${Se.content}`).join(", ");T(`${g} already has a DNS record (${He}). A Worker custom domain creates its own record, so Cloudflare will not attach over it. Delete the record first (DNS, Records), then re-run the deploy; it is not deleted automatically.`);return}if(S.dryRun){h.changes.push(`would attach custom domain ${g}`),A("not attached");return}try{await S.workers.ensureCustomDomain(g,{service:u,zoneId:Ct},W),h.changes.push(`custom domain ${g} attached`),W.push({id:"",hostname:g,service:u,zone_id:Ct}),A("pending")}catch(He){S.warnings.push(`Workers: custom domain ${g} on ${u} failed: ${gi(He)}`),A("error")}}async function Yh(u){if(u.attached!==void 0)return u.attached;try{u.attached=await u.workers.listCustomDomains()}catch(g){u.warnings.push(`Workers: could not list Worker custom domains, none attached: ${gi(g)}`),u.attached=null}return u.attached}async function Xh(u){if(u.r2AccountDomains!==void 0)return u.r2AccountDomains;let g=new Map;try{let h=(await u.r2.listBuckets()).map((S)=>({name:S.name}));for(let S of Object.values(u.r2Buckets?.buckets??{}))if(S.jurisdiction&&S.jurisdiction!=="default")h.push({name:S.name,jurisdiction:S.jurisdiction});for(let S of h){let A=await u.r2.listCustomDomains(S.name,{jurisdiction:S.jurisdiction}).catch(()=>[]);for(let T of A)g.set(T.domain.toLowerCase(),S.name)}u.r2AccountDomains=g}catch(h){u.log(`Workers: could not check R2 custom domains (${gi(h)}); relying on the DNS check.`),u.r2AccountDomains=null}return u.r2AccountDomains}async function Qh(u,g,h){try{let S=await u.fetch(`${Gh}/zones/${g}/dns_records?name=${encodeURIComponent(h)}&per_page=100`,{method:"GET",headers:{Authorization:`Bearer ${u.apiToken}`}}),A=await S.json();if(!A?.success)throw Error(`HTTP ${S.status}`);return(A.result??[]).filter((T)=>T.name?.toLowerCase()===h).map((T)=>({type:T.type??"?",content:T.content??""}))}catch(S){return u.log(`Workers: could not read DNS records for ${h} (${gi(S)}); attaching anyway.`),[]}}function pp(u,g){let h=[],S=new Set,A=(P)=>{if(P===Fn)return g.warnings.push(`Workers: ${u.name}: binding name ${Fn} is reserved for ts-cloud, ignored.`),!1;if(S.has(P))return g.warnings.push(`Workers: ${u.name}: binding ${P} is declared twice; the first one wins.`),!1;return S.add(P),!0},T=new Map;for(let P of Object.values(g.r2Buckets?.buckets??{}))if(P.jurisdiction&&P.jurisdiction!=="default")T.set(P.name,P.jurisdiction);for(let[P,M]of Object.entries(u.bindings?.r2Buckets??{})){if(!A(P))continue;let W=T.get(M);h.push(W?{type:"r2_bucket",name:P,bucket_name:M,jurisdiction:W}:{type:"r2_bucket",name:P,bucket_name:M})}for(let[P,M]of Object.entries(u.bindings?.vars??{}))if(A(P))h.push({type:"plain_text",name:P,text:String(M)});return h}function MS(u){let g=new Map;for(let h of Object.values(u?.buckets??{}))for(let S of h?.customDomains??[]){let A=mp(typeof S==="string"?S:S.domain);if(A)g.set(A,h.name)}return g}function KS(u){return[...new Set((u??[]).map(mp).filter(Boolean))]}function mp(u){return(u??"").trim().replace(/\.$/,"").toLowerCase()}function eR(u){if(u<1024)return`${u} B`;if(u<1048576)return`${(u/1024).toFixed(1)} KB`;return`${(u/1024/1024).toFixed(1)} MB`}function gi(u){return u instanceof Error?u.message:String(u)}export{Fl as ABTestManager,Ee as ACMClient,Or as ACMDnsValidator,bd as ACME_DIRECTORIES,Me as AI,Cu as API_IDEMPOTENCY_TTL_MS,Iu as API_TOKEN_DEFAULT_TTL_MS,bu as API_TOKEN_MAX_TTL_MS,bs as API_VERSION,Te as AUTHORIZATION_CAPABILITIES,hu as AUTH_ACTION_TOKEN_TTL_MS,Au as AUTH_MFA_CHALLENGE_TTL_MS,yu as AUTH_OIDC_TRANSACTION_TTL_MS,ct as AUTH_SESSION_ABSOLUTE_TTL_MS,fu as AUTH_SESSION_IDLE_TTL_MS,$y as AWSAPIError,n as AWSClient,y as AWSCloudFormationClient,b as AWSCloudFrontClient,_l as AWSConfigManager,lb as AWS_PSEUDO_PARAMETERS,Fe as AWS_REGIONS,hg as AcmeClient,on as AlertEvaluator,ji as AlertStore,Fo as AnomalyConfigStore,vl as ApiGateway,i as ApiServiceError,_c as ApplicationAutoScalingClient,pn as Arn,L as AssetHasher,ee as Auth,hs as AuthenticationStore,Xi as AutomationApiService,As as AutomationIdentityStore,Ga as AwsAuroraDataAdapter,Ka as AwsAuroraTransport,gc as AwsDatabaseBackupSource,Mr as AwsDriver,Va as AwsElastiCacheDataAdapter,Wa as AwsElastiCacheTransport,uh as AwsIamCapabilityScanner,Ac as AwsInfrastructureBackupSource,Ha as AwsRdsDataAdapter,za as AwsRdsTransport,vh as AwsRegionalDriver,Sc as AwsSecretsManagerConfigurationBackend,wm as AwsSpendTransport,Ic as AwsSsmConfigurationBackend,Bs as BackupCoordinator,xl as BackupManager,lc as BackupStore,Uf as BatchProcessingManager,qn as BedrockClient,Vn as BedrockRuntimeClient,Pu as BitbucketSourceAdapter,Ml as BlueGreenManager,kf as BounceComplaintHandler,bf as BuildOptimizationManager,Xu as BunDockerRuntime,Rg as BunDockerVolumeRuntime,wg as BunFilesystemArchiveRuntime,we as CDN,aa as CHAIN_HEADER,Wt as CLOUDFLARE_MANAGED_RULE_PREFIX,Sl as CLOUDFRONT_FAILOVER_STATUS_CODES,XC as COMMON_CROSS_ACCOUNT_ROLES,Fn as CONTENT_HASH_BINDING,Ze as CONTROL_PLANE_SCHEMA_VERSION,zm as CREDENTIAL_PROCESS_TIMEOUT_MS,Yo as Cache,cs as CanaryManager,yf as CertificateManager,jA as CloudBlockVolumeDriver,po as CloudDriverFactory,ot as CloudError,Gm as CloudFormationBuilder,y as CloudFormationClient,b as CloudFrontClient,Ll as CloudTrailManager,Ne as CloudWatchLogsClient,Ed as CloudflarePagesProvider,G as CloudflareProvider,iS as CommandHistory,re as Communication,en as ComposeApplicationService,ar as ComposeApplicationStore,Vt as ComprehendClient,a as Compute,Rm as ComputeSpendTransport,ia as ConfigurationError,Cc as ConfigurationService,yc as ConfigurationStore,Hn as ConnectClient,ja as ContainerDataAdapter,Vl as ContainerRegistryManager,hc as ControlPlaneBackupSource,oc as ControlPlaneCleanupDriver,Fi as ControlPlaneStore,Lo as CounterTracker,_t as CredentialError,k as CredentialProcessError,of as CrossRegionReferenceManager,by as DASHBOARD_ENTRY,Cy as DASHBOARD_PORT_BASE,Ey as DASHBOARD_PORT_SPAN,Iy as DASHBOARD_STATE_DIR,ha as DEFAULT_ATTACK_MODE_HOURS,oo as DEFAULT_COMPATIBILITY_DATE,cl as DEFAULT_DDOS_THRESHOLDS,Nm as DEFAULT_FAILOVER_STATUS_CODES,Gd as DEFAULT_METER_MAPPINGS,Qd as DEFAULT_PRICE_BOOK,An as DEFAULT_RECURSION_LIMITS,So as DEFAULT_RPX_CERTS_DIR,ne as DEFAULT_SERVICE_LIMITS,gl as DEFAULT_STATE_DIR,Ug as DEFAULT_STATIC_ASSET_EXTENSIONS,hy as DEFAULT_STORAGE_FAILOVER_STATUS_CODES,sy as DEFAULT_TELEMETRY_POLICY,lm as DEFAULT_THRESHOLDS,QA as DEPLOYMENT_QUEUE_KINDS,oa as DEPTH_HEADER,nn as DETECTABLE_SIGNALS,ju as DIAGNOSTIC_PRESETS,Ff as DLQMonitoringManager,X as DNS,Df as DNSSECManager,Ts as DataServiceLifecycle,Qa as DataServiceStore,gr as Database,hf as DatabaseUserManager,j as DebugLogger,fy as DependencyGraph,te as Deployment,Ly as DeploymentError,Ol as DisasterRecoveryManager,Zn as DnsProviderFactory,br as DockerDataTransport,_a as DockerDiscoveryAdapter,Zr as DockerNamedVolumeDriver,fc as DockerVolumeBackupSource,c as DurableOperationQueue,Po as DurableQueueWorker,Ve as DynamoDBClient,jr as EC2Client,je as ECRClient,pt as ECSClient,kr as EFSClient,Nc as ELBv2Client,KA as ENFORCEMENT_ACTIONS,Vi as ENFORCEMENT_DESCRIPTIONS,_ as ENFORCEMENT_SEVERITY,Mp as ENVIRONMENT_LABEL,Vu as EcsRuntimeAdapter,fa as EdgeRateLimiter,ft as ElastiCacheClient,f as Email,Of as EmailAdvanced,Nf as EmailAnalyticsManager,Wn as EmailClient,_f as EmailHandlers,xf as EmailTemplateManager,Ja as EncryptedDataSecretStore,My as ErrorCodes,Dr as EventBridgeClient,bh as EventBridgeJobAdapter,bc as ExternalConfigurationBackend,Xo as FAILOVER_REPLICA_POLICY_SID,Mf as FIFOQueueManager,tR as FLY_MACHINES_API,ym as FOCUS_VERSION,Rl as FileCache,it as FileSystem,pc as FilesystemBackupSource,Ya as FleetService,Xa as FleetStore,Io as FlyApiError,hp as FlyClient,e as Fn,ku as GiteaSourceAdapter,Ru as GithubSourceAdapter,Du as GitlabSourceAdapter,af as GlobalResourceManager,ze as GoDaddyProvider,$l as GuardDutyManager,wt as HOST_SITES_DIR,Hy as HashCache,Yf as HealthCheckManager,tt as HealthCheckRunner,Gr as HetznerClient,xe as HetznerDriver,Be as IAMClient,qc as IPV6_EXCLUDED_HOST_LABELS,If as ImageScanningManager,wp as InfrastructureGenerator,kd as InvalidOperationTransitionError,xt as JobLoader,Ch as JobProviderReconciler,Fa as JobService,Ua as JobStore,Rr as KendraClient,Jf as LARAVEL_SERVERLESS_BUILD_STEPS,w as LambdaClient,vf as LambdaConcurrencyManager,Rf as LambdaDLQManager,Tf as LambdaDestinationsManager,Cf as LambdaLayersManager,qu as LambdaRuntimeAdapter,wf as LambdaVPCManager,Ef as LambdaVersionsManager,Ln as LocalEncryptedConfigurationBackend,mc as LogicalDatabaseBackupSource,Ql as LogsManager,TS as MANAGED_NODE_VERSIONS,md as MANAGEMENT_DASHBOARD_SITE,Vm as MANAGEMENT_DASHBOARD_SITE_PREFIX,ms as MAX_CONTROL_HOURS,Nd as MAX_CONTROL_PLANE_ERROR_BYTES,sm as MAX_CONTROL_PLANE_JSON_BYTES,xo as METERS,zA as METER_KEYS,WA as MICRO_CENTS,um as MIN_PROJECTION_CONFIDENCE,qg as MTA_STS_PORT,sc as MaintenanceService,ic as MaintenanceStore,fe as Messaging,pf as MetricsManager,mf as MigrationManager,ef as MockCloudFormation,rf as MockDynamoDB,tf as MockS3,Zo as Monitoring,lf as MultiAccountManager,sf as MultiRegionManager,Yy as MultiStepProgress,I as Network,Zf as NetworkSecurityManager,zi as NotificationRouter,Om as ORIGIN_CONNECTION_ATTEMPTS,_m as ORIGIN_CONNECTION_TIMEOUT,Bm as ORIGIN_GROUP_ALLOWED_METHODS,ab as ORIGIN_GROUP_ID_SUFFIX,xm as ORIGIN_GROUP_SELECTION_CRITERIA,Bc as OpenSearchClient,Rt as OptimisticConcurrencyError,uf as OrganizationManager,Lg as PAGES_MAX_FILE_BYTES,_S as PHP_DEFAULT_EXCLUDES,wS as PHP_LAYER_EXTENSIONS,$p as PROJECT_LABEL,At as PROXIABLE_RECORD_TYPES,D as ParameterStore,ff as PerformanceManager,me as Permissions,xc as PersonalizeClient,st as Phone,Lf as PhoneAdvanced,Qm as PhoneHandlers,ec as PlacementService,Za as PlacementStore,jn as PollyClient,be as PorkbunProvider,Tn as PreDeployScanner,Nl as PreviewEnvironmentManager,Yr as PreviewEnvironmentService,et as PreviewEnvironmentStore,Bl as PreviewNotificationService,Xy as ProgressBar,Ul as ProgressiveDeploymentManager,Aa as ProtectionControlStore,my as Pseudo,Y as Queue,Ui as QueueCancellationError,Qf as QueueManagementManager,JI as QueuePresets,Do as QueueTimeoutError,_n as R2ApiError,Sn as R2NotEnabledError,ui as R2Provider,ip as R2_NOT_ENABLED_ERROR_CODE,ou as RATE_LIMIT_KEY_SEPARATOR,se as RDSClient,oS as RECOMMENDED_ACCOUNT_STRUCTURES,JC as RECOMMENDED_SCPS,ah as RELEASE_QUEUE_KINDS,tS as REPL,nS as REPLCommandBuilder,rS as REPLContext,Fp as ROLE_LABEL,Gy as RateLimiter,XI as RealtimePresets,Sm as RecordingSpendTransport,ls as RecursionGuard,Ot as Redirects,cf as RegionPairManager,rc as RegionService,tc as RegionStore,nt as Registry,qt as RekognitionClient,Lt as ReleaseService,wa as ReleaseStore,Eh as RemoteBuildService,Hl as ReplicaManager,eh as ResourceManagementManager,ue as RetryableOperationError,E as Route53Client,kc as Route53DomainsClient,oe as Route53Provider,Pf as Route53ResolverManager,jl as Route53RoutingManager,Pe as RuntimeOperationService,$a as RuntimeStreamRegistry,uc as S3BackupDestinationAdapter,o as S3Client,q as S3Error,xu as SECRET_PATTERNS,hm as SENSITIVITY_THRESHOLDS,ht as SESClient,Z as SMS,mt as SNSClient,Tm as SPEND_CYCLE_SECONDS,rl as SPEND_GATE_SETTING,dy as SPEND_LEASE_SETTING,ye as SQSClient,Oe as SSH_BOOTSTRAP_VERSION,yi as SSH_PREFLIGHT_SCRIPT,Le as SSMClient,Pm as STATE_DIR_ENV_VAR,Ei as STATIC_SITE_ZONE_SETTINGS,bl as STORAGE_FAILOVER_METADATA_KEY,ke as STSClient,zn as SchedulerClient,pr as Search,wn as SecretFindingScanner,ts as Secrets,Gl as SecretsManager,ie as SecretsManagerClient,Af as SecretsRotationManager,v as Security,hr as SecurityHubManager,vn as SecurityPostureStore,$t as SecurityScannerRunner,Sf as SecurityScanningManager,Bf as SenderReputationManager,Ih as ServerCronJobAdapter,qa as ServerDataAdapter,Bo as ServerPathVolumeDriver,ql as ServiceMeshManager,El as Sftp,Qo as SignalSource,$f as SmsAdvanced,zt as SmsClient,Hm as SmsHandlers,Mc as SmsVoiceClient,Ra as SourceConnectionStore,Sr as SourceProviderError,nl as SpendCapError,sn as SpendGate,Em as SpendLoopLease,jo as SpendNotificationRouter,vm as SpendRunner,dr as SpendService,Hi as SpendStore,Zy as Spinner,Vr as SshDriver,Pn as SshFleetDriver,df as StackDependencyManager,db as StacksIntegration,Xf as StaticSiteManager,$e as Storage,nu as StorageAdvancedManager,Kn as SupportClient,Ar as SyntheticsManager,Yu as SystemFleetSshTransport,Et as SystemSshTransport,La as SystemdDiscoveryAdapter,ca as TRACE_HEADER,eS as TaskList,kt as TelemetryStore,Al as TemplateBuilder,Dl as TemplateCache,jt as TextractClient,Gn as TranscribeClient,wr as TranslateClient,Rh as TransportDisasterRecoveryDriver,wh as TransportPlatformMaintenanceDriver,ws as TransportRemoteBuildDriver,xa as TrivyImageScanner,Ta as TsCloudApiError,Eu as TsCloudClient,cy as URGENT_SPEND_EVENTS,gm as USER_VISIBLE_ACTIONS,nc as UnavailableRegionalDriver,Ce as UnifiedDnsValidator,To as UnsupportedSchemaVersionError,Wm as ValidationError,Pr as VoiceClient,No as VolumeService,or as VolumeStore,nd as WORKER_MODULE_TYPE,di as WorkersApiError,Vs as WorkersPermissionError,Us as WorkersProvider,Sy as Workflow,gf as XRayManager,fS as abTestManager,vu as activateImmutableRelease,dg as addDns01ChallengeRecord,Nn as addSiteToCloudConfig,Ft as ageSeconds,qd as aggregateDeltas,rm as allocateSitePorts,Um as amazonLinuxImageId,yy as amazonLinuxImageParameter,sb as analyzeStackDiff,qi as anomalyOptionsForSignal,ya as applyControlsToDdos,uu as applyControlsToRateLimits,Xs as applyDeclaredZoneSettings,mi as applyHetznerVolumes,dn as applyMitigationFactor,CA as applyPlan,to as applyZoneMigration,zl as artifactKey,gu as assertComputeResidency,Nt as assertOriginGroupMethods,ys as assertReleaseStrategy,iy as assertSpendAllows,RA as attachConflicts,DA as attachIsViable,wA as attachPreconditions,Mu as attachProvenanceToRelease,Oa as attachSbomToRelease,Lu as attachVulnerabilitySummary,sh as authEncryptionKeyFile,O as authorizeOrganization,yh as authorizeRuntimePath,wC as autocomplete,dS as awsConfigManager,vg as backupCredentialStatus,aS as backupManager,Xb as batch,QE as batchProcessingManager,Ea as beginOidcAuthorization,pS as blueGreenManager,_E as bounceComplaintHandler,Dt as budgetWindow,Rc as buildAndPushServerlessImage,VE as buildBunRuntimeLayerZip,OA as buildCertificatePackScript,NA as buildCertificateStateScript,_A as buildCertificateUnpackScript,Tl as buildCloudFormationTemplate,cd as buildCloudInitFirstBoot,_d as buildComposeLogsCommand,KI as buildComposeRuntimeCommand,WI as buildComposeScaleCommand,Ld as buildComposeShellCommand,ni as buildComputeStorageInstallScript,Fr as buildComputeStorageSiteScript,Zp as buildDrainSourceScript,pA as buildDrainedSiteScanScript,Cl as buildFailoverReplicaPolicyStatement,Er as buildFunctionEnv,Yp as buildHealthGateScript,si as buildHostCleanupDeployScript,co as buildHostCleanupInstallScript,ii as buildHostCleanupScript,$i as buildHostSitePortsScript,Zi as buildMailEnv,ho as buildManagementDashboardArtifact,hR as buildMediaCdnPlan,Vg as buildMtaStsPolicy,Jh as buildMtaStsServer,GE as buildNodeRuntimeLayerZip,wE as buildOptimizationManager,Il as buildOriginGroup,gn as buildOriginGroups,Qc as buildOriginGuardRule,qp as buildPauseWorkersScript,KE as buildPhpRuntimeLayerZip,Fm as buildReplicationConfiguration,Mm as buildReplicationRole,Wp as buildRestoreScript,x as buildRpxConfig,_e as buildRpxFragmentRefreshScript,Op as buildRpxUpgradeScript,vA as buildSetHostnameScript,ai as buildSiteDeployScript,Kp as buildSnapshotScript,em as buildSourceStateScript,li as buildSshArgs,hi as buildSshBootstrapScript,Uc as buildStaticSiteCacheRules,ci as buildStaticSiteDeployScript,Jp as buildTargetStateScript,up as buildUploadForm,jp as buildWorkersStateScript,id as bundleWorker,Uu as bytes,sp as cacheRuleParameters,mS as canaryManager,kn as canonicalJson,Mt as capabilities,Cr as capacity,oC as categorizeChanges,EE as certificateManager,xA as certificatesMatch,Qb as checkIAMPermissions,jf as checkInvocation,Gb as checkServiceQuotas,Vy as chunk,NR as cleanupDns01Challenge,Lb as clearCredentialProcessCache,VS as clearSigningKeyCache,Pa as cloneSourceBinding,qy as cloudConfigSchema,Ap as cloudDrivers,lS as cloudTrailManager,tp as collectAssets,ga as collectPhpAppEntries,Qg as collectServerDnsDomains,om as completeComposeVolumeDeletion,va as completeOidcAuthorization,Db as composePresets,Ro as composeProjectName,Wl as composeServerlessAppTemplate,uy as compositeSpendTransport,Gt as compressBackup,WS as config,Fc as configOrigins,Wu as connectionGuidance,bS as containerRegistryManager,FA as controlPlaneDatabaseFile,Dd as controlPlaneMigrations,hb as createApiBackendPreset,Ba as createApiV1Handler,iI as createAsgBuildDriver,Tg as createBackupQueueHandlers,OS as createCliHandler,U as createCloudDriver,pd as createCloudFrontPolicy,$b as createCredentialProvider,wb as createDashboardSite,bb as createDataPipelinePreset,Ju as createDataServiceQueueHandlers,$d as createDeploymentQueueHandlers,B as createDnsProvider,nI as createEcsBuildDriver,il as createEnforcementHandlers,Jm as createError,wl as createExistingStaticFullStackPreset,Zu as createFleetQueueHandlers,fb as createFullStackAppPreset,io as createGoDaddyValidator,zE as createHandlers,BS as createHttpHandler,yb as createJamstackPreset,Ku as createJobQueueHandlers,vb as createLaravelPreset,Cb as createMLApiPreset,og as createMaintenanceQueueHandlers,mR as createMediaAccessToken,Sb as createMicroservicesPreset,mC as createMockAWS,gb as createNodeJsServerPreset,pb as createNodeJsServerlessPreset,Gs as createObjectStorageClient,no as createPorkbunValidator,Pb as createPreset,pa as createPresignedUrl,FS as createPresignedUrlAsync,xS as createQueueHandler,Ib as createRealtimeAppPreset,tg as createRegionQueueHandlers,$u as createReleaseProvenance,wu as createReleaseQueueHandlers,tI as createRemoteBuildQueueHandlers,so as createRoute53Validator,Ah as createRuntimeAdapters,_y as createS3Client,rI as createServerBuildDriver,Tb as createServerlessLaravelPreset,mb as createServerlessNodePreset,Fg as createSmsInfrastructure,lt as createSourceAdapter,ub as createStaticSitePreset,Eb as createTraditionalWebAppPreset,Md as createVolumeQueueHandlers,Ab as createWordPressPreset,at as createZip,OC as crossRegionReferenceManager,$n as dashboardActions,fo as dashboardCredentialsFile,Dn as dataServiceCapabilities,bE as databaseUserManager,mu as decodeBase32,Ge as decompressBackup,$h as decryptBackup,Sa as defaultConfig,Zm as defaultLocalConfig,cu as defaultRateLimitRules,xr as delegateZone,Ws as delegateZoneFromConfig,Ig as deleteFailoverReplicaBuckets,Tc as deleteStaticSite,hd as deployAllComputeSites,cc as deployServerlessApp,bg as deploySite,Ao as deploySiteRelease,Ls as deployStaticSite,wc as deployStaticSiteFull,Mn as deployStaticSiteWithExternalDns,Un as deployStaticSiteWithExternalDnsFull,oR as deployToFly,hl as deploymentCoexistenceError,vy as deriveManagementDashboardPort,Js as describeDelegation,lu as describePosture,Ys as describeZoneSettings,Sh as desiredJobProviderState,fm as detectAnomalies,km as detectDeploymentTargets,Hc as detectDnsProvider,Zd as detectLatestAnomaly,Fb as detectMisconfigurations,iu as detectServiceRegion,xd as diffCompose,nC as diffTemplates,Da as discoverGitRefs,Ca as discoverOidcProvider,Qu as discoverRuntimeInventory,UE as dlqMonitoringManager,Gc as dnsProviders,xE as dnssecManager,mh as dockerWorkloads,Rs as documentDigest,ed as domainStatus,cS as drManager,Je as driverStatePath,Hu as ecsWorkloads,sr as effectiveCapabilities,LE as emailAnalyticsManager,ME as emailTemplateManager,fs as encodeBase32,Lh as encryptBackup,Fu as ensureDefaultSecurityPolicies,Ag as ensureFailoverReplicaBuckets,Ti as ensureFirewall,Pi as ensureManagementDashboard,wi as ensureServer,vi as ensureSshKey,de as escapeSecLang,zd as evaluateBudget,Ii as evaluatePreflight,qo as evaluateTelemetryAlertRules,zu as eventBridgeScheduleInput,NS as eventToRequest,ty as ewma,Bd as exportCompose,Zs as exportRoute53Zone,jm as extendPreset,FE as fifoQueueManager,Jb as findChangedFiles,cm as findMapping,am as findPriceEntry,iR as flyDeployOptions,sd as flyIpType,Cp as flyMachineConfig,tE as formatAccountStructure,PA as formatAttachPlan,yC as formatBytes,an as formatCents,ob as formatDiff,fA as formatDrainedSiteRefusal,SC as formatDuration,DC as formatFlagSuggestions,NC as formatHistory,BC as formatHistoryStats,SA as formatInventory,bC as formatKeyValue,IC as formatList,bA as formatPlan,Ci as formatPreflightFindings,AC as formatProgressBar,sS as formatRegion,jC as formatRegionList,lh as formatScanResults,CC as formatSuggestion,fC as formatTable,rn as formatTimeToExhaustion,hC as formatTree,ky as fromCredentialProcess,Ny as fromEC2Metadata,By as fromECSMetadata,Dy as fromEnvironment,Py as fromSharedCredentials,xy as fromWebIdentity,Yl as functionFingerprint,Co as gatewayHostnames,Xl as generateAppImageDockerfile,fE as generateApprovalConfig,Hf as generateBootstrap,Ky as generateCleanupWorkflow,Wy as generateCostReportWorkflow,ZC as generateCrossAccountRoleCF,Ou as generateCycloneDxSbom,gE as generateDeploymentConfig,aE as generateDeploymentPipeline,rE as generateDeploymentWorkflow,vc as generateExternalDnsStaticSiteTemplate,ER as generateHttpsServerCode,_u as generateImageSbom,vR as generateLetsEncryptUserData,t as generateLogicalId,uE as generateManualPipeline,oE as generateMatrixWorkflow,pE as generateMultiEnvConfig,cE as generateMultiEnvPipeline,nE as generateMultiEnvWorkflow,iE as generatePRPreviewWorkflow,hE as generateParallelConfig,Wf as generatePhpFpmConfig,Gf as generatePhpLayerDockerfile,dE as generatePreviewPipeline,zy as generatePreviewWorkflow,r as generateResourceName,mE as generateScheduledConfig,lE as generateScheduledPipeline,sE as generateScheduledWorkflow,_s as generateStaticSiteTemplate,F as generateUbuntuAppCloudInit,Km as getAccountId,MC as getAllRegions,GC as getClosestRegion,PC as getCommandUsage,UA as getComposeTemplate,rh as getConfig,vC as getContextualHelp,os as getCredentials,aC as getDeploymentStrategy,cC as getDiffStats,iC as getDiffSummary,Fy as getErrorDetails,kl as getLocalConfig,gC as getLocalCredentials,uC as getLocalEndpoint,pC as getLocalEnvVars,Vb as getQuotaUsageSummary,YC as getRecommendedStructure,as as getRegion,zC as getRegionStats,UC as getRegionsByCompliance,FC as getRegionsByLocation,QC as getRegionsByPricingTier,Uy as getRequiredPermissions,qS as getSigningKeyCacheSize,Mg as getSmsInfrastructureStatus,YI as getTimestamp,ma as globMatches,yo as globToRegex,_C as globalResourceManager,Gi as governingLimitCents,yg as grantFailoverReplicaAccess,uS as guardDutyManager,zo as handleSpendRequest,bo as hasAutoWwwVariant,mr as hasManagementDashboardSite,Rd as hasProxyUpstream,jb as hashBuffer,zb as hashDirectory,Xm as hashFile,Kb as hashManifest,Ym as hashString,JE as healthCheckManager,ei as hostAcceptsIpv6,Kt as hostCondition,Ia as hotp,tn as hourBucket,ey as hourBucketsBetween,TE as imageScanningManager,ks as infraEnvFromOutputs,eu as inspectInvocation,PS as installRecursionFetch,Ms as invalidateCache,qf as invocationContext,Ay as isArmInstanceType,EC as isLikelyTypo,Lr as isLocalDatabase,lC as isLocalDevelopment,fr as isManagementDashboardSiteName,Nr as isNameserverRegistrar,jS as isNodeCryptoAvailable,Yd as isOperationAllowed,Vo as isQuietHours,Jo as isS3RestEndpoint,Ni as isSafePattern,ml as isStateDirConfigured,fl as isStatePath,cn as isValidCidr,HC as isValidRegion,Qi as isValidTimeZone,zS as isWebCryptoAvailable,Br as isZoneHost,Rn as jobProviderCapability,Hs as keyMatchesFilters,PE as lambdaConcurrencyManager,BE as lambdaDLQManager,kE as lambdaDestinationsManager,RE as lambdaLayersManager,NE as lambdaVPCManager,DE as lambdaVersionsManager,Gu as lambdaWorkloads,tu as laravelServerlessEnvDefaults,Xr as listComposeTemplates,Is as listSourceReferences,pu as loadCloudConfig,ss as loadProfileCredentials,ra as loadProfileCredentialsSync,is as loadStaticProfileCredentials,lr as loadTelemetryPolicy,AS as logsManager,el as lookbackHoursForSignal,py as mailEnabled,rt as mailFirewallPorts,un as mailWebmailSites,Th as maintenanceWindowOpen,th as makeAWSRequest,QS as makeAWSRequestAsync,US as makeAWSRequestOnce,ap as managedRuleInSync,qm as managementDashboardSiteName,rg as manifestDigest,In as matchTotpCounter,fR as mediaObjectHeaders,Mo as median,pm as medianAbsoluteDeviation,Kd as mergeDecisions,mn as mergeInfrastructure,YA as mergePriceBooks,Vd as meterTelemetry,yE as metricsManager,xg as migrateObjectStorage,SE as migrationManager,KC as multiAccountManager,xC as multiRegionManager,xR as needsRenewal,XE as networkSecurityManager,Ut as nextScheduleRuns,ae as normalizePublicIpv6,Ue as normalizeRuntimeStatus,ut as normalizeScheduleExpression,ch as normalizeSourceEvent,We as normalizeSshPublicKey,Im as normalizeTelemetryPolicy,Li as occupiedHostPorts,Na as openApiDocument,Ho as optionsForSignal,WC as organizationManager,ru as packagePhpApp,hn as packageServerlessApp,ep as pagesAssetHash,Bg as pagesDnsRecord,Pl as parallel,Yb as parallelMap,Zb as parallelWithRetry,BA as parseCertificateState,Zl as parseChain,Jr as parseCompose,jI as parseComposeCatalog,ph as parseDockerInspect,Dg as parseDotenv,mA as parseDrainedSites,Mi as parseHostSiteFragments,GS as parseJSONResponse,Si as parsePreflightFacts,tm as parseSourceDrained,fh as parseSystemdRecords,Xp as parseTargetReady,wd as parseUpstreamPort,zp as parseWorkersPaused,HS as parseXMLResponse,Wi as pathTemplate,vd as pendingSteps,$o as percentOfLimit,IE as performanceManager,Jl as phpLayerBuildStage,RS as phpLayerPackages,yn as phpRuntimeLayerAssets,zI as planComposeTemplateUpgrade,Wd as planEnforcement,pi as planHetznerVolumes,Gp as planIsDestructive,Dm as planMitigation,EA as planServerRename,LA as planSiteMove,eo as planZoneMigration,Xt as policyTag,bi as preflightFailed,jy as previewManager,Jy as previewNotifications,Qt as previewSchedule,ZA as previousBudgetWindow,Oo as priceUsage,JA as priceUsageLines,AA as probeHostRoutes,Xc as probeOriginTls,rC as processInChunks,Nu as processSourceWebhook,Es as productionChangeReview,ta as profileCredentialProcess,hS as progressiveDeploymentManager,jd as projectSpend,da as propagationHeaders,Dc as providerEndpoint,ng as publicKeyFingerprint,Xn as qualifyName,HE as queueManagementManager,Wb as quickHash,op as r2Endpoint,Zg as r2S3Credentials,au as rateLimitHeaders,ps as rateLimitKey,Xe as readDriverState,fn as readSharedProfile,yA as reconcile,Gg as reconcileAddressRecords,Eg as reconcileCloudflareCdn,Kh as reconcileCloudflareWorkers,Ks as reconcileDeclaredRecords,eI as reconcileJobObservation,Xg as reconcileR2Buckets,En as reconcileSourceWebhook,Cs as recordDashboardHostPosture,XS as recordPreDeploySecretScan,YS as recordSkippedSecretScan,la as recursionBlockedResponse,Qe as redactRuntimeConfig,al as redactTelemetryText,Ki as redactTelemetryValue,xn as redeployServerlessApp,LC as regionPairManager,Cn as releaseStrategyCapabilities,oh as releaseTrafficPlan,ki as reloadRpxGateway,Qs as remapKey,Hg as removeAddressRecords,mg as removeDns01ChallengeRecord,Bn as removeSiteFromCloudConfig,Bu as removeSourceWebhook,Vc as removeStaleServerAddressRecords,Od as renderComposeTemplate,Yi as renderDdosInstallScript,ul as renderNftablesRuleset,vs as renderServerCron,ll as renderSysctlFile,yd as renderWafConfig,Bi as renderWafInstallScript,Ad as renewRpxCertificates,SS as replicaManager,gy as requestHash,sC as requiresReplacement,qE as resetRecursionRuntime,jE as resolveApp,p as resolveAppDatabase,TA as resolveAttachTarget,dt as resolveAuthEncryptionKey,ge as resolveCloudProvider,Ng as resolveCloudflareCdnPlan,ri as resolveComputeVolumes,na as resolveCredentials,Os as resolveDashboardAction,fd as resolveDashboardAuth,Ty as resolveDashboardDomain,wy as resolveDashboardDomains,zs as resolveDeclaredRecords,ib as resolveDeployBucketName,J as resolveDeploymentMode,oi as resolveExecStart,Wo as resolveFailoverStatusCodes,Zc as resolveHetznerApiToken,Qr as resolveHostCleanupConfig,R as resolveMailProxy,C as resolveMailService,Rb as resolveManagementDashboardSite,rs as resolveManagementDashboardSites,Pc as resolveObjectStorage,pe as resolveOriginConnection,IA as resolvePlan,Re as resolveProfileName,m as resolveProjectStackName,Wr as resolveProxyUpstreams,Kl as resolveQueueNames,HA as resolveQueuedDeploymentCommand,yr as resolveQueues,DS as resolveRecursionConfig,Oy as resolveRegion,Ae as resolveRuntimeInventory,ur as resolveServerlessAppStackName,yl as resolveServerlessArtifactBucketName,es as resolveServerlessAssetBucketName,ds as resolveServerlessRuntime,rb as resolveSiteBucketName,vo as resolveSiteDeployTarget,d as resolveSiteKind,tb as resolveSiteResourceName,eb as resolveSiteStackName,Ai as resolveSshSettings,l as resolveStatePath,nb as resolveStorageBucketName,Lm as resolveStorageFailover,rr as resolveUiSource,Id as resolveZoneApex,YE as resourceManagementManager,Kf as responseToResult,mm as robustZScore,ir as roleCapabilities,Tu as rollbackImmutableRelease,On as rollbackServerlessApp,XA as roundCents,OE as route53ResolverManager,ES as route53RoutingManager,Am as routeMatches,Up as routesFromFragments,gs as ruleMatches,vS as runBuildHooks,Jd as runEnforcement,ua as runPhpBuildHooks,gt as runRemoteCommand,De as runtimeId,qe as s3OriginBucket,$m as s3RegionalDomain,Ps as sameCorsRules,Ns as sameLifecycleRules,Yn as sameNameservers,xs as sanitizeCloudConfig,s as sanitizeControlPlaneValue,ZI as sanitizeName,Su as sanitizeOidcReturnPath,sl as saveTelemetryPolicy,dh as scanForSecrets,Pd as scopeContains,Pt as scopeKey,Wc as scpUpload,TC as searchCommands,wo as searchControlPlane,IS as secretsManager,CE as secretsRotationManager,ZS as secureContainerRelease,gS as securityHubManager,vE as securityScanningManager,he as securityScope,Sg as seedFailoverReplicas,bn as sendAuthenticationEmail,$E as senderReputationManager,eC as sequence,Pg as serializeDotenv,Ri as serverPublicIpv4,CS as serviceMeshManager,pg as setAttachToInCloudConfig,vr as setMaintenance,Ds as setSitePropertyInCloudConfig,pl as setStateDir,OR as setupDns01Challenge,$c as setupSmsInfrastructure,sa as sha256,ea as sharedConfigPath,ns as sharedCredentialsPath,kS as sharedRecursionGuard,Vf as sharedRuntimeLoop,im as shipsARelease,pR as signCloudFrontCookies,dR as signCloudFrontUrl,N as signRequest,su as signRequestAsync,Uo as signalDefinition,Q as siteInstallBase,_i as siteMoveArchivePath,kA as siteMoveCertArchivePath,Td as siteUnitGlob,Cm as spendNotificationText,Ko as spendOpenApiPaths,Ry as splitCommandLine,Hr as sshExec,ve as sshExecOrThrow,$C as stackDependencyManager,Ec as startLocalDashboardServer,ly as startSpendLoop,ln as stateDir,H as statePath,WE as staticSiteManager,LS as storageAdvancedManager,cb as storageFailoverReplicasFromTemplate,ry as streamFocusJsonl,Xd as strongestActiveAction,nf as suggestCommand,RC as suggestFlags,Hb as suggestIAMPolicy,qb as suggestQuotaIncrease,qC as suggestRegionPairs,VC as suggestRegions,Ss as syncSourceRepositories,Fd as synchronizeComposeVolumes,kg as synchronizeConfiguredConfiguration,Ma as synchronizeConfiguredJobs,yS as syntheticsManager,dl as sysctlHardening,hh as systemdWorkloads,ay as telemetryBucketLabel,Ji as telemetryCursor,ol as telemetryEstimatedMonthlyCost,oy as telemetryPercentile,bm as telemetryPolicyKey,Qy as templateCache,Qp as tenantsOf,ka as testSourceConnection,Ud as tieredMicroCents,cp as toApiLifecycleRule,Yc as toCloudflareZoneSettings,Go as toFocusJsonl,tl as toFocusRecords,hA as toInventoryServer,nh as totp,ba as totpUri,Hp as unaccountedSites,gh as unsupportedCapabilities,GA as unsupportedVolumeCapabilities,sg as updateCompatibility,ag as updateSiteInCloudConfig,$s as uploadStaticFiles,dm as usageDeltaKey,cr as utcInstantOfLocal,eE as validateAccountStructure,dC as validateAgainstSchema,qA as validateAttachment,_h as validateBackupDestination,kC as validateCommand,Mb as validateConfiguration,Ub as validateCredentials,nm as validateDeploymentConfig,VA as validateMountPath,Bt as validateOriginGroups,Lp as validateResourceLimits,Vp as validateServerName,Ip as validateTemplate,xp as validateTemplateSize,jc as verifyAddressRecord,JS as verifyArtifactSignature,gR as verifyMediaAccessToken,ih as verifyTotp,ig as verifyUpdateSignature,ro as verifyZoneParity,ko as volumeCapabilities,Np as wafEventTelemetry,Jc as waitForCloudInit,St as waitForSsh,Ir as webhookEndpoint,Ob as withCDN,xb as withCache,dp as withContentHash,Bb as withDatabase,zf as withInvocation,kb as withMonitoring,_b as withQueue,Nb as withSecurity,tC as withTimeout,pp as workerBindings,lo as workerContentHash,js as workerInSync,ce as wrapCloudInitUserData,bt as writeDriverState,AE as xrayManager,eg as zeroCapacity,ny as zeroFill,Hd as zoneOffsetMs,_o as zonedParts};