@stacksjs/ts-cloud 0.9.4 → 0.11.0

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 (252) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/chunk-0djsffn6.js +1 -0
  3. package/dist/bin/chunk-0t3sev1j.js +1 -0
  4. package/dist/bin/chunk-0y89hs67.js +6 -0
  5. package/dist/bin/chunk-21gggxvf.js +2 -0
  6. package/dist/bin/chunk-26cj89s6.js +1 -0
  7. package/dist/bin/chunk-35xstvnq.js +1 -0
  8. package/dist/bin/chunk-41yqpdv7.js +2 -0
  9. package/dist/bin/chunk-4a85nk2q.js +92 -0
  10. package/dist/bin/{chunk-rxcvf10f.js → chunk-4a97kbk1.js} +129 -129
  11. package/dist/bin/chunk-4kbhbfq8.js +34 -0
  12. package/dist/bin/chunk-4vdv41nh.js +70 -0
  13. package/dist/bin/chunk-67jsyn0g.js +111 -0
  14. package/dist/bin/chunk-6tct7e89.js +1 -0
  15. package/dist/bin/chunk-6vjrts39.js +1 -0
  16. package/dist/bin/chunk-7v5ff3vc.js +1 -0
  17. package/dist/bin/chunk-80nra92y.js +1 -0
  18. package/dist/bin/chunk-9mydnqr6.js +2 -0
  19. package/dist/bin/chunk-9rsn48qg.js +3 -0
  20. package/dist/bin/chunk-a2t1e5yb.js +1 -0
  21. package/dist/bin/chunk-akbfefwq.js +1 -0
  22. package/dist/bin/chunk-b704nznp.js +1 -0
  23. package/dist/bin/chunk-c1j9v7ee.js +2 -0
  24. package/dist/bin/chunk-cjz36ths.js +1 -0
  25. package/dist/bin/chunk-cxd5cevb.js +2 -0
  26. package/dist/bin/chunk-dbv8w56s.js +50 -0
  27. package/dist/bin/chunk-dxchg0g1.js +1 -0
  28. package/dist/bin/{chunk-tx0tqq2k.js → chunk-e1bfd1yv.js} +6 -6
  29. package/dist/bin/chunk-fpcghdr3.js +585 -0
  30. package/dist/bin/chunk-ftse39wf.js +9 -0
  31. package/dist/bin/chunk-g0ewbkbq.js +1 -0
  32. package/dist/bin/chunk-gskbezam.js +141 -0
  33. package/dist/bin/chunk-gvs85t2j.js +1 -0
  34. package/dist/bin/chunk-hej39dwr.js +2 -0
  35. package/dist/bin/chunk-jce28gnz.js +2 -0
  36. package/dist/bin/chunk-kbtrr0c3.js +1 -0
  37. package/dist/bin/chunk-khrye4x9.js +1 -0
  38. package/dist/bin/{chunk-mh0kdzqp.js → chunk-ks4ewy1s.js} +1 -1
  39. package/dist/bin/chunk-mbnwt3r5.js +2 -0
  40. package/dist/bin/chunk-md2k3n21.js +37 -0
  41. package/dist/bin/chunk-memfxrcn.js +1 -0
  42. package/dist/bin/chunk-mwgxyc0z.js +44 -0
  43. package/dist/bin/chunk-neampxq1.js +4 -0
  44. package/dist/bin/chunk-nkpf91d3.js +1 -0
  45. package/dist/bin/chunk-nmkm1f68.js +2 -0
  46. package/dist/bin/chunk-nyc2jxd8.js +2 -0
  47. package/dist/bin/chunk-pqr8jqnd.js +1 -0
  48. package/dist/bin/chunk-q182t9ba.js +3 -0
  49. package/dist/bin/chunk-r6x7beew.js +60 -0
  50. package/dist/bin/chunk-rfqk5xym.js +1 -0
  51. package/dist/bin/{chunk-etrb03mt.js → chunk-ww770qpn.js} +30 -30
  52. package/dist/bin/chunk-wy20ztb6.js +1 -0
  53. package/dist/bin/chunk-wzepfqf4.js +512 -0
  54. package/dist/bin/chunk-xcqmwphz.js +1 -0
  55. package/dist/bin/chunk-xev7qr2h.js +3 -0
  56. package/dist/bin/chunk-y3rm37z1.js +6 -0
  57. package/dist/bin/chunk-zejwh9cy.js +6 -0
  58. package/dist/bin/chunk-zwwnt4x1.js +1 -0
  59. package/dist/bin/cli.js +431 -418
  60. package/dist/bin/dashboard-server.js +1 -1
  61. package/dist/{chunk-dskvqt67.js → chunk-0hj552t7.js} +127 -127
  62. package/dist/chunk-1ypkh8g6.js +5 -0
  63. package/dist/chunk-2m09t0c0.js +60 -0
  64. package/dist/chunk-7fkyfh65.js +1 -0
  65. package/dist/chunk-7xpxzbkr.js +442 -0
  66. package/dist/chunk-8e0az001.js +2 -0
  67. package/dist/chunk-b10cbk8z.js +44 -0
  68. package/dist/chunk-gk58959n.js +6 -0
  69. package/dist/chunk-h1rc94df.js +114 -0
  70. package/dist/chunk-hbhxk5a0.js +4 -0
  71. package/dist/chunk-hz7k9ymh.js +1 -0
  72. package/dist/chunk-kj7gzdj6.js +1 -0
  73. package/dist/chunk-ky5c6t5y.js +2 -0
  74. package/dist/chunk-mch30cyc.js +1 -0
  75. package/dist/chunk-n04a3bgf.js +1 -0
  76. package/dist/chunk-nnqxmh7f.js +34 -0
  77. package/dist/chunk-p6vszgc2.js +92 -0
  78. package/dist/chunk-q2njk4hx.js +141 -0
  79. package/dist/chunk-qjk1v1gs.js +50 -0
  80. package/dist/chunk-qtp90j44.js +2 -0
  81. package/dist/chunk-r5natbed.js +37 -0
  82. package/dist/chunk-rcxq9aaa.js +704 -0
  83. package/dist/{chunk-gahsdmxf.js → chunk-s3rpd72x.js} +52 -52
  84. package/dist/{chunk-xt3s24vr.js → chunk-spx89gaw.js} +1 -1
  85. package/dist/chunk-t0kh8haz.js +2 -0
  86. package/dist/chunk-vz95qy3n.js +1 -0
  87. package/dist/deploy/attach-credentials.d.ts +4 -8
  88. package/dist/deploy/index.js +1 -1
  89. package/dist/dns/cloudflare.d.ts +27 -0
  90. package/dist/dns/godaddy.d.ts +18 -1
  91. package/dist/dns/index.d.ts +2 -0
  92. package/dist/dns/index.js +1 -1
  93. package/dist/dns/zone-migration.d.ts +92 -0
  94. package/dist/dns/zone-migration.test.d.ts +1 -0
  95. package/dist/drivers/hetzner/driver.d.ts +8 -1
  96. package/dist/drivers/index.js +1 -1
  97. package/dist/drivers/shared/app-updates.d.ts +36 -0
  98. package/dist/drivers/shared/compute-provision.d.ts +14 -2
  99. package/dist/drivers/shared/db-provision.d.ts +3 -2
  100. package/dist/drivers/shared/mail-provision.d.ts +116 -0
  101. package/dist/drivers/shared/mail-provision.test.d.ts +1 -0
  102. package/dist/drivers/shared/managed-services-probe.d.ts +47 -0
  103. package/dist/drivers/shared/managed-services-probe.test.d.ts +1 -0
  104. package/dist/drivers/shared/package-manager.d.ts +1 -0
  105. package/dist/drivers/shared/remote-failure.d.ts +21 -0
  106. package/dist/drivers/shared/remote-failure.test.d.ts +1 -0
  107. package/dist/drivers/shared/sqlite-shared-path.d.ts +50 -0
  108. package/dist/drivers/shared/sqlite-shared-path.test.d.ts +1 -0
  109. package/dist/index.d.ts +2 -0
  110. package/dist/index.js +92 -89
  111. package/dist/operations/plan.d.ts +136 -0
  112. package/dist/operations/plan.test.d.ts +1 -0
  113. package/dist/operations/server-rename.d.ts +84 -0
  114. package/dist/operations/server-rename.test.d.ts +1 -0
  115. package/dist/operations/site-move.d.ts +263 -0
  116. package/dist/operations/site-move.test.d.ts +1 -0
  117. package/dist/protection/index.js +1 -1
  118. package/dist/push/index.js +1 -1
  119. package/dist/spend/index.js +1 -1
  120. package/dist/ui/404.html +1 -1
  121. package/dist/ui/accept-invitation.html +1 -1
  122. package/dist/ui/access-denied.html +1 -1
  123. package/dist/ui/account/automation.html +6 -6
  124. package/dist/ui/account/security.html +2 -2
  125. package/dist/ui/applications/compose.html +6 -6
  126. package/dist/ui/applications/new.html +2 -2
  127. package/dist/ui/data/backups.html +80 -80
  128. package/dist/ui/data/services.html +78 -78
  129. package/dist/ui/data/volumes.html +50 -50
  130. package/dist/ui/index.html +50 -50
  131. package/dist/ui/infrastructure/topology.html +118 -118
  132. package/dist/ui/integrations.html +2 -2
  133. package/dist/ui/operations/alerts.html +48 -48
  134. package/dist/ui/operations/configuration.html +6 -6
  135. package/dist/ui/operations/jobs.html +75 -75
  136. package/dist/ui/operations/maintenance.html +6 -6
  137. package/dist/ui/operations/observability.html +82 -82
  138. package/dist/ui/operations/previews.html +6 -6
  139. package/dist/ui/operations/queue.html +6 -6
  140. package/dist/ui/operations/regions.html +6 -6
  141. package/dist/ui/operations/releases.html +6 -6
  142. package/dist/ui/operations/spend.html +54 -54
  143. package/dist/ui/operations/workloads.html +104 -104
  144. package/dist/ui/security.html +2 -2
  145. package/dist/ui/server/actions.html +56 -56
  146. package/dist/ui/server/activity.html +1 -1
  147. package/dist/ui/server/capacity.html +6 -6
  148. package/dist/ui/server/database.html +106 -106
  149. package/dist/ui/server/deployments.html +50 -50
  150. package/dist/ui/server/diagnostics.html +2 -2
  151. package/dist/ui/server/firewall.html +76 -76
  152. package/dist/ui/server/fleet.html +34 -34
  153. package/dist/ui/server/logs.html +24 -24
  154. package/dist/ui/server/metrics.html +112 -112
  155. package/dist/ui/server/security.html +2 -2
  156. package/dist/ui/server/services.html +27 -27
  157. package/dist/ui/server/sites.html +120 -120
  158. package/dist/ui/server/ssh-keys.html +52 -52
  159. package/dist/ui/server/team.html +144 -144
  160. package/dist/ui/server/terminal.html +15 -15
  161. package/dist/ui/serverless/alarms.html +52 -52
  162. package/dist/ui/serverless/assets.html +27 -27
  163. package/dist/ui/serverless/cost.html +2 -2
  164. package/dist/ui/serverless/data.html +36 -36
  165. package/dist/ui/serverless/deployments.html +27 -27
  166. package/dist/ui/serverless/firewall.html +1 -1
  167. package/dist/ui/serverless/functions.html +40 -40
  168. package/dist/ui/serverless/logs.html +24 -24
  169. package/dist/ui/serverless/metrics.html +2 -2
  170. package/dist/ui/serverless/queues.html +48 -48
  171. package/dist/ui/serverless/secrets.html +51 -51
  172. package/dist/ui/serverless/traces.html +6 -6
  173. package/dist/ui/serverless.html +53 -53
  174. package/dist/ui-src/src/charts.ts +17499 -12662
  175. package/dist/ui-src/src/topology.ts +2 -2
  176. package/package.json +3 -3
  177. package/dist/bin/chunk-00kg80qg.js +0 -1
  178. package/dist/bin/chunk-09nwf2gy.js +0 -34
  179. package/dist/bin/chunk-1k5kszjp.js +0 -111
  180. package/dist/bin/chunk-21e0mavm.js +0 -1
  181. package/dist/bin/chunk-271gk1n2.js +0 -6
  182. package/dist/bin/chunk-2empps47.js +0 -2
  183. package/dist/bin/chunk-38pq971s.js +0 -2
  184. package/dist/bin/chunk-3gykfyq4.js +0 -37
  185. package/dist/bin/chunk-3vqfexc4.js +0 -70
  186. package/dist/bin/chunk-4vrqm9h0.js +0 -2
  187. package/dist/bin/chunk-598yf4bs.js +0 -1
  188. package/dist/bin/chunk-5ectjq0b.js +0 -1
  189. package/dist/bin/chunk-5erkxpt7.js +0 -512
  190. package/dist/bin/chunk-5mrtzemj.js +0 -1
  191. package/dist/bin/chunk-5n9fmabb.js +0 -1
  192. package/dist/bin/chunk-9knpg30y.js +0 -1
  193. package/dist/bin/chunk-9pvsff8g.js +0 -1
  194. package/dist/bin/chunk-ax9mr6wm.js +0 -44
  195. package/dist/bin/chunk-axhnkn5g.js +0 -2
  196. package/dist/bin/chunk-c1vcdgvr.js +0 -1
  197. package/dist/bin/chunk-ctd2vg9w.js +0 -2
  198. package/dist/bin/chunk-dbgffky8.js +0 -1
  199. package/dist/bin/chunk-ddk4rt4j.js +0 -6
  200. package/dist/bin/chunk-dwr30vbv.js +0 -1
  201. package/dist/bin/chunk-e0rkrq70.js +0 -1
  202. package/dist/bin/chunk-e3xrwh9z.js +0 -1
  203. package/dist/bin/chunk-fhc6ntvd.js +0 -2
  204. package/dist/bin/chunk-fpm59y25.js +0 -6
  205. package/dist/bin/chunk-fvbxvq6b.js +0 -1
  206. package/dist/bin/chunk-fy8j3y8p.js +0 -92
  207. package/dist/bin/chunk-fz21b57w.js +0 -1
  208. package/dist/bin/chunk-gavvf0pg.js +0 -141
  209. package/dist/bin/chunk-ggn7ax8p.js +0 -4
  210. package/dist/bin/chunk-gpe2prkm.js +0 -1
  211. package/dist/bin/chunk-h5pa5men.js +0 -2
  212. package/dist/bin/chunk-hm08xdxf.js +0 -2
  213. package/dist/bin/chunk-hzgz13nf.js +0 -1
  214. package/dist/bin/chunk-j703btc5.js +0 -50
  215. package/dist/bin/chunk-k9t9wvms.js +0 -1
  216. package/dist/bin/chunk-m669wtgr.js +0 -1
  217. package/dist/bin/chunk-m7dgskt1.js +0 -1
  218. package/dist/bin/chunk-mr0atd2s.js +0 -2
  219. package/dist/bin/chunk-mz0wbbsj.js +0 -3
  220. package/dist/bin/chunk-ngcyftm2.js +0 -1
  221. package/dist/bin/chunk-p66ptpmr.js +0 -2
  222. package/dist/bin/chunk-qk9qgepa.js +0 -1
  223. package/dist/bin/chunk-rytk89az.js +0 -60
  224. package/dist/bin/chunk-tga3hhwk.js +0 -6
  225. package/dist/bin/chunk-vek8a0w6.js +0 -1
  226. package/dist/bin/chunk-vm3q5gf2.js +0 -3
  227. package/dist/bin/chunk-y7s5r8y6.js +0 -3
  228. package/dist/bin/chunk-yv9sth30.js +0 -1
  229. package/dist/bin/chunk-zmegvjp8.js +0 -581
  230. package/dist/chunk-0ccta6z6.js +0 -6
  231. package/dist/chunk-0k1cs6pp.js +0 -1
  232. package/dist/chunk-1egjn203.js +0 -704
  233. package/dist/chunk-2wx29qga.js +0 -5
  234. package/dist/chunk-5m5rqmv7.js +0 -1
  235. package/dist/chunk-8ea5022g.js +0 -114
  236. package/dist/chunk-8xqn3c0w.js +0 -2
  237. package/dist/chunk-b4esxhmw.js +0 -2
  238. package/dist/chunk-b8e5wzwn.js +0 -44
  239. package/dist/chunk-bggt4n6e.js +0 -2
  240. package/dist/chunk-cwkg37rs.js +0 -37
  241. package/dist/chunk-gnv3r2jg.js +0 -1
  242. package/dist/chunk-hg3c48cp.js +0 -34
  243. package/dist/chunk-m5azeva3.js +0 -2
  244. package/dist/chunk-r3qf56b3.js +0 -92
  245. package/dist/chunk-sdqa9ghv.js +0 -141
  246. package/dist/chunk-svrvvcm7.js +0 -1
  247. package/dist/chunk-v0p3hpc3.js +0 -60
  248. package/dist/chunk-wdzjbecg.js +0 -50
  249. package/dist/chunk-ww8k3g7j.js +0 -1
  250. package/dist/chunk-xmqfc62w.js +0 -1
  251. package/dist/chunk-xrebj679.js +0 -435
  252. package/dist/chunk-y21zk0pn.js +0 -4
package/dist/index.js CHANGED
@@ -1,14 +1,17 @@
1
- import{$ as NU,$a as VF,$b as VK,$c as hK,A as E5,Aa as vQ,Ab as vF,B as V5,Ba as cQ,Bb as cF,Bc as F8,C as G5,Ca as uQ,Cb as uF,Cc as K8,D as O5,Da as dQ,Db as dF,Dc as H8,E as e5,Ea as tQ,Eb as tF,Ec as E8,F as $U,Fa as rQ,Fb as rF,Fc as V8,G as MU,Ga as lQ,Gb as lF,Gc as G8,H as JU,Ha as gQ,Hb as gF,Hc as O8,I as XU,Ia as aQ,Ib as aF,J as YU,Ja as iQ,Jb as iF,K as WU,Ka as oQ,Kb as oF,L as UU,La as sQ,Lb as sF,M as _U,Ma as nQ,Mb as nF,N as QU,Na as eQ,Nb as eF,O as FU,Oa as $F,Ob as $K,P as KU,Pa as MF,Pb as MK,Pc as NK,Q as HU,Qa as JF,Qb as JK,Qc as jK,R as EU,Ra as XF,Rb as XK,Rc as SK,S as VU,Sa as YF,Sb as YK,Sc as PK,T as GU,Ta as WF,Tb as WK,Tc as wK,U as OU,Ua as UF,Ub as UK,Uc as TK,V as xU,Va as _F,Vb as _K,Vc as BK,W as AU,Wa as QF,Wb as QK,Wc as DK,X as ZU,Xa as FF,Xb as FK,Xc as kK,Y as RU,Ya as KF,Yb as KK,Yc as LK,Z as zU,Za as HF,Zb as HK,Zc as yK,_ as qU,_a as EF,_b as EK,_c as bK,a as SW,aa as jU,ab as GF,ac as GK,ad as CK,b as PW,ba as SU,bb as OF,bc as OK,bd as IK,c as wW,ca as xQ,cb as xF,cc as xK,cd as fK,d as TW,da as AQ,db as AF,dc as AK,dd as pK,e as BW,ea as ZQ,eb as ZF,ec as ZK,ed as mK,f as DW,fa as RQ,fb as RF,fc as RK,fd as vK,g as kW,ga as zQ,gb as zF,gc as zK,gd as cK,h as LW,ha as qQ,hb as qF,hc as qK,hd as uK,i as yW,ia as NQ,ib as NF,id as dK,j as bW,ja as jQ,jb as jF,jd as tK,k as hW,ka as SQ,kb as SF,kd as rK,l as CW,la as PQ,lb as PF,ld as lK,m as IW,ma as wQ,mb as wF,md as gK,n as fW,na as TQ,nb as TF,nd as aK,o as pW,oa as BQ,ob as BF,od as x8,p as mW,pa as DQ,pb as DF,pc as _8,pd as A8,q as vW,qa as kQ,qb as kF,qd as Z8,r as cW,ra as LQ,rb as LF,rd as R8,s as uW,sa as yQ,sb as yF,t as dW,ta as bQ,tb as bF,u as tW,ua as hQ,ub as hF,v as rW,va as CQ,vb as CF,w as lW,wa as IQ,wb as IF,x as gW,xa as fQ,xb as fF,y as K5,ya as pQ,yb as pF,z as H5,za as mQ,zb as mF}from"./chunk-1egjn203.js";import{Ad as U8,sd as n3,td as e3,ud as $8,vd as M8,wd as J8,xd as X8,yd as Y8,zd as W8}from"./chunk-v0p3hpc3.js";import{Id as Q8}from"./chunk-2wx29qga.js";import{$d as z6,Be as D6,Fe as k6,Jd as C$,Ld as I$,Le as L6,Md as f$,Nd as p$,Od as m$,Oe as y6,Pd as v$,Pe as b6,Qd as c$,Qe as h6,Re as C6,Sd as d$,Td as K6,Ud as E6,Vd as V6,Wd as G6,We as I6,Xd as O6,Yd as x6,Zd as A6,_d as Z6,ae as q6,be as N6,ce as j6,de as S6,ef as f6,if as p6,ke as P6,nf as m6,pe as w6,te as T6,xe as B6}from"./chunk-8ea5022g.js";import{of as A$,pf as R$,qf as z$}from"./chunk-hg3c48cp.js";import{sf as h0}from"./chunk-sdqa9ghv.js";import{tf as F6}from"./chunk-bggt4n6e.js";import{uf as R6}from"./chunk-m5azeva3.js";import{Af as i$,Bf as o$,Cf as s$,Df as n$,Ef as e$,Ff as $6,Gf as M6,Hf as J6,If as X6,Jf as a,Kf as Y6,Lf as W6,Mf as U6,Nf as _6,Of as Q6,vf as t$,wf as r$,xf as l$,yf as g$,zf as a$}from"./chunk-8xqn3c0w.js";import{Pf as g}from"./chunk-wdzjbecg.js";import{Ag as U3,Ah as L3,Bh as y3,Cg as _3,Ch as b3,Dg as Q3,Dh as h3,Eg as F3,Fg as K3,Fh as C3,Gg as H3,Gh as I3,Hh as f3,Ih as p3,Jg as E3,Kg as V3,Lg as G3,Pg as O3,Qf as v6,Qg as x3,Rf as c6,Rg as A3,Sf as u6,Sg as Z3,Tf as d6,Tg as R3,Uf as K0,Ug as z3,Vf as t6,Wf as r6,dg as l6,eg as g6,fg as a6,gg as i6,gh as q3,hh as N3,ig as o6,ih as j3,jg as s6,jh as S3,ng as n6,og as H0,rh as P3,sh as w3,th as T3,xh as B3,yh as D3,zg as W3,zh as k3}from"./chunk-xrebj679.js";import{Nh as u$,Oh as H6}from"./chunk-y21zk0pn.js";import{Ph as b0}from"./chunk-b4esxhmw.js";import{Rh as Z$}from"./chunk-r3qf56b3.js";import{Th as x$}from"./chunk-0ccta6z6.js";import{$h as eW,$i as LU,$j as L_,Ai as y5,Aj as Y_,Ak as w$,Bi as b5,Bj as W_,Bk as e_,Ci as h5,Cj as U_,Ck as $Q,Di as C5,Dj as __,Dk as MQ,Ei as I5,Ej as Q_,Ek as JQ,Fi as f5,Fj as F_,Fk as XQ,Gi as p5,Gj as K_,Gk as YQ,Hi as m5,Hj as H_,Hk as WQ,Ii as v5,Ij as E_,Ik as UQ,Ji as c5,Jj as V_,Jk as _Q,Ki as u5,Kj as G_,Kk as QQ,Li as d5,Lj as O_,Lk as FQ,Mi as t5,Mj as x_,Mk as KQ,Ni as r5,Nj as A_,Nk as HQ,Oi as l5,Oj as Z_,Ok as EQ,Pi as g5,Pj as R_,Pk as VQ,Qi as a5,Qj as z_,Qk as GQ,Ri as i5,Rj as q_,Rk as OQ,Si as o5,Sj as N_,Ti as s5,Tj as j_,Ui as n5,Uj as S_,Vi as PU,Vj as P_,Wh as aW,Wi as wU,Wj as w_,Xh as iW,Xi as TU,Xj as T_,Yh as oW,Yi as BU,Yj as B_,Zh as sW,Zi as DU,Zj as D_,_h as nW,_i as kU,_j as k_,ai as $5,aj as yU,ak as y_,bi as M5,bj as bU,bk as b_,ci as J5,cj as hU,ck as h_,di as X5,dj as CU,dk as C_,ei as Y5,ej as IU,ek as I_,fi as W5,fj as fU,fk as f_,gi as U5,gj as pU,gk as p_,hi as _5,hj as mU,hk as m_,ii as Q5,ij as vU,ik as q$,ji as F5,jj as cU,jk as N$,ki as x5,kj as uU,kk as j$,li as A5,lj as dU,lk as S$,mi as Z5,mj as tU,mk as P$,ni as R5,nj as rU,nk as v_,oi as z5,oj as lU,ok as c_,pi as q5,pj as gU,pk as u_,qi as N5,qj as aU,qk as d_,ri as j5,rj as iU,rk as t_,si as S5,sj as oU,sk as r_,ti as P5,tj as sU,tk as l_,ui as w5,uj as nU,uk as g_,vi as T5,vj as eU,vk as a_,wi as B5,wj as $_,wk as i_,xi as D5,xj as M_,xk as o_,yi as k5,yj as J_,yk as s_,zi as L5,zj as X_,zk as n_}from"./chunk-gahsdmxf.js";import{$k as g3,Sk as m3,Tk as v3,Uk as c3,Vk as u3,Wk as d3,Xk as t3,Yk as r3,_k as l3,al as a3,bl as i3,cl as o3,dl as s3}from"./chunk-gnv3r2jg.js";import{fl as e6,gl as $3,hl as M3,il as J3,jl as X3,kl as Y3}from"./chunk-cwkg37rs.js";import{ll as T$,ml as B$,nl as D$,ol as k$,pl as L$,ql as y$,rl as b$,sl as h$}from"./chunk-b8e5wzwn.js";import{$l as b4,$m as A1,$n as A9,$o as AJ,$p as AX,$q as AY,$r as A2,$s as _W,Al as F4,Am as e4,An as t1,Ao as t9,Ap as tJ,Aq as tX,Ar as tY,As as t2,Bl as K4,Bm as N0,Bn as r1,Bo as r9,Bp as rJ,Bq as rX,Br as rY,Bs as U$,Cl as H4,Cm as C,Cn as l1,Co as l9,Cp as lJ,Cq as lX,Cr as lY,Cs as _$,Dl as E4,Dm as r,Dn as g1,Do as g9,Dp as gJ,Dq as gX,Dr as gY,Ds as Q$,El as V4,Em as M0,En as a1,Eo as a9,Ep as aJ,Eq as aX,Er as aY,Es as F$,Fl as G4,Fm as j0,Fn as i1,Fo as i9,Fp as iJ,Fq as iX,Fr as iY,Fs as K$,Gl as O4,Gm as S0,Gn as o1,Go as o9,Gp as oJ,Gq as oX,Gr as oY,Gs as H$,Hl as x4,Hm as $1,Hn as s1,Ho as s9,Hp as sJ,Hq as sX,Hr as sY,Hs as E$,Il as A4,Im as M1,In as n1,Io as n9,Ip as nJ,Iq as nX,Ir as nY,Is as V$,Jl as Z4,Jm as P0,Jn as e1,Jo as e9,Jp as eJ,Jq as eX,Jr as eY,Js as G$,Kl as R4,Km as J1,Kn as $9,Ko as $J,Kp as $X,Kq as $Y,Kr as $2,Ks as O$,Ll as z4,Lm as X1,Ln as M9,Lo as MJ,Lp as MX,Lq as MY,Lr as M2,Ls as r2,Ml as q4,Mm as Y1,Mn as J9,Mo as JJ,Mp as JX,Mq as JY,Mr as J2,Ms as l2,Nl as N4,Nm as W1,Nn as X9,No as XJ,Np as XX,Nq as XY,Nr as X2,Ns as g2,Ol as j4,Om as U1,On as Y9,Oo as YJ,Op as YX,Oq as YY,Or as Y2,Os as a2,Pl as S4,Pm as w0,Pn as W9,Po as WJ,Pp as WX,Pq as WY,Pr as W2,Ps as i2,Ql as P4,Qm as l,Qn as U9,Qo as UJ,Qp as UX,Qq as UY,Qr as U2,Qs as o2,Rl as w4,Rm as _1,Rn as _9,Ro as _J,Rp as _X,Rq as _Y,Rr as _2,Rs as s2,Sl as T4,Sm as Q1,Sn as Q9,So as QJ,Sp as QX,Sq as QY,Sr as Q2,Ss as n2,Tl as B4,Tm as F1,Tn as F9,To as FJ,Tp as FX,Tq as FY,Tr as F2,Ts as e2,Ul as D4,Um as K1,Un as K9,Uo as KJ,Up as KX,Uq as KY,Ur as K2,Us as $W,Vl as Z0,Vm as H1,Vn as H9,Vo as HJ,Vp as HX,Vq as HY,Vr as H2,Vs as MW,Wl as k4,Wm as E1,Wn as E9,Wo as EJ,Wp as EX,Wq as EY,Wr as E2,Ws as JW,Xl as R0,Xm as V1,Xn as V9,Xo as VJ,Xp as VX,Xq as VY,Xr as V2,Xs as XW,Yl as z0,Ym as G1,Yn as G9,Yo as GJ,Yp as GX,Yq as GY,Yr as G2,Ys as YW,Zl as L4,Zm as O1,Zn as O9,Zo as OJ,Zp as OX,Zq as OY,Zr as O2,Zs as WW,_l as y4,_m as x1,_n as x9,_o as xJ,_p as xX,_q as xY,_r as x2,_s as UW,am as h4,an as Z1,ao as Z9,ap as ZJ,aq as ZX,ar as ZY,as as Z2,at as QW,bm as C4,bn as R1,bo as R9,bp as RJ,bq as RX,br as RY,bs as R2,bt as FW,cm as I4,cn as z1,co as z9,cp as zJ,cq as zX,cr as zY,cs as z2,ct as KW,dm as f4,dn as q1,do as q9,dp as qJ,dq as qX,dr as qY,ds as q2,dt as HW,em as p4,en as N1,eo as N9,ep as NJ,eq as NX,er as NY,es as N2,et as EW,fm as m4,fn as j1,fo as j9,fp as jJ,fq as jX,fr as jY,fs as j2,ft as VW,gm as v4,gn as S1,go as S9,gp as SJ,gq as SX,gr as SY,gs as S2,gt as GW,hm as c4,hn as P1,ho as P9,hp as PJ,hq as PX,hr as PY,hs as P2,ht as OW,im as u4,in as w1,io as w9,ip as wJ,iq as wX,ir as wY,is as w2,it as xW,jm as d4,jn as T1,jo as T9,jp as TJ,jq as TX,jr as TY,js as T2,jt as AW,km as t4,kn as B1,ko as B9,kp as BJ,kq as BX,kr as BY,ks as B2,kt as ZW,lm as n,ln as D1,lo as D9,lp as DJ,lq as DX,lr as DY,ls as D2,lt as RW,mm as r4,mn as k1,mo as k9,mp as kJ,mq as kX,mr as kY,ms as k2,mt as zW,nm as l4,nn as L1,no as L9,np as LJ,nq as LX,nr as LY,ns as L2,nt as qW,om as g4,on as y1,oo as y9,op as yJ,oq as yX,or as yY,os as y2,ot as NW,pm as e,pn as b1,po as b9,pp as bJ,pq as bX,pr as bY,ps as b2,pt as jW,qm as B,qn as h1,qo as h9,qp as hJ,qq as hX,qr as hY,qs as h2,rm as q0,rn as C1,ro as C9,rp as CJ,rq as CX,rr as CY,rs as C2,sm as t,sn as I1,so as I9,sp as IJ,sq as IX,sr as IY,ss as I2,tl as J4,tm as h,tn as f1,to as f9,tp as fJ,tq as fX,tr as fY,ts as f2,ul as X4,um as a4,un as p1,uo as p9,up as pJ,uq as pX,ur as pY,us as p2,vl as Y4,vm as i4,vn as m1,vo as m9,vp as mJ,vq as mX,vr as mY,vs as m2,wl as W4,wm as $0,wn as v1,wo as v9,wp as vJ,wq as vX,wr as vY,ws as v2,xl as U4,xm as o4,xn as c1,xo as c9,xp as cJ,xq as cX,xr as cY,xs as c2,yl as _4,ym as s4,yn as u1,yo as u9,yp as uJ,yq as uX,yr as uY,ys as u2,zl as Q4,zm as n4,zn as d1,zo as d9,zp as dJ,zq as dX,zr as dY,zs as d2}from"./chunk-dskvqt67.js";import{qt as a0}from"./chunk-xt3s24vr.js";import{createHmac as V0,createSign as f0,timingSafeEqual as p0}from"node:crypto";function m($){let M=$ instanceof Date?$.getTime():$;if(!Number.isFinite(M))throw TypeError("Media access timestamp must be finite");return Math.floor(M/1000)}function G0($){return Buffer.from($).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function m0($){return Buffer.from($).toString("base64url")}function O0($,M=!1){if(!$||/[\r\n]/.test($))throw TypeError("Media resource is invalid");let J=M?$.replaceAll("*","wildcard"):$,X=new URL(J);if(!["http:","https:"].includes(X.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!M&&$.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function x0($,M){let J=f0("RSA-SHA1");return J.update($),J.end(),G0(J.sign(M))}function A0($){O0($.resource,!0);let J={DateLessThan:{"AWS:EpochTime":m($.expiresAt)}};if($.activeAt!==void 0)J.DateGreaterThan={"AWS:EpochTime":m($.activeAt)};if($.ipAddress)J.IpAddress={"AWS:SourceIp":$.ipAddress};return JSON.stringify({Statement:[{Resource:$.resource,Condition:J}]})}function q8($,M,J){O0($);let X=m(M),W=$.includes("?")?"&":"?",F=A0({resource:$,expiresAt:M}),Q=x0(F,J.privateKey);return`${$}${W}Expires=${X}&Signature=${encodeURIComponent(Q)}&Key-Pair-Id=${encodeURIComponent(J.keyPairId)}`}function N8($,M){let J=A0($);return{"CloudFront-Key-Pair-Id":M.keyPairId,"CloudFront-Policy":G0(Buffer.from(J)),"CloudFront-Signature":x0(J,M.privateKey)}}function j8($){if(!$.resource||/[\r\n]/.test($.resource))throw TypeError("Media resource is invalid");let M=m0(Buffer.from(JSON.stringify({resource:$.resource,expiresAt:m($.expiresAt),...$.keyId?{keyId:$.keyId}:{},...$.audience?{audience:$.audience}:{}}))),J=V0("sha256",$.secret).update(M).digest("base64url");return`${M}.${J}`}function S8($,M){let[J,X,W]=$.split(".");if(!J||!X||W)return null;let F=V0("sha256",M.secret).update(J).digest(),Q;try{Q=Buffer.from(X,"base64url")}catch{return null}if(F.length!==Q.length||!p0(F,Q))return null;try{let _=JSON.parse(Buffer.from(J,"base64url").toString("utf8")),K=m(M.now??Date.now());if(!_.resource||!Number.isSafeInteger(_.expiresAt)||_.expiresAt<=K)return null;if(M.resource&&_.resource!==M.resource)return null;if(M.audience&&_.audience!==M.audience)return null;return _}catch{return null}}function P8($,M=!1){let J=new URL($,"https://media.invalid").pathname.toLowerCase(),X=/\.(?:m3u8|mpd|vtt|json)$/.test(J),W=/\.(?:key|license)$/.test(J)||J.includes("/keys/")||J.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":M&&(X||W)?"private, no-store":X?"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 w8($){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test($.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test($.region))throw TypeError("Media bucket region is invalid");let M=$.prefix?`/${$.prefix.replace(/^\/+|\/+$/g,"")}`:"",J=$.protected??!1,X="public, max-age=31536000, immutable",W=J?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${$.bucket}.s3.${$.region}.amazonaws.com`,originPath:M,domain:$.domain,trustedKeyGroupIds:[...new Set($.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:W,compress:!0,signed:J},{pathPattern:"*.mpd",cacheControl:W,compress:!0,signed:J},{pathPattern:"*.vtt",cacheControl:W,compress:!0,signed:J},{pathPattern:"*",cacheControl:X,compress:!1,signed:J}],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 v0{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;constructor($){this.config=$.config,this.environment=$.environment,this.builder=new Z0(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let M=this.config.environments[this.environment]?.infrastructure;if(!M)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...M,compute:{...this.config.infrastructure?.compute,...M.compute},storage:{...this.config.infrastructure?.storage,...M.storage},functions:{...this.config.infrastructure?.functions,...M.functions},servers:{...this.config.infrastructure?.servers,...M.servers},databases:{...this.config.infrastructure?.databases,...M.databases},cdn:{...this.config.infrastructure?.cdn,...M.cdn},sftp:M.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...M.queues},redirects:{...this.config.infrastructure?.redirects,...M.redirects},realtime:{...this.config.infrastructure?.realtime,...M.realtime},cache:{...this.config.infrastructure?.cache,...M.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...M.fileSystem},email:{...this.config.infrastructure?.email,...M.email},search:{...this.config.infrastructure?.search,...M.search},ai:{...this.config.infrastructure?.ai,...M.ai}}}}shouldDeploy($){if($.environments&&!$.environments.includes(this.environment))return!1;if($.requiresFeatures){let M=this.config.features||{};if(!$.requiresFeatures.every((X)=>M[X]===!0))return!1}if($.regions){let M=this.config.environments[this.environment]?.region||this.config.project.region;if(!$.regions.includes(M))return!1}if($.condition&&typeof $.condition==="function")return $.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let $=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,M=Number($||3008);return Number.isFinite(M)&&M>0?M: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($,M){return $==="public"||M.routeCompute===!0}storageBucketName($,M,J){return this.mergedConfig.infrastructure?.storage?.[J]?.bucket??`${$}-${M}-${J}`}fileSystemLogicalId($,M,J){return z0(R0({slug:`${$}-${J}`,environment:M,resourceType:"efs"}))}resolveSftpStorage($,M,J){let X=$.storage;if(X?.type==="efs"&&X.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[X.fileSystem])throw Error(`sftp: storage.fileSystem "${X.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(M,J,X.fileSystem)},posixProfile:X.posixProfile}}if(X?.type==="s3"&&X.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[X.storageBucket])throw Error(`sftp: storage.storageBucket "${X.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(M,J,X.storageBucket)}}return}resolveComputeCachePathPatterns($){if($&&$.length>0)return $;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior($,M){return{PathPattern:$,TargetOriginId:M,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($,M,J,X,W,F){let Q=this.serverEipLogicalIds.get("app"),_=this.serverEipLogicalIds.get("appInstance");if(!Q)return;let K=`EC2-${X}-${W}-api`,O=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",H=O==="us-east-1"?".compute-1.amazonaws.com":`.${O}.compute.amazonaws.com`,R={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:Q}]}]},H]]},z=this.resolveApiOriginPort();if($.push({Id:K,DomainName:R,CustomOriginConfig:{HTTPPort:z,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),J.push(Q),_)J.push(_);for(let q of F)M.push(this.createComputeCacheBehavior(q,K))}buildCaddyfile($){let M=$.filter(([,W])=>typeof W.domain==="string"&&W.domain&&typeof W.port==="number");if(M.length===0)return;let J=new Map;for(let[,W]of M){let F=J.get(W.domain)??[];F.push({port:W.port,path:W.path}),J.set(W.domain,F)}let X=[];for(let[W,F]of J){let _=[...F].sort((K,O)=>{let H=!K.path||K.path==="/",R=!O.path||O.path==="/";if(H&&!R)return 1;if(!H&&R)return-1;return(O.path?.length??0)-(K.path?.length??0)}).map((K)=>{let O=!K.path||K.path==="/",H=`reverse_proxy localhost:${K.port}`;return O?` handle {
2
- ${H}
3
- }`:` handle ${K.path} {
4
- ${H}
5
- }`});X.push(`${W} {
6
- ${_.join(`
1
+ import{$ as Fg,$a as EC,$b as ES,$c as jS,A as Df,Aa as tC,Ab as tS,B as Ef,Ba as rC,Bb as rS,Bc as hi,C as wf,Ca as nC,Cb as nS,Cc as yi,D as Of,Da as iC,Db as iS,Dc as Ci,E as fg,Ea as oC,Eb as oS,Ec as Si,F as gg,Fa as aC,Fb as aS,Fc as Ai,G as hg,Ga as sC,Gb as sS,Gc as bi,H as yg,Ha as cC,Hb as cS,Hc as Ri,I as Cg,Ia as lC,Ib as lS,J as Sg,Ja as dC,Jb as dS,K as Ag,Ka as uC,Kb as uS,L as bg,La as pC,Lb as pS,M as Rg,Ma as mC,Mb as mS,N as Tg,Na as fC,Nb as fS,O as $g,Oa as gC,Ob as gS,P as Pg,Pa as hC,Pb as hS,Pc as FS,Q as Ig,Qa as yC,Qb as yS,Qc as VS,R as Dg,Ra as CC,Rb as CS,Rc as _S,S as Eg,Sa as SC,Sb as SS,Sc as BS,T as wg,Ta as AC,Tb as AS,Tc as WS,U as Og,Ua as bC,Ub as bS,Uc as zS,V as vg,Va as RC,Vb as RS,Vc as HS,W as Ng,Wa as TC,Wb as TS,Wc as GS,X as kg,Xa as $C,Xb as $S,Xc as KS,Y as xg,Ya as PC,Yb as PS,Yc as US,Z as Lg,Za as IC,Zb as IS,Zc as ZS,_ as Mg,_a as DC,_b as DS,_c as qS,a as Vm,aa as Vg,ab as wC,ac as wS,ad as JS,b as _m,ba as _g,bb as OC,bc as OS,bd as YS,c as Bm,ca as vy,cb as vC,cc as vS,cd as QS,d as Wm,da as Ny,db as NC,dc as NS,dd as XS,e as zm,ea as ky,eb as kC,ec as kS,ed as eA,f as Hm,fa as xy,fb as xC,fc as xS,fd as tA,g as Gm,ga as Ly,gb as LC,gc as LS,gd as rA,h as Km,ha as My,hb as MC,hc as MS,hd as nA,i as Um,ia as Fy,ib as FC,id as iA,j as Zm,ja as Vy,jb as VC,jd as oA,k as qm,ka as _y,kb as _C,kd as aA,l as jm,la as By,lb as BC,ld as sA,m as Jm,ma as Wy,mb as WC,md as cA,n as Ym,na as zy,nb as zC,nd as lA,o as Qm,oa as Hy,ob as HC,od as Ti,p as Xm,pa as Gy,pb as GC,pc as fi,pd as $i,q as ef,qa as Ky,qb as KC,qd as Pi,r as tf,ra as Uy,rb as UC,rd as Ii,s as rf,sa as Zy,sb as ZC,t as nf,ta as qy,tb as qC,u as of,ua as jy,ub as jC,v as af,va as Jy,vb as JC,w as sf,wa as Yy,wb as YC,x as cf,xa as Qy,xb as QC,y as Pf,ya as Xy,yb as XC,z as If,za as eC,zb as eS}from"./chunk-rcxq9aaa.js";import{Ad as mi,sd as oi,td as ai,ud as si,vd as ci,wd as li,xd as di,yd as ui,zd as pi}from"./chunk-2m09t0c0.js";import{Id as gi}from"./chunk-1ypkh8g6.js";import{$d as Ir,Be as Lr,Fe as Mr,Jd as Ft,Ld as Vt,Le as Fr,Md as _t,Nd as Bt,Od as Wt,Oe as Vr,Pd as zt,Pe as _r,Qd as Ht,Qe as Br,Re as Wr,Sd as Kt,Td as hr,Ud as Cr,Vd as Sr,Wd as Ar,We as zr,Xd as br,Yd as Rr,Zd as Tr,_d as $r,ae as Dr,be as Er,ce as wr,de as Or,ef as Hr,if as Gr,ke as vr,nf as Kr,pe as Nr,te as kr,xe as xr}from"./chunk-h1rc94df.js";import{of as St,pf as bt,qf as Rt}from"./chunk-nnqxmh7f.js";import{sf as Me}from"./chunk-q2njk4hx.js";import{tf as gr}from"./chunk-ky5c6t5y.js";import{uf as Pr}from"./chunk-t0kh8haz.js";import{Af as Yt,Bf as Qt,Cf as Xt,Df as er,Ef as tr,Ff as rr,Gf as nr,Hf as ir,If as or,Jf as ar,Kf as sr,Lf as cr,Mf as lr,Nf as j,Of as dr,Pf as ur,Qf as pr,Rf as mr,Sf as fr,vf as Ut,wf as Zt,xf as qt,yf as jt,zf as Jt}from"./chunk-qtp90j44.js";import{Tf as q}from"./chunk-qjk1v1gs.js";import{Ch as Ln,Dh as Mn,Eg as pn,Eh as Fn,Fg as mn,Fh as Vn,Gh as _n,Hg as fn,Hh as Bn,Ig as gn,Ih as Wn,Jg as hn,Kg as yn,Kh as zn,Lg as Cn,Lh as Hn,Mh as Gn,Nh as Kn,Og as Sn,Pg as An,Qg as bn,Uf as Ur,Ug as Rn,Vf as Zr,Vg as Tn,Wf as qr,Wg as $n,Xf as jr,Xg as Pn,Yf as ue,Yg as In,Zf as Jr,Zg as Dn,_f as Yr,fg as Ee,ig as Qr,jg as Xr,kg as en,lg as tn,lh as En,mh as wn,ng as rn,nh as On,og as nn,oh as vn,sg as on,tg as pe,wh as Nn,xh as kn,yh as xn}from"./chunk-7xpxzbkr.js";import{Sh as Gt,Th as yr}from"./chunk-hbhxk5a0.js";import{Uh as Le}from"./chunk-8e0az001.js";import{Wh as At}from"./chunk-p6vszgc2.js";import{Yh as Ct}from"./chunk-gk58959n.js";import{$h as lf,$i as Wg,$j as Wh,Ai as zf,Aj as fh,Ak as ly,Bi as Hf,Bj as gh,Bk as dy,Ci as Gf,Cj as hh,Ck as uy,Di as Kf,Dj as yh,Dk as py,Ei as Uf,Ej as Ch,Ek as my,Fi as Zf,Fj as Sh,Fk as Et,Gi as qf,Gj as Ah,Gk as fy,Hi as jf,Hj as bh,Hk as gy,Ii as Jf,Ij as Rh,Ik as hy,Ji as Yf,Jj as Th,Jk as yy,Ki as Qf,Kj as $h,Kk as Cy,Li as Xf,Lj as Ph,Lk as Sy,Mi as eg,Mj as Ih,Mk as Ay,Ni as tg,Nj as Dh,Nk as by,Oi as rg,Oj as Eh,Ok as Ry,Pi as ng,Pj as wh,Pk as Ty,Qi as ig,Qj as Oh,Qk as $y,Ri as og,Rj as vh,Rk as Py,Si as ag,Sj as Nh,Sk as Iy,Ti as sg,Tj as kh,Tk as Dy,Ui as cg,Uj as xh,Uk as Ey,Vi as lg,Vj as Lh,Vk as wy,Wi as dg,Wj as Mh,Wk as Oy,Xi as ug,Xj as Fh,Yi as pg,Yj as Vh,Zi as mg,Zj as _h,_i as Bg,_j as Bh,ai as df,aj as zg,ak as zh,bi as uf,bj as Hg,bk as Hh,ci as pf,cj as Gg,ck as Gh,di as mf,dj as Kg,dk as Kh,ei as ff,ej as Ug,ek as Uh,fi as gf,fj as Zg,fk as Zh,gi as hf,gj as qg,gk as qh,hi as yf,hj as jg,hk as jh,ii as Cf,ij as Jg,ik as Jh,ji as Sf,jj as Yg,jk as Yh,ki as Af,kj as Qg,kk as Qh,li as bf,lj as Xg,lk as Xh,mi as Rf,mj as eh,mk as ey,ni as Tf,nj as th,nk as Tt,oi as $f,oj as rh,ok as $t,pi as vf,pj as nh,pk as Pt,qi as Nf,qj as ih,qk as It,ri as kf,rj as oh,rk as Dt,si as xf,sj as ah,sk as ty,ti as Lf,tj as sh,tk as ry,ui as Mf,uj as ch,uk as ny,vi as Ff,vj as lh,vk as iy,wi as Vf,wj as dh,wk as oy,xi as _f,xj as uh,xk as ay,yi as Bf,yj as ph,yk as sy,zi as Wf,zj as mh,zk as cy}from"./chunk-s3rpd72x.js";import{$k as Jn,Xk as Un,Yk as Zn,Zk as qn,_k as jn,al as Yn,bl as Qn,dl as Xn,el as ei,fl as ti,gl as ri,hl as ni,il as ii}from"./chunk-vz95qy3n.js";import{kl as an,ll as sn,ml as cn,nl as ln,ol as dn,pl as un}from"./chunk-r5natbed.js";import{ql as wt,rl as Ot,sl as vt,tl as Nt,ul as kt,vl as xt,wl as Lt,xl as Mt}from"./chunk-b10cbk8z.js";import{$l as Wa,$m as Rs,$n as Rc,$o as Rl,$p as Rd,$q as Ru,$r as Rp,$s as pm,Al as fa,Am as Re,An as js,Ao as jc,Ap as jl,Aq as jd,Ar as ju,As as jp,Bl as ga,Bm as K,Bn as Js,Bo as Jc,Bp as Jl,Bq as Jd,Br as Ju,Bs as Jp,Cl as ha,Cm as L,Cn as Ys,Co as Yc,Cp as Yl,Cq as Yd,Cr as Yu,Cs as Yp,Dl as ya,Dm as cs,Dn as Qs,Do as Qc,Dp as Ql,Dq as Qd,Dr as Qu,Ds as Qp,El as Ca,Em as ls,En as Xs,Eo as Xc,Ep as Xl,Eq as Xd,Er as Xu,Es as Xp,Fl as Sa,Fm as te,Fn as ec,Fo as el,Fp as ed,Fq as eu,Fr as ep,Fs as em,Gl as Aa,Gm as ds,Gn as tc,Go as tl,Gp as td,Gq as tu,Gr as tp,Gs as tm,Hl as ba,Hm as us,Hn as rc,Ho as rl,Hp as rd,Hq as ru,Hr as rp,Hs as rm,Il as Ra,Im as ps,In as nc,Io as nl,Ip as nd,Iq as nu,Ir as np,Is as nm,Jl as Ta,Jm as ms,Jn as ic,Jo as il,Jp as id,Jq as iu,Jr as ip,Js as im,Kl as $a,Km as Te,Kn as oc,Ko as ol,Kp as od,Kq as ou,Kr as op,Ks as ct,Ll as Pa,Lm as M,Ln as ac,Lo as al,Lp as ad,Lq as au,Lr as ap,Ls as lt,Ml as Ia,Mm as U,Mn as sc,Mo as sl,Mp as sd,Mq as su,Mr as sp,Ms as dt,Nl as Da,Nm as re,Nn as cc,No as cl,Np as cd,Nq as cu,Nr as cp,Ns as ut,Ol as Ea,Om as $e,On as lc,Oo as ll,Op as ld,Oq as lu,Or as lp,Os as pt,Pl as wa,Pm as Pe,Pn as dc,Po as dl,Pp as dd,Pq as du,Pr as dp,Ps as mt,Ql as Oa,Qm as fs,Qn as uc,Qo as ul,Qp as ud,Qq as uu,Qr as up,Qs as ft,Rl as va,Rm as gs,Rn as pc,Ro as pl,Rp as pd,Rq as pu,Rr as pp,Rs as gt,Sl as Na,Sm as Ie,Sn as mc,So as ml,Sp as md,Sq as mu,Sr as mp,Ss as ht,Tl as ka,Tm as hs,Tn as fc,To as fl,Tp as fd,Tq as fu,Tr as fp,Ts as yt,Ul as xa,Um as ys,Un as gc,Uo as gl,Up as gd,Uq as gu,Ur as gp,Us as om,Vl as La,Vm as Cs,Vn as hc,Vo as hl,Vp as hd,Vq as hu,Vr as hp,Vs as am,Wl as Ma,Wm as Ss,Wn as yc,Wo as yl,Wp as yd,Wq as yu,Wr as yp,Ws as sm,Xl as Fa,Xm as As,Xn as Cc,Xo as Cl,Xp as Cd,Xq as Cu,Xr as Cp,Xs as cm,Yl as Va,Ym as De,Yn as Sc,Yo as Sl,Yp as Sd,Yq as Su,Yr as Sp,Ys as lm,Zl as _a,Zm as Z,Zn as Ac,Zo as Al,Zp as Ad,Zq as Au,Zr as Ap,Zs as dm,_l as Ba,_m as bs,_n as bc,_o as bl,_p as bd,_q as bu,_r as bp,_s as um,am as za,an as Ts,ao as Tc,ap as Tl,aq as Td,ar as Tu,as as Tp,at as mm,bm as Ha,bn as $s,bo as $c,bp as $l,bq as $d,br as $u,bs as $p,bt as fm,cm as Se,cn as Ps,co as Pc,cp as Pl,cq as Pd,cr as Pu,cs as Pp,ct as gm,dm as Ga,dn as Is,do as Ic,dp as Il,dq as Id,dr as Iu,ds as Ip,dt as hm,em as Ae,en as Ds,eo as Dc,ep as Dl,eq as Dd,er as Du,es as Dp,et as ym,fm as be,fn as Es,fo as Ec,fp as El,fq as Ed,fr as Eu,fs as Ep,ft as Cm,gm as Ka,gn as ws,go as wc,gp as wl,gq as wd,gr as wu,gs as wp,gt as Sm,hm as Ua,hn as Os,ho as Oc,hp as Ol,hq as Od,hr as Ou,hs as Op,ht as Am,im as Za,in as vs,io as vc,ip as vl,iq as vd,ir as vu,is as vp,it as bm,jm as qa,jn as Ns,jo as Nc,jp as Nl,jq as Nd,jr as Nu,js as Np,jt as Rm,km as ja,kn as ks,ko as kc,kp as kl,kq as kd,kr as ku,ks as kp,kt as Tm,lm as Ja,ln as xs,lo as xc,lp as xl,lq as xd,lr as xu,ls as xp,lt as $m,mm as Ya,mn as Ls,mo as Lc,mp as Ll,mq as Ld,mr as Lu,ms as Lp,mt as Pm,nm as Qa,nn as Ms,no as Mc,np as Ml,nq as Md,nr as Mu,ns as Mp,nt as Im,om as Xa,on as Fs,oo as Fc,op as Fl,oq as Fd,or as Fu,os as Fp,ot as Dm,pm as es,pn as Vs,po as Vc,pp as Vl,pq as Vd,pr as Vu,ps as Vp,pt as Em,qm as ts,qn as _s,qo as _c,qp as _l,qq as _d,qr as _u,qs as _p,qt as wm,rm as rs,rn as Bs,ro as Bc,rp as Bl,rq as Bd,rr as Bu,rs as Bp,rt as Om,sm as ns,sn as Ws,so as Wc,sp as Wl,sq as Wd,sr as Wu,ss as Wp,st as vm,tm as is,tn as zs,to as zc,tp as zl,tq as zd,tr as zu,ts as zp,tt as Nm,um as X,un as Hs,uo as Hc,up as Hl,uq as Hd,ur as Hu,us as Hp,ut as km,vm as os,vn as Gs,vo as Gc,vp as Gl,vq as Gd,vr as Gu,vs as Gp,vt as xm,wm as as,wn as Ks,wo as Kc,wp as Kl,wq as Kd,wr as Ku,ws as Kp,wt as Lm,xm as ss,xn as Us,xo as Uc,xp as Ul,xq as Ud,xr as Uu,xs as Up,xt as Mm,yl as pa,ym as ee,yn as Zs,yo as Zc,yp as Zl,yq as Zd,yr as Zu,ys as Zp,yt as Fm,zl as ma,zm as w,zn as qs,zo as qc,zp as ql,zq as qd,zr as qu,zs as qp}from"./chunk-0hj552t7.js";import{zt as Je}from"./chunk-spx89gaw.js";import{createHmac as fe,createSign as _e,timingSafeEqual as Be}from"node:crypto";function B(e){let t=e instanceof Date?e.getTime():e;if(!Number.isFinite(t))throw TypeError("Media access timestamp must be finite");return Math.floor(t/1000)}function ge(e){return Buffer.from(e).toString("base64").replaceAll("+","-").replaceAll("=","_").replaceAll("/","~")}function We(e){return Buffer.from(e).toString("base64url")}function he(e,t=!1){if(!e||/[\r\n]/.test(e))throw TypeError("Media resource is invalid");let r=t?e.replaceAll("*","wildcard"):e,n=new URL(r);if(!["http:","https:"].includes(n.protocol))throw TypeError("Media resource must use HTTP or HTTPS");if(!t&&e.includes("*"))throw TypeError("Canned policies cannot contain wildcards")}function ye(e,t){let r=_e("RSA-SHA1");return r.update(e),r.end(),ge(r.sign(t))}function Ce(e){he(e.resource,!0);let r={DateLessThan:{"AWS:EpochTime":B(e.expiresAt)}};if(e.activeAt!==void 0)r.DateGreaterThan={"AWS:EpochTime":B(e.activeAt)};if(e.ipAddress)r.IpAddress={"AWS:SourceIp":e.ipAddress};return JSON.stringify({Statement:[{Resource:e.resource,Condition:r}]})}function Ei(e,t,r){he(e);let n=B(t),i=e.includes("?")?"&":"?",l=Ce({resource:e,expiresAt:t}),c=ye(l,r.privateKey);return`${e}${i}Expires=${n}&Signature=${encodeURIComponent(c)}&Key-Pair-Id=${encodeURIComponent(r.keyPairId)}`}function wi(e,t){let r=Ce(e);return{"CloudFront-Key-Pair-Id":t.keyPairId,"CloudFront-Policy":ge(Buffer.from(r)),"CloudFront-Signature":ye(r,t.privateKey)}}function Oi(e){if(!e.resource||/[\r\n]/.test(e.resource))throw TypeError("Media resource is invalid");let t=We(Buffer.from(JSON.stringify({resource:e.resource,expiresAt:B(e.expiresAt),...e.keyId?{keyId:e.keyId}:{},...e.audience?{audience:e.audience}:{}}))),r=fe("sha256",e.secret).update(t).digest("base64url");return`${t}.${r}`}function vi(e,t){let[r,n,i]=e.split(".");if(!r||!n||i)return null;let l=fe("sha256",t.secret).update(r).digest(),c;try{c=Buffer.from(n,"base64url")}catch{return null}if(l.length!==c.length||!Be(l,c))return null;try{let s=JSON.parse(Buffer.from(r,"base64url").toString("utf8")),d=B(t.now??Date.now());if(!s.resource||!Number.isSafeInteger(s.expiresAt)||s.expiresAt<=d)return null;if(t.resource&&s.resource!==t.resource)return null;if(t.audience&&s.audience!==t.audience)return null;return s}catch{return null}}function Ni(e,t=!1){let r=new URL(e,"https://media.invalid").pathname.toLowerCase(),n=/\.(?:m3u8|mpd|vtt|json)$/.test(r),i=/\.(?:key|license)$/.test(r)||r.includes("/keys/")||r.includes("/licenses/");return{"Accept-Ranges":"bytes","Cache-Control":t&&(n||i)?"private, no-store":n?"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 ki(e){if(!/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/.test(e.bucket))throw TypeError("Media bucket is invalid");if(!/^[a-z0-9-]+$/.test(e.region))throw TypeError("Media bucket region is invalid");let t=e.prefix?`/${e.prefix.replace(/^\/+|\/+$/g,"")}`:"",r=e.protected??!1,n="public, max-age=31536000, immutable",i=r?"private, no-store":"public, max-age=5, s-maxage=30, stale-while-revalidate=30";return{originDomain:`${e.bucket}.s3.${e.region}.amazonaws.com`,originPath:t,domain:e.domain,trustedKeyGroupIds:[...new Set(e.trustedKeyGroupIds??[])],behaviors:[{pathPattern:"*.m3u8",cacheControl:i,compress:!0,signed:r},{pathPattern:"*.mpd",cacheControl:i,compress:!0,signed:r},{pathPattern:"*.vtt",cacheControl:i,compress:!0,signed:r},{pathPattern:"*",cacheControl:n,compress:!1,signed:r}],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 ze{builder;config;environment;mergedConfig;serverEipLogicalIds=new Map;constructor(e){this.config=e.config,this.environment=e.environment,this.builder=new Se(`${this.config.project.name} - ${this.environment}`),this.mergedConfig=this.mergeEnvironmentConfig()}mergeEnvironmentConfig(){let t=this.config.environments[this.environment]?.infrastructure;if(!t)return this.config;return{...this.config,infrastructure:{...this.config.infrastructure,...t,compute:{...this.config.infrastructure?.compute,...t.compute},storage:{...this.config.infrastructure?.storage,...t.storage},functions:{...this.config.infrastructure?.functions,...t.functions},servers:{...this.config.infrastructure?.servers,...t.servers},databases:{...this.config.infrastructure?.databases,...t.databases},cdn:{...this.config.infrastructure?.cdn,...t.cdn},sftp:t.sftp??this.config.infrastructure?.sftp,queues:{...this.config.infrastructure?.queues,...t.queues},redirects:{...this.config.infrastructure?.redirects,...t.redirects},realtime:{...this.config.infrastructure?.realtime,...t.realtime},cache:{...this.config.infrastructure?.cache,...t.cache},fileSystem:{...this.config.infrastructure?.fileSystem,...t.fileSystem},email:{...this.config.infrastructure?.email,...t.email},search:{...this.config.infrastructure?.search,...t.search},ai:{...this.config.infrastructure?.ai,...t.ai}}}}shouldDeploy(e){if(e.environments&&!e.environments.includes(this.environment))return!1;if(e.requiresFeatures){let t=this.config.features||{};if(!e.requiresFeatures.every((n)=>t[n]===!0))return!1}if(e.regions){let t=this.config.environments[this.environment]?.region||this.config.project.region;if(!e.regions.includes(t))return!1}if(e.condition&&typeof e.condition==="function")return e.condition(this.config,this.environment);return!0}resolveApiOriginPort(){let e=this.mergedConfig.infrastructure?.api?.port??this.mergedConfig.ports?.api,t=Number(e||3008);return Number.isFinite(t)&&t>0?t: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(e,t){return e==="public"||t.routeCompute===!0}storageBucketName(e,t,r){return this.mergedConfig.infrastructure?.storage?.[r]?.bucket??`${e}-${t}-${r}`}fileSystemLogicalId(e,t,r){return be(Ae({slug:`${e}-${r}`,environment:t,resourceType:"efs"}))}resolveSftpStorage(e,t,r){let n=e.storage;if(n?.type==="efs"&&n.fileSystem){if(!this.mergedConfig.infrastructure?.fileSystem?.[n.fileSystem])throw Error(`sftp: storage.fileSystem "${n.fileSystem}" is not defined in infrastructure.fileSystem`);return{type:"efs",fileSystemId:{Ref:this.fileSystemLogicalId(t,r,n.fileSystem)},posixProfile:n.posixProfile}}if(n?.type==="s3"&&n.storageBucket){if(!this.mergedConfig.infrastructure?.storage?.[n.storageBucket])throw Error(`sftp: storage.storageBucket "${n.storageBucket}" is not defined in infrastructure.storage`);return{type:"s3",bucket:this.storageBucketName(t,r,n.storageBucket)}}return}resolveComputeCachePathPatterns(e){if(e&&e.length>0)return e;return this.defaultComputeCachePathPatterns()}createComputeCacheBehavior(e,t){return{PathPattern:e,TargetOriginId:t,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(e,t,r,n,i,l){let c=this.serverEipLogicalIds.get("app"),s=this.serverEipLogicalIds.get("appInstance");if(!c)return;let d=`EC2-${n}-${i}-api`,h=this.mergedConfig.infrastructure?.servers?.app?.region||this.mergedConfig.project?.region||"us-east-1",u=h==="us-east-1"?".compute-1.amazonaws.com":`.${h}.compute.amazonaws.com`,b={"Fn::Join":["",["ec2-",{"Fn::Join":["-",{"Fn::Split":[".",{Ref:c}]}]},u]]},A=this.resolveApiOriginPort();if(e.push({Id:d,DomainName:b,CustomOriginConfig:{HTTPPort:A,HTTPSPort:443,OriginProtocolPolicy:"http-only",OriginSSLProtocols:["TLSv1.2"]}}),r.push(c),s)r.push(s);for(let R of l)t.push(this.createComputeCacheBehavior(R,d))}buildCaddyfile(e){let t=e.filter(([,i])=>typeof i.domain==="string"&&i.domain&&typeof i.port==="number");if(t.length===0)return;let r=new Map;for(let[,i]of t){let l=r.get(i.domain)??[];l.push({port:i.port,path:i.path}),r.set(i.domain,l)}let n=[];for(let[i,l]of r){let s=[...l].sort((d,h)=>{let u=!d.path||d.path==="/",b=!h.path||h.path==="/";if(u&&!b)return 1;if(!u&&b)return-1;return(h.path?.length??0)-(d.path?.length??0)}).map((d)=>{let h=!d.path||d.path==="/",u=`reverse_proxy localhost:${d.port}`;return h?` handle {
2
+ ${u}
3
+ }`:` handle ${d.path} {
4
+ ${u}
5
+ }`});n.push(`${i} {
6
+ ${s.join(`
7
7
  `)}
8
- }`)}return X.join(`
8
+ }`)}return n.join(`
9
9
 
10
- `)}normalizeMountPath($){let M=$?.mountPath||$?.path;if(!M||M==="/")return;let J=`/${M}`.replace(/\/+/g,"/").replace(/\/$/,"");return J==="/"?void 0:J}storageBucketLogicalId($,M,J){return`${$}-${M}-s3-${J}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((X)=>X.charAt(0).toUpperCase()+X.slice(1)).join("")}pathMountRewriteFunctionCode($,M="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify($)}; var rewriteStyle = ${JSON.stringify(M)}; 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 $=this.mergedConfig.project.slug,M=this.environment,J=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),X=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),W=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure($,M),this.generateContainerInfrastructure($,M);if(J)this.generateServerless($,M);if(X)this.generateServer($,M);if(W)this.generateComputeApp($,M);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox($,M);if(this.generateSharedInfrastructure($,M),this.config.tags)this.applyGlobalTags(this.config.tags);return this}applyGlobalTags($){}generateNetworkInfrastructure($,M){if(this.builder.hasResource("VPC"))return;let X=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:W,logicalId:F}=q0.createVpc({slug:$,environment:M,cidr:X,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",W);let Q=`${$}${M}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Q,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${$}-${M}-igw`},{Key:"Environment",Value:M}]}});let _=`${$}${M}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(_,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:Q}}});let K=`${$}${M}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(K,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${$}-${M}-public-rt`},{Key:"Environment",Value:M}]}}),this.builder.addResource(`${$}${M}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:K},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:Q}},DependsOn:_});let O=this.mergedConfig.environments[M]?.region||this.mergedConfig.project.region||"us-east-1",H=["a","b"];for(let R=0;R<2;R++){let z=`PublicSubnet${R+1}`;this.builder.addResource(z,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${R}.0/24`,AvailabilityZone:`${O}${H[R]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${$}-${M}-public-${H[R]}`},{Key:"Environment",Value:M}]}}),this.builder.addResource(`${z}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:z},RouteTableId:{Ref:K}}})}}generateContainerInfrastructure($,M){let J=this.mergedConfig.infrastructure?.containers;if(!J)return;let X=this.mergedConfig.infrastructure?.loadBalancer,W=this.mergedConfig.infrastructure?.ssl,F=this.mergedConfig.infrastructure?.dns,Q;if(W?.enabled&&W.domains?.length)if(W.certificateArn);else{let H=W.domains[0],R=W.domains.slice(1).map((A)=>{if(A.includes(".")&&A.endsWith(H))return A.replace(`.${H}`,"");return A}),{certificate:z,logicalId:q}=e.createCertificate({domain:H,subdomains:R,slug:$,environment:M,validationMethod:"DNS",hostedZoneId:F?.hostedZoneId});Q=q,this.builder.addResource(q,z)}let _="ECSCluster";this.builder.addResource(_,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${$}-${M}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${$}-${M}`},{Key:"Environment",Value:M}]}});let K=`${$}${M}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(K,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${$}-${M}`,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:`${$}-${M}-alb-sg`},{Key:"Environment",Value:M}]}});let O=`${$}${M}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[H,R]of Object.entries(J)){let z=R.port||3000;this.builder.addResource(O,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${$}-${M}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:z,ToPort:z,SourceSecurityGroupId:{Ref:K},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${$}-${M}-ecs-sg`},{Key:"Environment",Value:M}]}});let q=`${$}${M}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(q,{Type:"AWS::IAM::Role",Properties:{RoleName:`${$}-${M}-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 A=`${$}${M}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(A,{Type:"AWS::IAM::Role",Properties:{RoleName:`${$}-${M}-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 G=`${$}${M}${H}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),Y=`/ecs/${$}-${M}-${H}`;this.builder.addResource(G,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:Y,RetentionInDays:30}});let V=`${$}${M}${H}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),U=String(R.cpu||512),x=String(R.memory||1024);this.builder.addResource(V,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${$}-${M}-${H}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:U,Memory:x,ExecutionRoleArn:{"Fn::GetAtt":[q,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[A,"Arn"]},ContainerDefinitions:[{Name:H,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${$}:latest`},Essential:!0,PortMappings:[{ContainerPort:z,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":Y,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":H}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${z}${R.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${$}-${M}-${H}`},{Key:"Environment",Value:M}]},DependsOn:[q,A,G]});let E=`${$}${M}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(X?.enabled!==!1){this.builder.addResource(E,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${$}-${M}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:K}],Tags:[{Key:"Name",Value:`${$}-${M}-alb`},{Key:"Environment",Value:M}]}});let Z=`${$}${M}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),N=X?.healthCheck?.path||R.healthCheck||"/health";this.builder.addResource(Z,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${$}-${M}-tg`,Port:z,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:N,HealthCheckIntervalSeconds:X?.healthCheck?.interval||30,HealthyThresholdCount:X?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:X?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${$}-${M}-tg`},{Key:"Environment",Value:M}]}});let j=`${$}${M}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(W?.enabled&&W?.redirectHttp)this.builder.addResource(j,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:E},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(j,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:E},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Z}}]}});if(W?.enabled){let D=W.certificateArn||(Q?{Ref:Q}:void 0);if(D){let k=`${$}${M}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(k,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:E},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:D}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:Z}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let P=`${$}${M}${H}Service`.replace(/[^a-zA-Z0-9]/g,""),w=R.desiredCount||1;this.builder.addResource(P,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${$}-${M}-${H}`,Cluster:{Ref:_},TaskDefinition:{Ref:V},DesiredCount:w,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:O}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:H,ContainerPort:z,TargetGroupArn:{Ref:Z}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${$}-${M}-${H}`},{Key:"Environment",Value:M}]},DependsOn:[V,j,Z]});let S=R.autoScaling;if(S){let D=`${$}${M}${H}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(D,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:S.max||10,MinCapacity:S.min||1,ResourceId:{"Fn::Sub":`service/\${${_}}/${$}-${M}-${H}`},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:P}),S.targetCpuUtilization)this.builder.addResource(`${$}${M}${H}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${$}-${M}-${H}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:D},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:S.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(S.targetMemoryUtilization)this.builder.addResource(`${$}${M}${H}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${$}-${M}-${H}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:D},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:S.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(F?.domain&&F?.hostedZoneId)this.builder.addResource(`${$}${M}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:F.hostedZoneId,Name:`api.${F.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[E,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[E,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[_,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${$}-${M}-${H}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[E,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let Z=`${$}${M}${H}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Z,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${$}-${M}-${H}`,Cluster:{Ref:_},TaskDefinition:{Ref:V},DesiredCount:R.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:O}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${$}-${M}-${H}`},{Key:"Environment",Value:M}]},DependsOn:[V]})}break}}generateServerless($,M){if(this.mergedConfig.infrastructure?.functions)for(let[J,X]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(X))continue;let{role:W,logicalId:F}=j0.createRole({slug:$,environment:M,roleName:`${$}-${M}-${J}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(F,W);let{lambdaFunction:Q,logicalId:_}=B.createLambdaFunction({slug:$,environment:M,functionName:`${$}-${M}-${J}`,handler:X.handler||"index.handler",runtime:X.runtime||"nodejs20.x",code:{zipFile:X.code||"export const handler = async () => ({ statusCode: 200 });"},role:F,timeout:X.timeout,memorySize:X.memorySize});this.builder.addResource(_,Q)}if(this.mergedConfig.infrastructure?.api){let{restApi:J,logicalId:X}=S0.createRestApi({slug:$,environment:M,apiName:`${$}-${M}-api`});this.builder.addResource(X,J)}}generateServer($,M){if(!this.mergedConfig.infrastructure?.servers)return;let J=this.mergedConfig.infrastructure.servers,X=this.mergedConfig.infrastructure?.compute,W=this.mergedConfig.infrastructure?.ssl;if(Object.values(J).some((Q)=>!Q.privateNetwork||Q.privateNetwork==="create"))this.generateNetworkInfrastructure($,M);for(let[Q,_]of Object.entries(J)){let K=_.instanceType||_.size||X?.size,H=(K?B.InstanceSize.specs[K]:void 0)?.instanceType||K||"t3.micro",R=_.type||"app",z=_.userData||_.startupScript;if(!z)z=B.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:_.bunVersion||"latest",webServer:"none",domain:_.domain,enableSsl:!!W?.enabled,sslEmail:W?.letsEncrypt?.email,installRedis:R==="cache",installDatabaseClients:!!_.database});let q=_.privateNetwork&&_.privateNetwork!=="create"?_.privateNetwork:{Ref:"VPC"},A=_.subnet||{Ref:"PublicSubnet1"},Y=!!this.mergedConfig.infrastructure?.email?.server?.enabled,V=[22,80,443,this.resolveApiOriginPort()];if(Y)V.push(25,465,587,143,993);let U=B.createServerModeStack({slug:`${$}-${Q}`,environment:M,vpcId:q,subnetId:A,instanceType:H,keyName:_.keyName||`${$}-${M}`,domain:_.domain,userData:z,volumeSize:_.diskSize||20,imageId:_.image,allowedPorts:V});for(let[x,E]of Object.entries(U.resources))this.builder.addResource(x,E);this.serverEipLogicalIds.set(Q,U.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${Q}Instance`,U.outputs.instanceLogicalId),this.builder.addOutput(`${Q}InstanceId`,{Value:{Ref:U.outputs.instanceLogicalId},Description:`Instance ID for ${Q} server`}),this.builder.addOutput(`${Q}PublicIp`,{Value:{Ref:U.outputs.eipLogicalId},Description:`Public IP for ${Q} server`})}}generateComputeApp($,M){let J=this.mergedConfig.infrastructure?.compute;if(!J)return;let X=this.mergedConfig.sites||{},W=Object.entries(X),Q=this.mergedConfig.infrastructure?.dns?.domain,_=this.mergedConfig.infrastructure?.database,K=J.size,H=(K?B.InstanceSize.specs[K]:void 0)?.instanceType||K||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure($,M);let R=this.buildCaddyfile(W),z=B.UserData.generateBunAppScript({runtime:J.runtime||"bun",runtimeVersion:J.runtimeVersion||"latest",systemPackages:J.systemPackages,database:_,caddyfile:R}),q=W.map(([,E])=>E.port).filter((E)=>typeof E==="number"&&![80,443].includes(E)),A=this.resolveApiOriginPort(),G=`${$}${M}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),Y=`${$}-${M}-deploy`;this.builder.addResource(G,{Type:"AWS::S3::Bucket",Properties:{BucketName:Y,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:$},{Key:"Environment",Value:M},{Key:"ManagedBy",Value:"ts-cloud"}]}});let V=B.createServerModeStack({slug:`${$}-app`,environment:M,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:H,keyName:J.allowSsh?`${$}-${M}`:void 0,domain:Q,userData:z,volumeSize:J.disk?.size||20,imageId:J.image,allowedPorts:[...J.allowSsh?[22]:[],80,443,A,...q]}),U=V.resources[V.outputs.instanceLogicalId];if(U?.Properties){let E=U.Properties.Tags||[];U.Properties.Tags=[...E,{Key:"Project",Value:$},{Key:"Environment",Value:M},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let x=V.resources[V.outputs.roleLogicalId];if(x?.Properties)x.Properties.Policies=x.Properties.Policies||[],x.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${Y}`,`arn:aws:s3:::${Y}/*`]}]}});for(let[E,Z]of Object.entries(V.resources))this.builder.addResource(E,Z);this.builder.addOutput("deployBucketName",{Value:{Ref:G},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:V.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:V.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",V.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",V.outputs.instanceLogicalId)}generateJumpBox($,M){let J=this.mergedConfig.infrastructure?.jumpBox;if(!J)return;let X=J===!0?{}:J;if(X.enabled===!1)return;this.generateNetworkInfrastructure($,M);let W=X.size||"micro",Q=B.InstanceSize.specs[W]?.instanceType||W||"t3.micro",_;if(X.mountEfs)_={fileSystemId:typeof X.mountEfs==="string"?X.mountEfs:{Ref:"FileSystem"},mountPath:X.mountPath||"/mnt/efs"};let K;if(X.databaseTools)K=B.JumpBox.withDatabaseTools({slug:$,environment:M,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:X.keyName||`${$}-${M}`,allowedCidrs:X.allowedCidrs});else if(_)K=B.JumpBox.withEfsMount({slug:$,environment:M,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:X.keyName||`${$}-${M}`,fileSystemId:_.fileSystemId,mountPath:_.mountPath,allowedCidrs:X.allowedCidrs});else K=B.createJumpBox({slug:$,environment:M,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:X.keyName||`${$}-${M}`,instanceType:Q,allowedCidrs:X.allowedCidrs,mountEfs:_});for(let[O,H]of Object.entries(K.resources))this.builder.addResource(O,H);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:K.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure($,M){let J=this.mergedConfig.infrastructure?.ssl,X=this.mergedConfig.infrastructure?.dns,W=X?.domain,F=X?.hostedZoneId,Q=[],_,K;if(J?.certificateArn)K=J.certificateArn;else if(J?.enabled&&W&&F){let G=J.domains||[W],Y=G[0],V=G.slice(1).map((E)=>{if(E.includes(".")&&E.endsWith(Y))return E.replace(`.${Y}`,"");return E}),{certificate:U,logicalId:x}=e.createCertificate({domain:Y,subdomains:V,slug:$,environment:M,validationMethod:"DNS",hostedZoneId:F});_=x,this.builder.addResource(x,U)}if(this.mergedConfig.infrastructure?.storage){let G=Object.entries(this.mergedConfig.infrastructure.storage).some(([,U])=>U.website),Y;if(G&&(_||K))Y=`${$}${M}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(Y,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${$}-${M}-s3-oac`,Description:`OAC for ${$} ${M} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let V=Object.entries(this.mergedConfig.infrastructure.storage).map(([U,x])=>({name:U,config:x,mountPath:this.normalizeMountPath(x),rewriteStyle:x.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId($,M,U)})).filter((U)=>U.name!=="public"&&U.config.website&&U.mountPath);for(let[U,x]of Object.entries(this.mergedConfig.infrastructure.storage)){let E=!!(x.website&&Y),Z=this.storageBucketName($,M,U),{bucket:N,logicalId:j}=n.createBucket({slug:$,name:U,environment:M,bucketName:Z,versioning:x.versioning,encryption:x.encryption,public:E?!1:x.public});if(E&&N.Properties)N.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(j,N),x.website){let w=typeof x.website==="object"?x.website:{},S=n.enableWebsiteHosting(N,w.indexDocument||"index.html",w.errorDocument);this.builder.addResource(j,S)}let P=this.normalizeMountPath(x);if(E&&Y&&W&&!(P&&U!=="public")){let w=`${$}${M}${U}CDN`.replace(/[^a-zA-Z0-9]/g,""),S=[];if(x.aliases&&x.aliases.length>0)S.push(...x.aliases);else if(U==="public"){if(S.push(W),J?.domains?.includes(`www.${W}`))S.push(`www.${W}`)}else if(U==="docs")S.push(`docs.${W}`);else if(U==="blog")S.push(`blog.${W}`);let D=typeof x.website==="object"?x.website:{},k=x.spa===!0,I=D.errorDocument||(k?"index.html":"404.html"),f=[];if(k)f.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else f.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${I}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${I}`,ErrorCachingMinTTL:300});let c=K&&S.length>0?{AcmCertificateArn:K,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:_&&S.length>0?{AcmCertificateArn:{Ref:_},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},p=`S3-${$}-${M}-${U}`,L=this.mergedConfig.project.region||"us-east-1",b;if(!k)b=`${$}${M}${U}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(b,{Type:"AWS::CloudFront::Function",Properties:{Name:`${$}-${M}-${U}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${$} ${M} ${U} - 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'; }
11
- else if (!uri.includes('.')) { request.uri += '.html'; } return request; }`}});let i=[{Id:p,DomainName:{"Fn::Sub":`\${${j}}.s3.${L}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Y}}],u=[],o=[];if(this.shouldRouteStorageBucketToCompute(U,x)){this.appendComputeAppOrigin(i,u,o,$,M,this.resolveComputeCachePathPatterns(x.computeRoutes));for(let T of V){let d=`S3-${$}-${M}-${T.name}`,s=`${$}${M}${T.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(s,{Type:"AWS::CloudFront::Function",Properties:{Name:`${$}-${M}-${T.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${$} ${M} ${T.name} at ${T.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(T.mountPath,T.rewriteStyle)}}),i.push({Id:d,DomainName:{"Fn::Sub":`\${${T.logicalId}}.s3.${L}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:Y}}),o.push(T.logicalId,s);for(let I0 of[T.mountPath,`${T.mountPath}/*`])u.push({PathPattern:I0,TargetOriginId:d,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":[s,"FunctionARN"]}}]})}}let E0={Type:"AWS::CloudFront::Distribution",DependsOn:[j,Y,...b?[b]:[],...o],Properties:{DistributionConfig:{Enabled:!0,Comment:`${$} ${M} ${U} site`,DefaultRootObject:"index.html",Origins:i,DefaultCacheBehavior:{TargetOriginId:p,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...b?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[b,"FunctionARN"]}}]}:{}},...u.length>0?{CacheBehaviors:u}:{},...S.length>0?{Aliases:S}:{},ViewerCertificate:c,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:f}}};if(_)E0.DependsOn.push(_);this.builder.addResource(w,E0);let C0=`${j}CloudFrontPolicy`;if(this.builder.addResource(C0,{Type:"AWS::S3::BucketPolicy",DependsOn:[j,w],Properties:{Bucket:{Ref:j},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${j}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${w}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(U,x))for(let T of V){let d=`${T.logicalId}CloudFrontPolicy`;this.builder.addResource(d,{Type:"AWS::S3::BucketPolicy",DependsOn:[T.logicalId,w],Properties:{Bucket:{Ref:T.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:::\${${T.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${w}}`}}}}]}}})}if(S.length>0)Q.push({name:U,bucketLogicalId:j,distLogicalId:w,oacLogicalId:Y,aliases:S});this.builder.addOutput(`${U}CloudFrontDomain`,{Value:{"Fn::GetAtt":[w,"DomainName"]},Description:`CloudFront domain for ${U}`}),this.builder.addOutput(`${U}CloudFrontDistributionId`,{Value:{Ref:w},Description:`CloudFront distribution ID for ${U}`})}if(this.builder.addOutput(`${U}BucketName`,{Value:{Ref:j},Description:`S3 bucket name for ${U}`}),U==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:j},Description:"Frontend S3 bucket name"});if(U==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:j},Description:"Documentation S3 bucket name"});if(U==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:j},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let G=this.mergedConfig.infrastructure.sftp,Y=N0.create({...G,storage:this.resolveSftpStorage(G,$,M)??G.storage,slug:$,environment:M});for(let[V,U]of Object.entries(Y.resources))this.builder.addResource(V,U);this.builder.addOutput("SftpServerId",{Value:{Ref:Y.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${Y.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:Y.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(F&&Q.length>0)for(let{name:G,distLogicalId:Y,aliases:V}of Q)for(let U of V){let x=U.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${x}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Y],Properties:{HostedZoneId:F,Name:U,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[Y,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${x}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[Y],Properties:{HostedZoneId:F,Name:U,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[Y,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[G,Y]of Object.entries(this.mergedConfig.infrastructure.databases))if(Y.engine==="dynamodb"){let{table:V,logicalId:U}=r.createTable({slug:$,environment:M,tableName:`${$}-${M}-${G}`,partitionKey:Y.partitionKey||{name:"id",type:"S"},sortKey:Y.sortKey});this.builder.addResource(U,V)}else if(Y.engine==="postgres"){let{dbInstance:V,logicalId:U}=r.createPostgres({slug:$,environment:M,dbInstanceIdentifier:`${$}-${M}-${G}`,masterUsername:Y.username||"admin",masterUserPassword:Y.password||"changeme123",allocatedStorage:Y.storage||20,dbInstanceClass:Y.instanceClass||"db.t3.micro"});this.builder.addResource(U,V)}else if(Y.engine==="mysql"){let{dbInstance:V,logicalId:U}=r.createMysql({slug:$,environment:M,dbInstanceIdentifier:`${$}-${M}-${G}`,masterUsername:Y.username||"admin",masterUserPassword:Y.password||"changeme123",allocatedStorage:Y.storage||20,dbInstanceClass:Y.instanceClass||"db.t3.micro"});this.builder.addResource(U,V)}}if(this.mergedConfig.infrastructure?.cdn)for(let[G,Y]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!Y.origin)continue;let V=typeof Y.customDomain==="string"?Y.customDomain:Y.customDomain?.domain||Y.domain,U=typeof Y.customDomain==="object"?Y.customDomain?.certificateArn:Y.certificateArn,x=U||K,E=`${$}${M}${G}CDN`.replace(/[^a-zA-Z0-9]/g,""),Z=`S3-${$}-${M}-${G}-cdn`,N=[{Id:Z,DomainName:Y.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:Y.originShield?{Enabled:!0,OriginShieldRegion:Y.originShieldRegion||this.mergedConfig.environments[M]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1}}],j=[],P=[];if(Y.routeCompute)this.appendComputeAppOrigin(N,j,P,$,M,this.resolveComputeCachePathPatterns(Y.computeRoutes));let w=x&&V?{AcmCertificateArn:_&&!U?{Ref:_}:x,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},S=[...P];if(_&&!U&&V)S.push(_);let D={Type:"AWS::CloudFront::Distribution",...S.length>0?{DependsOn:S}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${$} ${M} ${G} CDN`,DefaultRootObject:"index.html",Origins:N,DefaultCacheBehavior:{TargetOriginId:Z,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:Y.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...j.length>0?{CacheBehaviors:j}:{},...V&&x?{Aliases:[V]}:{},ViewerCertificate:w,PriceClass:"PriceClass_100",HttpVersion:Y.http3?"http2and3":"http2"}}};if(this.builder.addResource(E,D),F&&V&&x){let k=V.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${k}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[E,..._&&!U?[_]:[]],Properties:{HostedZoneId:F,Name:V,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[E,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[G,Y]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(Y))continue;let{queue:V,logicalId:U}=$0.createQueue({slug:$,environment:M,name:`${$}-${M}-${G}`,fifo:Y.fifo,visibilityTimeout:Y.visibilityTimeout,messageRetentionPeriod:Y.messageRetentionPeriod,delaySeconds:Y.delaySeconds,maxMessageSize:Y.maxMessageSize,receiveMessageWaitTime:Y.receiveMessageWaitTime,contentBasedDeduplication:Y.contentBasedDeduplication,encrypted:Y.encrypted,kmsKeyId:Y.kmsKeyId});this.builder.addResource(U,V);let x;if(Y.deadLetterQueue){let{deadLetterQueue:E,updatedSourceQueue:Z,deadLetterLogicalId:N}=$0.createDeadLetterQueue(U,{slug:$,environment:M,maxReceiveCount:Y.maxReceiveCount});x=N,this.builder.addResource(N,E);let P=this.builder.getResources()[U];if(P?.Properties)P.Properties.RedrivePolicy=Z.Properties?.RedrivePolicy}if(Y.trigger){let E=Y.trigger,Z=`${$}${M}${E.functionName}`.replace(/[^a-zA-Z0-9]/g,""),N={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[U,"Arn"]},FunctionName:{Ref:Z},BatchSize:E.batchSize||10,MaximumBatchingWindowInSeconds:E.batchWindow||0,Enabled:!0,...E.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...E.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:E.maxConcurrency}},...E.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(E.filterPattern)}]}}},DependsOn:[U,Z]};this.builder.addResource(`${U}Trigger`,N)}if(Y.alarms?.enabled){let E=Y.alarms,Z=E.notificationTopicArn;if(!Z&&E.notificationEmails?.length){let P=`${U}AlarmTopic`;this.builder.addResource(P,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${$}-${M}-${G}-alarms`,DisplayName:`${G} Queue Alarms`}}),E.notificationEmails.forEach((w,S)=>{this.builder.addResource(`${P}Sub${S}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:P},Protocol:"email",Endpoint:w}})}),Z={Ref:P}}let N=E.queueDepthThreshold||1000;this.builder.addResource(`${U}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${$}-${M}-${G}-queue-depth`,AlarmDescription:`Queue ${G} depth exceeds ${N} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:N,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[U,"QueueName"]}}],...Z&&{AlarmActions:[Z],OKActions:[Z]}}});let j=E.messageAgeThreshold||3600;if(this.builder.addResource(`${U}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${$}-${M}-${G}-message-age`,AlarmDescription:`Queue ${G} oldest message exceeds ${j} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:j,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[U,"QueueName"]}}],...Z&&{AlarmActions:[Z],OKActions:[Z]}}}),x&&E.dlqAlarm!==!1)this.builder.addResource(`${x}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${$}-${M}-${G}-dlq-messages`,AlarmDescription:`Dead letter queue for ${G} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[x,"QueueName"]}}],...Z&&{AlarmActions:[Z]}}})}if(Y.subscribe){let E=Y.subscribe,Z=E.topicArn;if(!Z&&E.topicName)Z={Ref:E.topicName};if(Z){this.builder.addResource(`${U}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:U}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[U,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":Z}}}]}}});let N={TopicArn:Z,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[U,"Arn"]},RawMessageDelivery:E.rawMessageDelivery||!1};if(E.filterPolicy)N.FilterPolicy=E.filterPolicy,N.FilterPolicyScope=E.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${U}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:N,DependsOn:`${U}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources($,M);else this.generateRealtimeResources($,M);let O=this.mergedConfig.infrastructure?.redirects;if(O){let G=O.target||this.mergedConfig.infrastructure?.dns?.domain||"",Y=O.protocol||"https";if(O.domains?.length&&G)for(let V of O.domains){let{bucket:U,bucketPolicy:x,logicalId:E,policyLogicalId:Z}=l.createDomainRedirectBucket({slug:$,environment:M,sourceDomain:V,targetDomain:G,protocol:Y});this.builder.addResource(E,U),this.builder.addResource(Z,x)}if(O.paths&&Object.keys(O.paths).length>0){let V=l.fromMapping(O.paths,{statusCode:O.statusCode||301}),{function:U,logicalId:x}=l.createPathRedirectFunction({slug:$,environment:M,rules:V});this.builder.addResource(x,U)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[G,Y]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:V,logicalId:U}=P0.createAlarm({slug:$,environment:M,alarmName:`${$}-${M}-${G}`,metricName:Y.metricName||"Errors",namespace:Y.namespace||"AWS/Lambda",threshold:Y.threshold||1,comparisonOperator:Y.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(U,V)}let H=this.mergedConfig.infrastructure?.cache;if(H){let G=H.type||"redis";if(G==="redis"){this.generateNetworkInfrastructure($,M);let Y=H.redis||{},{replicationGroup:V,subnetGroup:U,logicalId:x,subnetGroupId:E}=M0.createRedis({slug:$,environment:M,nodeType:Y.nodeType||H.nodeType||"cache.t3.micro",engineVersion:Y.engineVersion||"7.1",port:Y.port||6379,numCacheClusters:Y.numCacheNodes||2,automaticFailover:Y.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:Y.snapshotRetentionLimit||7,snapshotWindow:Y.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(x,V),U&&E)this.builder.addResource(E,U);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[x,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[x,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(G==="memcached"){this.generateNetworkInfrastructure($,M);let Y=H.elasticache||{},{cluster:V,subnetGroup:U,logicalId:x,subnetGroupId:E}=M0.createMemcached({slug:$,environment:M,nodeType:Y.nodeType||H.nodeType||"cache.t3.micro",engineVersion:Y.engineVersion||"1.6.22",numCacheNodes:Y.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(x,V),U&&E)this.builder.addResource(E,U);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[x,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let R=this.mergedConfig.infrastructure?.email;if(R){let G=R.domain||this.mergedConfig.infrastructure?.dns?.domain;if(G){let{emailIdentity:Y,logicalId:V}=h.verifyDomain({domain:G,slug:$,environment:M,enableDkim:R.enableDkim!==!1,dkimKeyLength:R.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(V,Y),R.configurationSet!==!1){let{configurationSet:E,logicalId:Z}=h.createConfigurationSet({slug:$,environment:M});this.builder.addResource(Z,E)}let U=R.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(U){if(R.enableDkim!==!1)for(let P=1;P<=3;P++){let w=`DkimRecord${P}${G.replace(/\./g,"")}`;this.builder.addResource(w,{Type:"AWS::Route53::RecordSet",DependsOn:[V],Properties:{HostedZoneId:U,Name:{"Fn::GetAtt":[V,`DkimDNSTokenName${P}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[V,`DkimDNSTokenValue${P}`]}]}})}let{record:E,logicalId:Z}=h.createSpfRecord(G,U);this.builder.addResource(Z,E);let{record:N,logicalId:j}=h.createDmarcRecord(G,U,{policy:"none",reportingEmail:R.dmarcReportingEmail||`dmarc-reports@${G}`});this.builder.addResource(j,N)}this.builder.addOutput("EmailDomain",{Value:G,Description:"SES verified email domain"});let x=R.server;if(x?.enabled&&U){let E=this.mergedConfig.environments[M]?.region||this.mergedConfig.project.region||"us-east-1",Z=`${$}-${M}-email`,{role:N,policy:j,roleLogicalId:P,policyLogicalId:w}=h.createEmailLambdaRole({slug:$,environment:M,s3BucketArn:`arn:aws:s3:::${Z}`,sesIdentityArn:`arn:aws:ses:${E}:*:identity/${G}`});this.builder.addResource(P,N),this.builder.addResource(w,j);let{function:S,permission:D,logicalId:k,permissionLogicalId:I}=h.createInboundEmailLambda({slug:$,environment:M,roleArn:{"Fn::GetAtt":[P,"Arn"]},s3BucketName:Z,organizedPrefix:"mailboxes/"});this.builder.addResource(k,S),this.builder.addResource(I,D);let f=h.createInboundEmailSetup({slug:$,environment:M,domain:G,s3BucketName:Z,s3KeyPrefix:"inbox/",region:E,hostedZoneId:U,lambdaFunctionArn:{"Fn::GetAtt":[k,"Arn"]}});for(let[p,L]of Object.entries(f.resources)){if(L.Type==="AWS::SES::ReceiptRule")L.DependsOn=[I,k];this.builder.addResource(p,L)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:k},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:Z,Description:"S3 bucket for email storage"});let c=this.serverEipLogicalIds.get("app");if(c&&U){let L=`${x?.subdomain||"mail"}.${G}`,b=L.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${b}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:U,Name:L,Type:"A",TTL:"300",ResourceRecords:[{Ref:c}]}})}this.builder.addOutput("MailHost",{Value:`mail.${G}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let z=this.mergedConfig.infrastructure?.search;if(z){let G=z.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(G)this.generateNetworkInfrastructure($,M);let{domain:Y,logicalId:V}=w0.createDomain({slug:$,environment:M,engineVersion:z.engineVersion||"OpenSearch_2.11",instanceType:z.instanceType||"t3.small.search",instanceCount:z.instanceCount||1,volumeSize:z.volumeSize||10,volumeType:z.volumeType||"gp3",dedicatedMaster:z.dedicatedMaster||!1,dedicatedMasterType:z.dedicatedMasterType,dedicatedMasterCount:z.dedicatedMasterCount||3,multiAz:z.multiAz||!1,encryption:z.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:z.advancedSecurity,autoTune:z.autoTune!==!1,vpc:G});this.builder.addResource(V,Y),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[V,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[V,"Arn"]},Description:"OpenSearch domain ARN"})}let q=this.mergedConfig.infrastructure?.fileSystem;if(q&&Object.keys(q).length>0){this.generateNetworkInfrastructure($,M);for(let[G,Y]of Object.entries(q)){let{fileSystem:V,logicalId:U}=t.createFileSystem({slug:`${$}-${G}`,environment:M,encrypted:Y.encrypted!==!1,performanceMode:Y.performanceMode||"generalPurpose",throughputMode:Y.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(U,V);let{securityGroup:x,logicalId:E}=t.createEfsSecurityGroup({slug:`${$}-${G}`,environment:M,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(E,x);let{mountTargets:Z,logicalIds:N}=t.createMultiAzMountTargets(U,{slug:`${$}-${G}`,environment:M,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:E}});for(let j=0;j<Z.length;j++)this.builder.addResource(N[j],Z[j]);this.builder.addOutput(`${G}FileSystemId`,{Value:{Ref:U},Description:`EFS file system ID for ${G}`})}}let A=this.mergedConfig.infrastructure?.ai;if(A){let G=A.service||"ecs",Y=A.models||["*"],V=A.allowStreaming!==!1,U;if(G==="ecs")U=C.enableBedrockForEcs({slug:$,environment:M,models:Y,allowStreaming:V});else if(G==="ec2")U=C.enableBedrockForEc2({slug:$,environment:M,models:Y,allowStreaming:V});else if(G==="lambda")U=C.enableBedrockForLambda({slug:$,environment:M,models:Y,allowStreaming:V});else U=C.createBedrockRole(G,{slug:$,environment:M,models:Y,allowStreaming:V});if(this.builder.addResource(U.logicalId,U.role),A.allowAsync){let{policy:x,logicalId:E}=C.createBedrockPolicy({slug:$,environment:M,models:Y,allowStreaming:V,allowAsync:!0});this.builder.addResource(E,x)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[U.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources($,M){let J=this.mergedConfig.infrastructure?.realtime;if(!J)return;let X=J.name||`${$}-${M}-realtime`,W=J.scaling||{},F=J.storage||{type:"dynamodb"},Q=W.handlerMemory||256,_=W.handlerTimeout||30,K=`${$}${M}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),O=`${$}${M}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(F.type==="dynamodb"){let N=F.dynamodb||{},j=N.billingMode||"PAY_PER_REQUEST";this.builder.addResource(K,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${$}-${M}-realtime-connections`,BillingMode:j,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"},...j==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:N.readCapacity||5,WriteCapacityUnits:N.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...j==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:N.readCapacity||5,WriteCapacityUnits:N.writeCapacity||5}},...N.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${$}-${M}-realtime-connections`},{Key:"Environment",Value:M}]}}),this.builder.addResource(O,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${$}-${M}-realtime-channels`,BillingMode:j,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"},...j==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:N.readCapacity||5,WriteCapacityUnits:N.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...j==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:N.readCapacity||5,WriteCapacityUnits:N.writeCapacity||5}},Tags:[{Key:"Name",Value:`${$}-${M}-realtime-channels`},{Key:"Environment",Value:M}]}})}let H=`${$}${M}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(H,{Type:"AWS::IAM::Role",Properties:{RoleName:`${$}-${M}-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":[K,"Arn"]},{"Fn::Sub":`\${${K}.Arn}/index/*`},{"Fn::GetAtt":[O,"Arn"]},{"Fn::Sub":`\${${O}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let R=`${$}${M}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),z=`${$}${M}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),q=`${$}${M}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(R,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${$}-${M}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[H,"Arn"]},MemorySize:Q,Timeout:_,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:K},CHANNELS_TABLE:{Ref:O},ENVIRONMENT:M}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[H,K]}),this.builder.addResource(z,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${$}-${M}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[H,"Arn"]},MemorySize:Q,Timeout:_,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:K},CHANNELS_TABLE:{Ref:O},ENVIRONMENT:M}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[H,K,O]}),this.builder.addResource(q,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${$}-${M}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[H,"Arn"]},MemorySize:Q,Timeout:_,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:K},CHANNELS_TABLE:{Ref:O},ENVIRONMENT:M}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[H,K,O]});let A=`${$}${M}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(A,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:X,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:X,Environment:M}}});let G=`${R}Permission`,Y=`${z}Permission`,V=`${q}Permission`;this.builder.addResource(G,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:R},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${A}}/*/$connect`}}}),this.builder.addResource(Y,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:z},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${A}}/*/$disconnect`}}}),this.builder.addResource(V,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:q},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${A}}/*/$default`}}});let U=`${A}ConnectInteg`,x=`${A}DisconnectInteg`,E=`${A}MessageInteg`;this.builder.addResource(U,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:A},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${R}.Arn}/invocations`}}}),this.builder.addResource(x,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:A},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${z}.Arn}/invocations`}}}),this.builder.addResource(E,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:A},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${q}.Arn}/invocations`}}}),this.builder.addResource(`${A}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:A},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${U}}`}}}),this.builder.addResource(`${A}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:A},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${x}}`}}}),this.builder.addResource(`${A}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:A},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${E}}`}}});let Z=`${A}Stage`;if(this.builder.addResource(Z,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:A},StageName:M,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:W.messagesPerSecond||1000,ThrottlingRateLimit:W.messagesPerSecond||1000}}}),J.monitoring?.enabled){let N=J.monitoring,j=N.notificationTopicArn;if(!j&&N.notificationEmails?.length){let P=`${A}AlarmTopic`;this.builder.addResource(P,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${$}-${M}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),N.notificationEmails.forEach((w,S)=>{this.builder.addResource(`${P}Sub${S}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:P},Protocol:"email",Endpoint:w}})}),j={Ref:P}}if(N.connectionThreshold)this.builder.addResource(`${A}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${$}-${M}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${N.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:N.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:A}}],...j&&{AlarmActions:[j]}}});if(N.errorThreshold)this.builder.addResource(`${A}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${$}-${M}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${N.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:N.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:A}}],...j&&{AlarmActions:[j]}}})}this.builder.addOutput(`${A}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${A}}.execute-api.\${AWS::Region}.amazonaws.com/${M}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${A}Id`,{Description:"WebSocket API ID",Value:{Ref:A},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
10
+ `)}normalizeMountPath(e){let t=e?.mountPath||e?.path;if(!t||t==="/")return;let r=`/${t}`.replace(/\/+/g,"/").replace(/\/$/,"");return r==="/"?void 0:r}storageBucketLogicalId(e,t,r){return`${e}-${t}-s3-${r}`.split(/[^a-zA-Z0-9]+/).filter(Boolean).map((n)=>n.charAt(0).toUpperCase()+n.slice(1)).join("")}pathMountRewriteFunctionCode(e,t="directory"){return`function handler(event) { var request = event.request; var prefix = ${JSON.stringify(e)}; var rewriteStyle = ${JSON.stringify(t)}; 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 e=this.mergedConfig.project.slug,t=this.environment,r=!!(this.mergedConfig.infrastructure?.functions&&Object.keys(this.mergedConfig.infrastructure.functions).length>0||this.mergedConfig.infrastructure?.api),n=!!(this.mergedConfig.infrastructure?.servers&&Object.keys(this.mergedConfig.infrastructure.servers).length>0),i=!!this.mergedConfig.infrastructure?.compute;if(!!((this.mergedConfig.mode||"server")==="serverless"&&this.mergedConfig.infrastructure?.containers&&Object.keys(this.mergedConfig.infrastructure.containers).length>0))this.generateNetworkInfrastructure(e,t),this.generateContainerInfrastructure(e,t);if(r)this.generateServerless(e,t);if(n)this.generateServer(e,t);if(i)this.generateComputeApp(e,t);if(this.mergedConfig.infrastructure?.jumpBox)this.generateJumpBox(e,t);if(this.generateSharedInfrastructure(e,t),this.config.tags)this.applyGlobalTags(this.config.tags);return this}applyGlobalTags(e){}generateNetworkInfrastructure(e,t){if(this.builder.hasResource("VPC"))return;let n=this.mergedConfig.infrastructure?.network?.cidr||"10.0.0.0/16",{vpc:i,logicalId:l}=Re.createVpc({slug:e,environment:t,cidr:n,enableDnsHostnames:!0,enableDnsSupport:!0});this.builder.addResource("VPC",i);let c=`${e}${t}IGW`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(c,{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:`${e}-${t}-igw`},{Key:"Environment",Value:t}]}});let s=`${e}${t}IGWAttach`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(s,{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:{Ref:"VPC"},InternetGatewayId:{Ref:c}}});let d=`${e}${t}PublicRT`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(d,{Type:"AWS::EC2::RouteTable",Properties:{VpcId:{Ref:"VPC"},Tags:[{Key:"Name",Value:`${e}-${t}-public-rt`},{Key:"Environment",Value:t}]}}),this.builder.addResource(`${e}${t}PublicRoute`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::EC2::Route",Properties:{RouteTableId:{Ref:d},DestinationCidrBlock:"0.0.0.0/0",GatewayId:{Ref:c}},DependsOn:s});let h=this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1",u=["a","b"];for(let b=0;b<2;b++){let A=`PublicSubnet${b+1}`;this.builder.addResource(A,{Type:"AWS::EC2::Subnet",Properties:{VpcId:{Ref:"VPC"},CidrBlock:`10.0.${b}.0/24`,AvailabilityZone:`${h}${u[b]}`,MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:`${e}-${t}-public-${u[b]}`},{Key:"Environment",Value:t}]}}),this.builder.addResource(`${A}RTAssoc`,{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:{Ref:A},RouteTableId:{Ref:d}}})}}generateContainerInfrastructure(e,t){let r=this.mergedConfig.infrastructure?.containers;if(!r)return;let n=this.mergedConfig.infrastructure?.loadBalancer,i=this.mergedConfig.infrastructure?.ssl,l=this.mergedConfig.infrastructure?.dns,c;if(i?.enabled&&i.domains?.length)if(i.certificateArn);else{let u=i.domains[0],b=i.domains.slice(1).map((y)=>{if(y.includes(".")&&y.endsWith(u))return y.replace(`.${u}`,"");return y}),{certificate:A,logicalId:R}=ee.createCertificate({domain:u,subdomains:b,slug:e,environment:t,validationMethod:"DNS",hostedZoneId:l?.hostedZoneId});c=R,this.builder.addResource(R,A)}let s="ECSCluster";this.builder.addResource(s,{Type:"AWS::ECS::Cluster",Properties:{ClusterName:`${e}-${t}`,ClusterSettings:[{Name:"containerInsights",Value:"enabled"}],Tags:[{Key:"Name",Value:`${e}-${t}`},{Key:"Environment",Value:t}]}});let d=`${e}${t}ALBSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(d,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ALB security group for ${e}-${t}`,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:`${e}-${t}-alb-sg`},{Key:"Environment",Value:t}]}});let h=`${e}${t}ECSSecurityGroup`.replace(/[^a-zA-Z0-9]/g,"");for(let[u,b]of Object.entries(r)){let A=b.port||3000;this.builder.addResource(h,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`ECS tasks security group for ${e}-${t}`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:A,ToPort:A,SourceSecurityGroupId:{Ref:d},Description:"Allow traffic from ALB"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${e}-${t}-ecs-sg`},{Key:"Environment",Value:t}]}});let R=`${e}${t}TaskExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(R,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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 y=`${e}${t}TaskRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(y,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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 m=`${e}${t}${u}LogGroup`.replace(/[^a-zA-Z0-9]/g,""),o=`/ecs/${e}-${t}-${u}`;this.builder.addResource(m,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:o,RetentionInDays:30}});let g=`${e}${t}${u}TaskDef`.replace(/[^a-zA-Z0-9]/g,""),a=String(b.cpu||512),f=String(b.memory||1024);this.builder.addResource(g,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${e}-${t}-${u}`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:a,Memory:f,ExecutionRoleArn:{"Fn::GetAtt":[R,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[y,"Arn"]},ContainerDefinitions:[{Name:u,Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${e}:latest`},Essential:!0,PortMappings:[{ContainerPort:A,Protocol:"tcp"}],LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":o,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":u}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${A}${b.healthCheck||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[R,y,m]});let p=`${e}${t}ALB`.replace(/[^a-zA-Z0-9]/g,"");if(n?.enabled!==!1){this.builder.addResource(p,{Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:`${e}-${t}-alb`,Scheme:"internet-facing",Type:"application",Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],SecurityGroups:[{Ref:d}],Tags:[{Key:"Name",Value:`${e}-${t}-alb`},{Key:"Environment",Value:t}]}});let C=`${e}${t}TargetGroup`.replace(/[^a-zA-Z0-9]/g,""),S=n?.healthCheck?.path||b.healthCheck||"/health";this.builder.addResource(C,{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:`${e}-${t}-tg`,Port:A,Protocol:"HTTP",VpcId:{Ref:"VPC"},TargetType:"ip",HealthCheckPath:S,HealthCheckIntervalSeconds:n?.healthCheck?.interval||30,HealthyThresholdCount:n?.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:n?.healthCheck?.unhealthyThreshold||5,HealthCheckTimeoutSeconds:10,Tags:[{Key:"Name",Value:`${e}-${t}-tg`},{Key:"Environment",Value:t}]}});let T=`${e}${t}HTTPListener`.replace(/[^a-zA-Z0-9]/g,"");if(i?.enabled&&i?.redirectHttp)this.builder.addResource(T,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}});else this.builder.addResource(T,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:C}}]}});if(i?.enabled){let O=i.certificateArn||(c?{Ref:c}:void 0);if(O){let v=`${e}${t}HTTPSListener`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(v,{Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:{Ref:p},Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:O}],DefaultActions:[{Type:"forward",TargetGroupArn:{Ref:C}}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06"}})}}let I=`${e}${t}${u}Service`.replace(/[^a-zA-Z0-9]/g,""),D=b.desiredCount||1;this.builder.addResource(I,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-${u}`,Cluster:{Ref:s},TaskDefinition:{Ref:g},DesiredCount:D,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:h}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},LoadBalancers:[{ContainerName:u,ContainerPort:A,TargetGroupArn:{Ref:C}}],HealthCheckGracePeriodSeconds:120,Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[g,T,C]});let P=b.autoScaling;if(P){let O=`${e}${t}${u}ScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(O,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:P.max||10,MinCapacity:P.min||1,ResourceId:{"Fn::Sub":`service/\${${s}}/${e}-${t}-${u}`},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:I}),P.targetCpuUtilization)this.builder.addResource(`${e}${t}${u}CPUScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-${u}-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:O},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:P.targetCpuUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}});if(P.targetMemoryUtilization)this.builder.addResource(`${e}${t}${u}MemoryScaling`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-${u}-memory-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:O},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageMemoryUtilization"},TargetValue:P.targetMemoryUtilization,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(l?.domain&&l?.hostedZoneId)this.builder.addResource(`${e}${t}ApiDnsRecord`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:l.hostedZoneId,Name:`api.${l.domain}`,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[p,"DNSName"]},HostedZoneId:{"Fn::GetAtt":[p,"CanonicalHostedZoneID"]}}}});this.builder.addOutput("ECSClusterArn",{Description:"ECS Cluster ARN",Value:{"Fn::GetAtt":[s,"Arn"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-cluster-arn"}}}),this.builder.addOutput("ECSServiceName",{Description:"ECS Service Name",Value:`${e}-${t}-${u}`,Export:{Name:{"Fn::Sub":"${AWS::StackName}-ecs-service-name"}}}),this.builder.addOutput("LoadBalancerDNS",{Description:"Application Load Balancer DNS Name",Value:{"Fn::GetAtt":[p,"DNSName"]},Export:{Name:{"Fn::Sub":"${AWS::StackName}-alb-dns"}}})}else{let C=`${e}${t}${u}Service`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(C,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-${u}`,Cluster:{Ref:s},TaskDefinition:{Ref:g},DesiredCount:b.desiredCount||1,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:h}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},Tags:[{Key:"Name",Value:`${e}-${t}-${u}`},{Key:"Environment",Value:t}]},DependsOn:[g]})}break}}generateServerless(e,t){if(this.mergedConfig.infrastructure?.functions)for(let[r,n]of Object.entries(this.mergedConfig.infrastructure.functions)){if(!this.shouldDeploy(n))continue;let{role:i,logicalId:l}=$e.createRole({slug:e,environment:t,roleName:`${e}-${t}-${r}-role`,servicePrincipal:"lambda.amazonaws.com",managedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]});this.builder.addResource(l,i);let{lambdaFunction:c,logicalId:s}=w.createLambdaFunction({slug:e,environment:t,functionName:`${e}-${t}-${r}`,handler:n.handler||"index.handler",runtime:n.runtime||"nodejs20.x",code:{zipFile:n.code||"export const handler = async () => ({ statusCode: 200 });"},role:l,timeout:n.timeout,memorySize:n.memorySize});this.builder.addResource(s,c)}if(this.mergedConfig.infrastructure?.api){let{restApi:r,logicalId:n}=Pe.createRestApi({slug:e,environment:t,apiName:`${e}-${t}-api`});this.builder.addResource(n,r)}}generateServer(e,t){if(!this.mergedConfig.infrastructure?.servers)return;let r=this.mergedConfig.infrastructure.servers,n=this.mergedConfig.infrastructure?.compute,i=this.mergedConfig.infrastructure?.ssl;if(Object.values(r).some((c)=>!c.privateNetwork||c.privateNetwork==="create"))this.generateNetworkInfrastructure(e,t);for(let[c,s]of Object.entries(r)){let d=s.instanceType||s.size||n?.size,u=(d?w.InstanceSize.specs[d]:void 0)?.instanceType||d||"t3.micro",b=s.type||"app",A=s.userData||s.startupScript;if(!A)A=w.UserData.generateAppServerScript({runtime:"bun",runtimeVersion:s.bunVersion||"latest",webServer:"none",domain:s.domain,enableSsl:!!i?.enabled,sslEmail:i?.letsEncrypt?.email,installRedis:b==="cache",installDatabaseClients:!!s.database});let R=s.privateNetwork&&s.privateNetwork!=="create"?s.privateNetwork:{Ref:"VPC"},y=s.subnet||{Ref:"PublicSubnet1"},o=!!this.mergedConfig.infrastructure?.email?.server?.enabled,g=[22,80,443,this.resolveApiOriginPort()];if(o)g.push(25,465,587,143,993);let a=w.createServerModeStack({slug:`${e}-${c}`,environment:t,vpcId:R,subnetId:y,instanceType:u,keyName:s.keyName||`${e}-${t}`,domain:s.domain,userData:A,volumeSize:s.diskSize||20,imageId:s.image,allowedPorts:g});for(let[f,p]of Object.entries(a.resources))this.builder.addResource(f,p);this.serverEipLogicalIds.set(c,a.outputs.eipLogicalId),this.serverEipLogicalIds.set(`${c}Instance`,a.outputs.instanceLogicalId),this.builder.addOutput(`${c}InstanceId`,{Value:{Ref:a.outputs.instanceLogicalId},Description:`Instance ID for ${c} server`}),this.builder.addOutput(`${c}PublicIp`,{Value:{Ref:a.outputs.eipLogicalId},Description:`Public IP for ${c} server`})}}generateComputeApp(e,t){let r=this.mergedConfig.infrastructure?.compute;if(!r)return;let n=this.mergedConfig.sites||{},i=Object.entries(n),c=this.mergedConfig.infrastructure?.dns?.domain,s=this.mergedConfig.infrastructure?.database,d=r.size,u=(d?w.InstanceSize.specs[d]:void 0)?.instanceType||d||"t3.micro";if(!this.builder.hasResource("VPC"))this.generateNetworkInfrastructure(e,t);let b=this.buildCaddyfile(i),A=w.UserData.generateBunAppScript({runtime:r.runtime||"bun",runtimeVersion:r.runtimeVersion||"latest",systemPackages:r.systemPackages,database:s,caddyfile:b}),R=Ee(r.appUpdates),y=R.length>0?`${A}
11
+ ${R.join(`
12
+ `)}
13
+ `:A,m=i.map(([,S])=>S.port).filter((S)=>typeof S==="number"&&![80,443].includes(S)),o=this.resolveApiOriginPort(),g=`${e}${t}DeployBucket`.replace(/[^a-zA-Z0-9]/g,""),a=`${e}-${t}-deploy`;this.builder.addResource(g,{Type:"AWS::S3::Bucket",Properties:{BucketName:a,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:e},{Key:"Environment",Value:t},{Key:"ManagedBy",Value:"ts-cloud"}]}});let f=w.createServerModeStack({slug:`${e}-app`,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},instanceType:u,keyName:r.allowSsh?`${e}-${t}`:void 0,domain:c,userData:y,volumeSize:r.disk?.size||20,imageId:r.image,allowedPorts:[...r.allowSsh?[22]:[],80,443,o,...m]}),p=f.resources[f.outputs.instanceLogicalId];if(p?.Properties){let S=p.Properties.Tags||[];p.Properties.Tags=[...S,{Key:"Project",Value:e},{Key:"Environment",Value:t},{Key:"Role",Value:"app"},{Key:"ManagedBy",Value:"ts-cloud"}]}let C=f.resources[f.outputs.roleLogicalId];if(C?.Properties)C.Properties.Policies=C.Properties.Policies||[],C.Properties.Policies.push({PolicyName:"DeployBucketRead",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:ListBucket"],Resource:[`arn:aws:s3:::${a}`,`arn:aws:s3:::${a}/*`]}]}});for(let[S,T]of Object.entries(f.resources))this.builder.addResource(S,T);this.builder.addOutput("deployBucketName",{Value:{Ref:g},Description:"S3 bucket where release tarballs are uploaded"}),this.builder.addOutput("appInstanceId",{Value:{Ref:f.outputs.instanceLogicalId},Description:"EC2 instance ID for the app server"}),this.builder.addOutput("appPublicIp",{Value:{Ref:f.outputs.eipLogicalId},Description:"Public IP for the app server"}),this.serverEipLogicalIds.set("app",f.outputs.eipLogicalId),this.serverEipLogicalIds.set("appInstance",f.outputs.instanceLogicalId)}generateJumpBox(e,t){let r=this.mergedConfig.infrastructure?.jumpBox;if(!r)return;let n=r===!0?{}:r;if(n.enabled===!1)return;this.generateNetworkInfrastructure(e,t);let i=n.size||"micro",c=w.InstanceSize.specs[i]?.instanceType||i||"t3.micro",s;if(n.mountEfs)s={fileSystemId:typeof n.mountEfs==="string"?n.mountEfs:{Ref:"FileSystem"},mountPath:n.mountPath||"/mnt/efs"};let d;if(n.databaseTools)d=w.JumpBox.withDatabaseTools({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,allowedCidrs:n.allowedCidrs});else if(s)d=w.JumpBox.withEfsMount({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,fileSystemId:s.fileSystemId,mountPath:s.mountPath,allowedCidrs:n.allowedCidrs});else d=w.createJumpBox({slug:e,environment:t,vpcId:{Ref:"VPC"},subnetId:{Ref:"PublicSubnet1"},keyName:n.keyName||`${e}-${t}`,instanceType:c,allowedCidrs:n.allowedCidrs,mountEfs:s});for(let[h,u]of Object.entries(d.resources))this.builder.addResource(h,u);this.builder.addOutput("JumpBoxInstanceId",{Value:{Ref:d.instanceLogicalId},Description:"The ID of the JumpBox EC2 instance (use with SSM Session Manager or SSH)"})}generateSharedInfrastructure(e,t){let r=this.mergedConfig.infrastructure?.ssl,n=this.mergedConfig.infrastructure?.dns,i=n?.domain,l=n?.hostedZoneId,c=[],s,d;if(r?.certificateArn)d=r.certificateArn;else if(r?.enabled&&i&&l){let m=r.domains||[i],o=m[0],g=m.slice(1).map((p)=>{if(p.includes(".")&&p.endsWith(o))return p.replace(`.${o}`,"");return p}),{certificate:a,logicalId:f}=ee.createCertificate({domain:o,subdomains:g,slug:e,environment:t,validationMethod:"DNS",hostedZoneId:l});s=f,this.builder.addResource(f,a)}if(this.mergedConfig.infrastructure?.storage){let m=Object.entries(this.mergedConfig.infrastructure.storage).some(([,a])=>a.website),o;if(m&&(s||d))o=`${e}${t}CloudFrontOAC`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(o,{Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${e}-${t}-s3-oac`,Description:`OAC for ${e} ${t} S3 website buckets`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}});let g=Object.entries(this.mergedConfig.infrastructure.storage).map(([a,f])=>({name:a,config:f,mountPath:this.normalizeMountPath(f),rewriteStyle:f.pathRewriteStyle||"directory",logicalId:this.storageBucketLogicalId(e,t,a)})).filter((a)=>a.name!=="public"&&a.config.website&&a.mountPath);for(let[a,f]of Object.entries(this.mergedConfig.infrastructure.storage)){let p=!!(f.website&&o),C=this.storageBucketName(e,t,a),{bucket:S,logicalId:T}=X.createBucket({slug:e,name:a,environment:t,bucketName:C,versioning:f.versioning,encryption:f.encryption,public:p?!1:f.public});if(p&&S.Properties)S.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,IgnorePublicAcls:!0,BlockPublicPolicy:!1,RestrictPublicBuckets:!1};if(this.builder.addResource(T,S),f.website){let D=typeof f.website==="object"?f.website:{},P=X.enableWebsiteHosting(S,D.indexDocument||"index.html",D.errorDocument);this.builder.addResource(T,P)}let I=this.normalizeMountPath(f);if(p&&o&&i&&!(I&&a!=="public")){let D=`${e}${t}${a}CDN`.replace(/[^a-zA-Z0-9]/g,""),P=[];if(f.aliases&&f.aliases.length>0)P.push(...f.aliases);else if(a==="public"){if(P.push(i),r?.domains?.includes(`www.${i}`))P.push(`www.${i}`)}else if(a==="docs")P.push(`docs.${i}`);else if(a==="blog")P.push(`blog.${i}`);let O=typeof f.website==="object"?f.website:{},v=f.spa===!0,F=O.errorDocument||(v?"index.html":"404.html"),V=[];if(v)V.push({ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html",ErrorCachingMinTTL:300});else V.push({ErrorCode:403,ResponseCode:404,ResponsePagePath:`/${F}`,ErrorCachingMinTTL:300},{ErrorCode:404,ResponseCode:404,ResponsePagePath:`/${F}`,ErrorCachingMinTTL:300});let z=d&&P.length>0?{AcmCertificateArn:d,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:s&&P.length>0?{AcmCertificateArn:{Ref:s},SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},_=`S3-${e}-${t}-${a}`,N=this.mergedConfig.project.region||"us-east-1",x;if(!v)x=`${e}${t}${a}UrlRewrite`.replace(/[^a-zA-Z0-9]/g,""),this.builder.addResource(x,{Type:"AWS::CloudFront::Function",Properties:{Name:`${e}-${t}-${a}-url-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`URL rewrite for ${e} ${t} ${a} - 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 J=[{Id:_,DomainName:{"Fn::Sub":`\${${T}}.s3.${N}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:o}}],H=[],Y=[];if(this.shouldRouteStorageBucketToCompute(a,f)){this.appendComputeAppOrigin(J,H,Y,e,t,this.resolveComputeCachePathPatterns(f.computeRoutes));for(let E of g){let G=`S3-${e}-${t}-${E.name}`,Q=`${e}${t}${E.name}PathMountRewrite`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Q,{Type:"AWS::CloudFront::Function",Properties:{Name:`${e}-${t}-${E.name}-path-mount-rewrite`,AutoPublish:!0,FunctionConfig:{Comment:`Path mount rewrite for ${e} ${t} ${E.name} at ${E.mountPath}`,Runtime:"cloudfront-js-2.0"},FunctionCode:this.pathMountRewriteFunctionCode(E.mountPath,E.rewriteStyle)}}),J.push({Id:G,DomainName:{"Fn::Sub":`\${${E.logicalId}}.s3.${N}.amazonaws.com`},OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginAccessControlId:{Ref:o}}),Y.push(E.logicalId,Q);for(let Ve of[E.mountPath,`${E.mountPath}/*`])H.push({PathPattern:Ve,TargetOriginId:G,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":[Q,"FunctionARN"]}}]})}}let me={Type:"AWS::CloudFront::Distribution",DependsOn:[T,o,...x?[x]:[],...Y],Properties:{DistributionConfig:{Enabled:!0,Comment:`${e} ${t} ${a} site`,DefaultRootObject:"index.html",Origins:J,DefaultCacheBehavior:{TargetOriginId:_,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6",...x?{FunctionAssociations:[{EventType:"viewer-request",FunctionARN:{"Fn::GetAtt":[x,"FunctionARN"]}}]}:{}},...H.length>0?{CacheBehaviors:H}:{},...P.length>0?{Aliases:P}:{},ViewerCertificate:z,PriceClass:"PriceClass_100",HttpVersion:"http2and3",IPV6Enabled:!0,CustomErrorResponses:V}}};if(s)me.DependsOn.push(s);this.builder.addResource(D,me);let Fe=`${T}CloudFrontPolicy`;if(this.builder.addResource(Fe,{Type:"AWS::S3::BucketPolicy",DependsOn:[T,D],Properties:{Bucket:{Ref:T},PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowCloudFrontServicePrincipal",Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:{"Fn::Sub":`arn:aws:s3:::\${${T}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${D}}`}}}}]}}}),this.shouldRouteStorageBucketToCompute(a,f))for(let E of g){let G=`${E.logicalId}CloudFrontPolicy`;this.builder.addResource(G,{Type:"AWS::S3::BucketPolicy",DependsOn:[E.logicalId,D],Properties:{Bucket:{Ref:E.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:::\${${E.logicalId}}/*`},Condition:{StringEquals:{"AWS:SourceArn":{"Fn::Sub":`arn:aws:cloudfront::\${AWS::AccountId}:distribution/\${${D}}`}}}}]}}})}if(P.length>0)c.push({name:a,bucketLogicalId:T,distLogicalId:D,oacLogicalId:o,aliases:P});this.builder.addOutput(`${a}CloudFrontDomain`,{Value:{"Fn::GetAtt":[D,"DomainName"]},Description:`CloudFront domain for ${a}`}),this.builder.addOutput(`${a}CloudFrontDistributionId`,{Value:{Ref:D},Description:`CloudFront distribution ID for ${a}`})}if(this.builder.addOutput(`${a}BucketName`,{Value:{Ref:T},Description:`S3 bucket name for ${a}`}),a==="public")this.builder.addOutput("FrontendBucketName",{Value:{Ref:T},Description:"Frontend S3 bucket name"});if(a==="docs")this.builder.addOutput("DocsBucketName",{Value:{Ref:T},Description:"Documentation S3 bucket name"});if(a==="blog")this.builder.addOutput("BlogBucketName",{Value:{Ref:T},Description:"Blog S3 bucket name"})}}if(this.mergedConfig.infrastructure?.sftp){let m=this.mergedConfig.infrastructure.sftp,o=Te.create({...m,storage:this.resolveSftpStorage(m,e,t)??m.storage,slug:e,environment:t});for(let[g,a]of Object.entries(o.resources))this.builder.addResource(g,a);this.builder.addOutput("SftpServerId",{Value:{Ref:o.serverLogicalId},Description:"AWS Transfer Family SFTP server ID"}),this.builder.addOutput("SftpEndpoint",{Value:{"Fn::Sub":`\${${o.serverLogicalId}}.server.transfer.\${AWS::Region}.amazonaws.com`},Description:"AWS Transfer Family SFTP endpoint"}),this.builder.addOutput("SftpStorageDomain",{Value:o.domain,Description:"Storage backing the SFTP server (EFS or S3)"})}if(l&&c.length>0)for(let{name:m,distLogicalId:o,aliases:g}of c)for(let a of g){let f=a.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${f}ARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[o],Properties:{HostedZoneId:l,Name:a,Type:"A",AliasTarget:{DNSName:{"Fn::GetAtt":[o,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}}),this.builder.addResource(`${f}AAAARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[o],Properties:{HostedZoneId:l,Name:a,Type:"AAAA",AliasTarget:{DNSName:{"Fn::GetAtt":[o,"DomainName"]},HostedZoneId:"Z2FDTNDATAQYW2",EvaluateTargetHealth:!1}}})}if(this.mergedConfig.infrastructure?.databases){for(let[m,o]of Object.entries(this.mergedConfig.infrastructure.databases))if(o.engine==="dynamodb"){let{table:g,logicalId:a}=U.createTable({slug:e,environment:t,tableName:`${e}-${t}-${m}`,partitionKey:o.partitionKey||{name:"id",type:"S"},sortKey:o.sortKey});this.builder.addResource(a,g)}else if(o.engine==="postgres"){let{dbInstance:g,logicalId:a}=U.createPostgres({slug:e,environment:t,dbInstanceIdentifier:`${e}-${t}-${m}`,masterUsername:o.username||"admin",masterUserPassword:o.password||"changeme123",allocatedStorage:o.storage||20,dbInstanceClass:o.instanceClass||"db.t3.micro"});this.builder.addResource(a,g)}else if(o.engine==="mysql"){let{dbInstance:g,logicalId:a}=U.createMysql({slug:e,environment:t,dbInstanceIdentifier:`${e}-${t}-${m}`,masterUsername:o.username||"admin",masterUserPassword:o.password||"changeme123",allocatedStorage:o.storage||20,dbInstanceClass:o.instanceClass||"db.t3.micro"});this.builder.addResource(a,g)}}if(this.mergedConfig.infrastructure?.cdn)for(let[m,o]of Object.entries(this.mergedConfig.infrastructure.cdn)){if(!o.origin)continue;let g=typeof o.customDomain==="string"?o.customDomain:o.customDomain?.domain||o.domain,a=typeof o.customDomain==="object"?o.customDomain?.certificateArn:o.certificateArn,f=a||d,p=`${e}${t}${m}CDN`.replace(/[^a-zA-Z0-9]/g,""),C=`S3-${e}-${t}-${m}-cdn`,S=[{Id:C,DomainName:o.origin,OriginPath:"",S3OriginConfig:{OriginAccessIdentity:""},OriginShield:o.originShield?{Enabled:!0,OriginShieldRegion:o.originShieldRegion||this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1"}:{Enabled:!1}}],T=[],I=[];if(o.routeCompute)this.appendComputeAppOrigin(S,T,I,e,t,this.resolveComputeCachePathPatterns(o.computeRoutes));let D=f&&g?{AcmCertificateArn:s&&!a?{Ref:s}:f,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}:{CloudFrontDefaultCertificate:!0},P=[...I];if(s&&!a&&g)P.push(s);let O={Type:"AWS::CloudFront::Distribution",...P.length>0?{DependsOn:P}:{},Properties:{DistributionConfig:{Enabled:!0,Comment:`${e} ${t} ${m} CDN`,DefaultRootObject:"index.html",Origins:S,DefaultCacheBehavior:{TargetOriginId:C,ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:o.compress!==!1,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},...T.length>0?{CacheBehaviors:T}:{},...g&&f?{Aliases:[g]}:{},ViewerCertificate:D,PriceClass:"PriceClass_100",HttpVersion:o.http3?"http2and3":"http2"}}};if(this.builder.addResource(p,O),l&&g&&f){let v=g.replace(/\./g,"").replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${v}CdnARecord`,{Type:"AWS::Route53::RecordSet",DependsOn:[p,...s&&!a?[s]:[]],Properties:{HostedZoneId:l,Name:g,Type:"A",AliasTarget:{HostedZoneId:"Z2FDTNDATAQYW2",DNSName:{"Fn::GetAtt":[p,"DomainName"]}}}})}}if(this.mergedConfig.infrastructure?.queues)for(let[m,o]of Object.entries(this.mergedConfig.infrastructure.queues)){if(!this.shouldDeploy(o))continue;let{queue:g,logicalId:a}=te.createQueue({slug:e,environment:t,name:`${e}-${t}-${m}`,fifo:o.fifo,visibilityTimeout:o.visibilityTimeout,messageRetentionPeriod:o.messageRetentionPeriod,delaySeconds:o.delaySeconds,maxMessageSize:o.maxMessageSize,receiveMessageWaitTime:o.receiveMessageWaitTime,contentBasedDeduplication:o.contentBasedDeduplication,encrypted:o.encrypted,kmsKeyId:o.kmsKeyId});this.builder.addResource(a,g);let f;if(o.deadLetterQueue){let{deadLetterQueue:p,updatedSourceQueue:C,deadLetterLogicalId:S}=te.createDeadLetterQueue(a,{slug:e,environment:t,maxReceiveCount:o.maxReceiveCount});f=S,this.builder.addResource(S,p);let I=this.builder.getResources()[a];if(I?.Properties)I.Properties.RedrivePolicy=C.Properties?.RedrivePolicy}if(o.trigger){let p=o.trigger,C=`${e}${t}${p.functionName}`.replace(/[^a-zA-Z0-9]/g,""),S={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:{"Fn::GetAtt":[a,"Arn"]},FunctionName:{Ref:C},BatchSize:p.batchSize||10,MaximumBatchingWindowInSeconds:p.batchWindow||0,Enabled:!0,...p.reportBatchItemFailures!==!1&&{FunctionResponseTypes:["ReportBatchItemFailures"]},...p.maxConcurrency&&{ScalingConfig:{MaximumConcurrency:p.maxConcurrency}},...p.filterPattern&&{FilterCriteria:{Filters:[{Pattern:JSON.stringify(p.filterPattern)}]}}},DependsOn:[a,C]};this.builder.addResource(`${a}Trigger`,S)}if(o.alarms?.enabled){let p=o.alarms,C=p.notificationTopicArn;if(!C&&p.notificationEmails?.length){let I=`${a}AlarmTopic`;this.builder.addResource(I,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-${m}-alarms`,DisplayName:`${m} Queue Alarms`}}),p.notificationEmails.forEach((D,P)=>{this.builder.addResource(`${I}Sub${P}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:I},Protocol:"email",Endpoint:D}})}),C={Ref:I}}let S=p.queueDepthThreshold||1000;this.builder.addResource(`${a}DepthAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${m}-queue-depth`,AlarmDescription:`Queue ${m} depth exceeds ${S} messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:2,Threshold:S,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[a,"QueueName"]}}],...C&&{AlarmActions:[C],OKActions:[C]}}});let T=p.messageAgeThreshold||3600;if(this.builder.addResource(`${a}AgeAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${m}-message-age`,AlarmDescription:`Queue ${m} oldest message exceeds ${T} seconds`,MetricName:"ApproximateAgeOfOldestMessage",Namespace:"AWS/SQS",Statistic:"Maximum",Period:300,EvaluationPeriods:2,Threshold:T,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[a,"QueueName"]}}],...C&&{AlarmActions:[C],OKActions:[C]}}}),f&&p.dlqAlarm!==!1)this.builder.addResource(`${f}Alarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-${m}-dlq-messages`,AlarmDescription:`Dead letter queue for ${m} has messages`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:1,Threshold:0,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:{"Fn::GetAtt":[f,"QueueName"]}}],...C&&{AlarmActions:[C]}}})}if(o.subscribe){let p=o.subscribe,C=p.topicArn;if(!C&&p.topicName)C={Ref:p.topicName};if(C){this.builder.addResource(`${a}SnsPolicy`,{Type:"AWS::SQS::QueuePolicy",Properties:{Queues:[{Ref:a}],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"sns.amazonaws.com"},Action:"sqs:SendMessage",Resource:{"Fn::GetAtt":[a,"Arn"]},Condition:{ArnEquals:{"aws:SourceArn":C}}}]}}});let S={TopicArn:C,Protocol:"sqs",Endpoint:{"Fn::GetAtt":[a,"Arn"]},RawMessageDelivery:p.rawMessageDelivery||!1};if(p.filterPolicy)S.FilterPolicy=p.filterPolicy,S.FilterPolicyScope=p.filterPolicyScope||"MessageAttributes";this.builder.addResource(`${a}SnsSub`,{Type:"AWS::SNS::Subscription",Properties:S,DependsOn:`${a}SnsPolicy`})}}}if(this.mergedConfig.infrastructure?.realtime?.enabled)if((this.mergedConfig.infrastructure.realtime.mode||"serverless")==="server")this.generateRealtimeServerResources(e,t);else this.generateRealtimeResources(e,t);let h=this.mergedConfig.infrastructure?.redirects;if(h){let m=h.target||this.mergedConfig.infrastructure?.dns?.domain||"",o=h.protocol||"https";if(h.domains?.length&&m)for(let g of h.domains){let{bucket:a,bucketPolicy:f,logicalId:p,policyLogicalId:C}=Z.createDomainRedirectBucket({slug:e,environment:t,sourceDomain:g,targetDomain:m,protocol:o});this.builder.addResource(p,a),this.builder.addResource(C,f)}if(h.paths&&Object.keys(h.paths).length>0){let g=Z.fromMapping(h.paths,{statusCode:h.statusCode||301}),{function:a,logicalId:f}=Z.createPathRedirectFunction({slug:e,environment:t,rules:g});this.builder.addResource(f,a)}}if(this.mergedConfig.infrastructure?.monitoring?.alarms)for(let[m,o]of Object.entries(this.mergedConfig.infrastructure.monitoring.alarms)){let{alarm:g,logicalId:a}=Ie.createAlarm({slug:e,environment:t,alarmName:`${e}-${t}-${m}`,metricName:o.metricName||"Errors",namespace:o.namespace||"AWS/Lambda",threshold:o.threshold||1,comparisonOperator:o.comparisonOperator||"GreaterThanThreshold"});this.builder.addResource(a,g)}let u=this.mergedConfig.infrastructure?.cache;if(u){let m=u.type||"redis";if(m==="redis"){this.generateNetworkInfrastructure(e,t);let o=u.redis||{},{replicationGroup:g,subnetGroup:a,logicalId:f,subnetGroupId:p}=re.createRedis({slug:e,environment:t,nodeType:o.nodeType||u.nodeType||"cache.t3.micro",engineVersion:o.engineVersion||"7.1",port:o.port||6379,numCacheClusters:o.numCacheNodes||2,automaticFailover:o.automaticFailoverEnabled!==!1,atRestEncryption:!0,transitEncryption:!0,snapshotRetentionDays:o.snapshotRetentionLimit||7,snapshotWindow:o.snapshotWindow,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(f,g),a&&p)this.builder.addResource(p,a);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[f,"PrimaryEndPoint.Address"]},Description:"Redis primary endpoint address"}),this.builder.addOutput("CachePort",{Value:{"Fn::GetAtt":[f,"PrimaryEndPoint.Port"]},Description:"Redis primary endpoint port"})}else if(m==="memcached"){this.generateNetworkInfrastructure(e,t);let o=u.elasticache||{},{cluster:g,subnetGroup:a,logicalId:f,subnetGroupId:p}=re.createMemcached({slug:e,environment:t,nodeType:o.nodeType||u.nodeType||"cache.t3.micro",engineVersion:o.engineVersion||"1.6.22",numCacheNodes:o.numCacheNodes||2,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]});if(this.builder.addResource(f,g),a&&p)this.builder.addResource(p,a);this.builder.addOutput("CacheEndpoint",{Value:{"Fn::GetAtt":[f,"ConfigurationEndpoint.Address"]},Description:"Memcached configuration endpoint address"})}}let b=this.mergedConfig.infrastructure?.email;if(b){let m=b.domain||this.mergedConfig.infrastructure?.dns?.domain;if(m){let{emailIdentity:o,logicalId:g}=L.verifyDomain({domain:m,slug:e,environment:t,enableDkim:b.enableDkim!==!1,dkimKeyLength:b.dkimKeyLength||"RSA_2048_BIT"});if(this.builder.addResource(g,o),b.configurationSet!==!1){let{configurationSet:p,logicalId:C}=L.createConfigurationSet({slug:e,environment:t});this.builder.addResource(C,p)}let a=b.hostedZoneId||this.mergedConfig.infrastructure?.dns?.hostedZoneId;if(a){if(b.enableDkim!==!1)for(let I=1;I<=3;I++){let D=`DkimRecord${I}${m.replace(/\./g,"")}`;this.builder.addResource(D,{Type:"AWS::Route53::RecordSet",DependsOn:[g],Properties:{HostedZoneId:a,Name:{"Fn::GetAtt":[g,`DkimDNSTokenName${I}`]},Type:"CNAME",TTL:1800,ResourceRecords:[{"Fn::GetAtt":[g,`DkimDNSTokenValue${I}`]}]}})}let{record:p,logicalId:C}=L.createSpfRecord(m,a);this.builder.addResource(C,p);let{record:S,logicalId:T}=L.createDmarcRecord(m,a,{policy:"none",reportingEmail:b.dmarcReportingEmail||`dmarc-reports@${m}`});this.builder.addResource(T,S)}this.builder.addOutput("EmailDomain",{Value:m,Description:"SES verified email domain"});let f=b.server;if(f?.enabled&&a){let p=this.mergedConfig.environments[t]?.region||this.mergedConfig.project.region||"us-east-1",C=`${e}-${t}-email`,{role:S,policy:T,roleLogicalId:I,policyLogicalId:D}=L.createEmailLambdaRole({slug:e,environment:t,s3BucketArn:`arn:aws:s3:::${C}`,sesIdentityArn:`arn:aws:ses:${p}:*:identity/${m}`});this.builder.addResource(I,S),this.builder.addResource(D,T);let{function:P,permission:O,logicalId:v,permissionLogicalId:F}=L.createInboundEmailLambda({slug:e,environment:t,roleArn:{"Fn::GetAtt":[I,"Arn"]},s3BucketName:C,organizedPrefix:"mailboxes/"});this.builder.addResource(v,P),this.builder.addResource(F,O);let V=L.createInboundEmailSetup({slug:e,environment:t,domain:m,s3BucketName:C,s3KeyPrefix:"inbox/",region:p,hostedZoneId:a,lambdaFunctionArn:{"Fn::GetAtt":[v,"Arn"]}});for(let[_,N]of Object.entries(V.resources)){if(N.Type==="AWS::SES::ReceiptRule")N.DependsOn=[F,v];this.builder.addResource(_,N)}this.builder.addOutput("InboundEmailLambda",{Value:{Ref:v},Description:"Inbound email processing Lambda function"}),this.builder.addOutput("EmailBucket",{Value:C,Description:"S3 bucket for email storage"});let z=this.serverEipLogicalIds.get("app");if(z&&a){let N=`${f?.subdomain||"mail"}.${m}`,x=N.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(`${x}ARecord`,{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:a,Name:N,Type:"A",TTL:"300",ResourceRecords:[{Ref:z}]}})}this.builder.addOutput("MailHost",{Value:`mail.${m}`,Description:"Mail server hostname for SMTP/IMAP clients"})}}}let A=this.mergedConfig.infrastructure?.search;if(A){let m=A.vpc?{subnetIds:[{Ref:"PublicSubnet1"}],securityGroupIds:[]}:void 0;if(m)this.generateNetworkInfrastructure(e,t);let{domain:o,logicalId:g}=De.createDomain({slug:e,environment:t,engineVersion:A.engineVersion||"OpenSearch_2.11",instanceType:A.instanceType||"t3.small.search",instanceCount:A.instanceCount||1,volumeSize:A.volumeSize||10,volumeType:A.volumeType||"gp3",dedicatedMaster:A.dedicatedMaster||!1,dedicatedMasterType:A.dedicatedMasterType,dedicatedMasterCount:A.dedicatedMasterCount||3,multiAz:A.multiAz||!1,encryption:A.encryption||{atRest:!0,nodeToNode:!0},advancedSecurity:A.advancedSecurity,autoTune:A.autoTune!==!1,vpc:m});this.builder.addResource(g,o),this.builder.addOutput("SearchDomainEndpoint",{Value:{"Fn::GetAtt":[g,"DomainEndpoint"]},Description:"OpenSearch domain endpoint"}),this.builder.addOutput("SearchDomainArn",{Value:{"Fn::GetAtt":[g,"Arn"]},Description:"OpenSearch domain ARN"})}let R=this.mergedConfig.infrastructure?.fileSystem;if(R&&Object.keys(R).length>0){this.generateNetworkInfrastructure(e,t);for(let[m,o]of Object.entries(R)){let{fileSystem:g,logicalId:a}=K.createFileSystem({slug:`${e}-${m}`,environment:t,encrypted:o.encrypted!==!1,performanceMode:o.performanceMode||"generalPurpose",throughputMode:o.throughputMode||"bursting",enableBackup:!0});this.builder.addResource(a,g);let{securityGroup:f,logicalId:p}=K.createEfsSecurityGroup({slug:`${e}-${m}`,environment:t,vpcId:{Ref:"VPC"},sourceCidrBlocks:["10.0.0.0/16"]});this.builder.addResource(p,f);let{mountTargets:C,logicalIds:S}=K.createMultiAzMountTargets(a,{slug:`${e}-${m}`,environment:t,subnetIds:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}],securityGroupId:{Ref:p}});for(let T=0;T<C.length;T++)this.builder.addResource(S[T],C[T]);this.builder.addOutput(`${m}FileSystemId`,{Value:{Ref:a},Description:`EFS file system ID for ${m}`})}}let y=this.mergedConfig.infrastructure?.ai;if(y){let m=y.service||"ecs",o=y.models||["*"],g=y.allowStreaming!==!1,a;if(m==="ecs")a=M.enableBedrockForEcs({slug:e,environment:t,models:o,allowStreaming:g});else if(m==="ec2")a=M.enableBedrockForEc2({slug:e,environment:t,models:o,allowStreaming:g});else if(m==="lambda")a=M.enableBedrockForLambda({slug:e,environment:t,models:o,allowStreaming:g});else a=M.createBedrockRole(m,{slug:e,environment:t,models:o,allowStreaming:g});if(this.builder.addResource(a.logicalId,a.role),y.allowAsync){let{policy:f,logicalId:p}=M.createBedrockPolicy({slug:e,environment:t,models:o,allowStreaming:g,allowAsync:!0});this.builder.addResource(p,f)}this.builder.addOutput("BedrockRoleArn",{Value:{"Fn::GetAtt":[a.logicalId,"Arn"]},Description:"IAM role ARN with Bedrock permissions"})}}generateRealtimeResources(e,t){let r=this.mergedConfig.infrastructure?.realtime;if(!r)return;let n=r.name||`${e}-${t}-realtime`,i=r.scaling||{},l=r.storage||{type:"dynamodb"},c=i.handlerMemory||256,s=i.handlerTimeout||30,d=`${e}${t}RealtimeConnections`.replace(/[^a-zA-Z0-9]/g,""),h=`${e}${t}RealtimeChannels`.replace(/[^a-zA-Z0-9]/g,"");if(l.type==="dynamodb"){let S=l.dynamodb||{},T=S.billingMode||"PAY_PER_REQUEST";this.builder.addResource(d,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e}-${t}-realtime-connections`,BillingMode:T,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"},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:S.readCapacity||5,WriteCapacityUnits:S.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:S.readCapacity||5,WriteCapacityUnits:S.writeCapacity||5}},...S.pointInTimeRecovery&&{PointInTimeRecoverySpecification:{PointInTimeRecoveryEnabled:!0}},Tags:[{Key:"Name",Value:`${e}-${t}-realtime-connections`},{Key:"Environment",Value:t}]}}),this.builder.addResource(h,{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${e}-${t}-realtime-channels`,BillingMode:T,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"},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:S.readCapacity||5,WriteCapacityUnits:S.writeCapacity||5}}}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0},...T==="PROVISIONED"&&{ProvisionedThroughput:{ReadCapacityUnits:S.readCapacity||5,WriteCapacityUnits:S.writeCapacity||5}},Tags:[{Key:"Name",Value:`${e}-${t}-realtime-channels`},{Key:"Environment",Value:t}]}})}let u=`${e}${t}RealtimeRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(u,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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":[d,"Arn"]},{"Fn::Sub":`\${${d}.Arn}/index/*`},{"Fn::GetAtt":[h,"Arn"]},{"Fn::Sub":`\${${h}.Arn}/index/*`}]},{Effect:"Allow",Action:"execute-api:ManageConnections",Resource:{"Fn::Sub":"arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:*/*"}}]}}]}});let b=`${e}${t}RealtimeConnect`.replace(/[^a-zA-Z0-9]/g,""),A=`${e}${t}RealtimeDisconnect`.replace(/[^a-zA-Z0-9]/g,""),R=`${e}${t}RealtimeMessage`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(b,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-connect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:h},ENVIRONMENT:t}},Code:{ZipFile:this.generateConnectHandlerCode()}},DependsOn:[u,d]}),this.builder.addResource(A,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-disconnect`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:h},ENVIRONMENT:t}},Code:{ZipFile:this.generateDisconnectHandlerCode()}},DependsOn:[u,d,h]}),this.builder.addResource(R,{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${e}-${t}-realtime-message`,Runtime:"nodejs20.x",Handler:"index.handler",Role:{"Fn::GetAtt":[u,"Arn"]},MemorySize:c,Timeout:s,Environment:{Variables:{CONNECTIONS_TABLE:{Ref:d},CHANNELS_TABLE:{Ref:h},ENVIRONMENT:t}},Code:{ZipFile:this.generateMessageHandlerCode()}},DependsOn:[u,d,h]});let y=`${e}${t}RealtimeApi`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(y,{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:n,ProtocolType:"WEBSOCKET",RouteSelectionExpression:"$request.body.action",Tags:{Name:n,Environment:t}}});let m=`${b}Permission`,o=`${A}Permission`,g=`${R}Permission`;this.builder.addResource(m,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:b},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$connect`}}}),this.builder.addResource(o,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:A},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$disconnect`}}}),this.builder.addResource(g,{Type:"AWS::Lambda::Permission",Properties:{FunctionName:{Ref:R},Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:{"Fn::Sub":`arn:aws:execute-api:\${AWS::Region}:\${AWS::AccountId}:\${${y}}/*/$default`}}});let a=`${y}ConnectInteg`,f=`${y}DisconnectInteg`,p=`${y}MessageInteg`;this.builder.addResource(a,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${b}.Arn}/invocations`}}}),this.builder.addResource(f,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${A}.Arn}/invocations`}}}),this.builder.addResource(p,{Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:{Ref:y},IntegrationType:"AWS_PROXY",IntegrationUri:{"Fn::Sub":`arn:aws:apigateway:\${AWS::Region}:lambda:path/2015-03-31/functions/\${${R}.Arn}/invocations`}}}),this.builder.addResource(`${y}ConnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$connect",AuthorizationType:"NONE",Target:{"Fn::Sub":`integrations/\${${a}}`}}}),this.builder.addResource(`${y}DisconnectRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$disconnect",Target:{"Fn::Sub":`integrations/\${${f}}`}}}),this.builder.addResource(`${y}DefaultRoute`,{Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:{Ref:y},RouteKey:"$default",Target:{"Fn::Sub":`integrations/\${${p}}`}}});let C=`${y}Stage`;if(this.builder.addResource(C,{Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:{Ref:y},StageName:t,AutoDeploy:!0,DefaultRouteSettings:{ThrottlingBurstLimit:i.messagesPerSecond||1000,ThrottlingRateLimit:i.messagesPerSecond||1000}}}),r.monitoring?.enabled){let S=r.monitoring,T=S.notificationTopicArn;if(!T&&S.notificationEmails?.length){let I=`${y}AlarmTopic`;this.builder.addResource(I,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-realtime-alarms`,DisplayName:"Realtime WebSocket Alarms"}}),S.notificationEmails.forEach((D,P)=>{this.builder.addResource(`${I}Sub${P}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:I},Protocol:"email",Endpoint:D}})}),T={Ref:I}}if(S.connectionThreshold)this.builder.addResource(`${y}ConnectionAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-realtime-connections`,AlarmDescription:`WebSocket connections exceed ${S.connectionThreshold}`,MetricName:"ConnectCount",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:300,EvaluationPeriods:2,Threshold:S.connectionThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:y}}],...T&&{AlarmActions:[T]}}});if(S.errorThreshold)this.builder.addResource(`${y}ErrorAlarm`,{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-realtime-errors`,AlarmDescription:`WebSocket errors exceed ${S.errorThreshold}/min`,MetricName:"ExecutionError",Namespace:"AWS/ApiGateway",Statistic:"Sum",Period:60,EvaluationPeriods:3,Threshold:S.errorThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"ApiId",Value:{Ref:y}}],...T&&{AlarmActions:[T]}}})}this.builder.addOutput(`${y}Endpoint`,{Description:"WebSocket API endpoint URL",Value:{"Fn::Sub":`wss://\${${y}}.execute-api.\${AWS::Region}.amazonaws.com/${t}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}}),this.builder.addOutput(`${y}Id`,{Description:"WebSocket API ID",Value:{Ref:y},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-api-id"}}})}generateConnectHandlerCode(){return`
12
15
  const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
13
16
  const { DynamoDBDocumentClient, PutCommand } = require('@aws-sdk/lib-dynamodb');
14
17
 
@@ -167,56 +170,56 @@ catch (error) {
167
170
  return { statusCode: 500, body: JSON.stringify({ error: 'Internal error' }) };
168
171
  }
169
172
  };
170
- `.trim()}generateRealtimeServerResources($,M){let J=this.mergedConfig.infrastructure?.realtime;if(!J)return;let X=J.server||{},W=X.port||6001,F=X.instances||1,Q=`${$}${M}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(Q,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${$} realtime WebSocket server`,GroupName:`${$}-${M}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:W,ToPort:W,CidrIp:"0.0.0.0/0",Description:"WebSocket connections"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0",Description:"HTTPS/WSS connections"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:`${$}-${M}-realtime-sg`},{Key:"Environment",Value:M}]}});let _=`${$}${M}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),K=`${$}${M}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),O=`${$}${M}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(O,{Type:"AWS::IAM::Role",Properties:{RoleName:`${$}-${M}-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(K,{Type:"AWS::IAM::Role",Properties:{RoleName:`${$}-${M}-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:"*"},...X.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let H=[{Name:"BROADCAST_HOST",Value:X.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(W)},{Name:"NODE_ENV",Value:M==="production"?"production":"development"}];if(X.redis?.enabled){if(X.redis.useElastiCache)H.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),H.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else H.push({Name:"REDIS_HOST",Value:X.redis.host||"localhost"}),H.push({Name:"REDIS_PORT",Value:String(X.redis.port||6379)});if(X.redis.keyPrefix)H.push({Name:"REDIS_KEY_PREFIX",Value:X.redis.keyPrefix})}this.builder.addResource(_,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${$}-${M}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[O,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[K,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${$}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:W,Protocol:"tcp"}],Environment:H,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${$}-${M}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${W}${X.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${$}-${M}-realtime`},{Key:"Environment",Value:M}]},DependsOn:[O,K]});let R=`${$}${M}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(R,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${$}-${M}-realtime`,RetentionInDays:30}});let z=`${$}${M}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(z,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${$}-${M}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:_},DesiredCount:F,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:Q}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${$}-${M}-realtime`},{Key:"Environment",Value:M}]},DependsOn:[_,Q,R]}),X.autoScaling){let q=X.autoScaling,A=`${$}${M}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(A,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:q.max||10,MinCapacity:q.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${$}-${M}-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:z}),q.targetCPU)this.builder.addResource(`${$}${M}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${$}-${M}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:A},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:q.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(J.monitoring?.enabled){let q=J.monitoring,A=q.notificationTopicArn;if(!A&&q.notificationEmails?.length){let G=`${$}${M}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(G,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${$}-${M}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),q.notificationEmails.forEach((Y,V)=>{this.builder.addResource(`${G}Sub${V}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:G},Protocol:"email",Endpoint:Y}})}),A={Ref:G}}this.builder.addResource(`${$}${M}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${$}-${M}-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:`${$}-${M}-realtime`}],...A&&{AlarmActions:[A]}},DependsOn:z}),this.builder.addResource(`${$}${M}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${$}-${M}-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:`${$}-${M}-realtime`}],...A&&{AlarmActions:[A]}},DependsOn:z})}this.builder.addOutput(`${$}${M}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${$}-${M}-realtime.\${AWS::Region}.elb.amazonaws.com:${W}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let $=this.mergedConfig.infrastructure?.realtime;if(!$||$.mode!=="server")return"";let M=$.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
173
+ `.trim()}generateRealtimeServerResources(e,t){let r=this.mergedConfig.infrastructure?.realtime;if(!r)return;let n=r.server||{},i=n.port||6001,l=n.instances||1,c=`${e}${t}RealtimeSG`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(c,{Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:`Security group for ${e} realtime WebSocket server`,GroupName:`${e}-${t}-realtime-sg`,VpcId:{Ref:"VPC"},SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:i,ToPort:i,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:`${e}-${t}-realtime-sg`},{Key:"Environment",Value:t}]}});let s=`${e}${t}RealtimeTaskDef`.replace(/[^a-zA-Z0-9]/g,""),d=`${e}${t}RealtimeTaskRole`.replace(/[^a-zA-Z0-9]/g,""),h=`${e}${t}RealtimeExecRole`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(h,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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(d,{Type:"AWS::IAM::Role",Properties:{RoleName:`${e}-${t}-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:"*"},...n.redis?.enabled?[{Effect:"Allow",Action:["elasticache:DescribeCacheClusters","elasticache:DescribeReplicationGroups"],Resource:"*"}]:[]]}}]}});let u=[{Name:"BROADCAST_HOST",Value:n.host||"0.0.0.0"},{Name:"BROADCAST_PORT",Value:String(i)},{Name:"NODE_ENV",Value:t==="production"?"production":"development"}];if(n.redis?.enabled){if(n.redis.useElastiCache)u.push({Name:"REDIS_HOST",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Address"]}}),u.push({Name:"REDIS_PORT",Value:{"Fn::GetAtt":["CacheCluster","RedisEndpoint.Port"]}});else u.push({Name:"REDIS_HOST",Value:n.redis.host||"localhost"}),u.push({Name:"REDIS_PORT",Value:String(n.redis.port||6379)});if(n.redis.keyPrefix)u.push({Name:"REDIS_KEY_PREFIX",Value:n.redis.keyPrefix})}this.builder.addResource(s,{Type:"AWS::ECS::TaskDefinition",Properties:{Family:`${e}-${t}-realtime`,NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:"512",Memory:"1024",ExecutionRoleArn:{"Fn::GetAtt":[h,"Arn"]},TaskRoleArn:{"Fn::GetAtt":[d,"Arn"]},ContainerDefinitions:[{Name:"realtime",Image:{"Fn::Sub":`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${e}-realtime:latest`},Essential:!0,PortMappings:[{ContainerPort:i,Protocol:"tcp"}],Environment:u,LogConfiguration:{LogDriver:"awslogs",Options:{"awslogs-group":`/ecs/${e}-${t}-realtime`,"awslogs-region":{Ref:"AWS::Region"},"awslogs-stream-prefix":"realtime"}},HealthCheck:{Command:["CMD-SHELL",`curl -f http://localhost:${i}${n.healthCheckPath||"/health"} || exit 1`],Interval:30,Timeout:5,Retries:3,StartPeriod:60}}],Tags:[{Key:"Name",Value:`${e}-${t}-realtime`},{Key:"Environment",Value:t}]},DependsOn:[h,d]});let b=`${e}${t}RealtimeLogs`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(b,{Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/ecs/${e}-${t}-realtime`,RetentionInDays:30}});let A=`${e}${t}RealtimeService`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(A,{Type:"AWS::ECS::Service",Properties:{ServiceName:`${e}-${t}-realtime`,Cluster:{Ref:"ECSCluster"},TaskDefinition:{Ref:s},DesiredCount:l,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"ENABLED",SecurityGroups:[{Ref:c}],Subnets:[{Ref:"PublicSubnet1"},{Ref:"PublicSubnet2"}]}},HealthCheckGracePeriodSeconds:60,Tags:[{Key:"Name",Value:`${e}-${t}-realtime`},{Key:"Environment",Value:t}]},DependsOn:[s,c,b]}),n.autoScaling){let R=n.autoScaling,y=`${e}${t}RealtimeScalableTarget`.replace(/[^a-zA-Z0-9]/g,"");if(this.builder.addResource(y,{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{MaxCapacity:R.max||10,MinCapacity:R.min||1,ResourceId:{"Fn::Sub":`service/\${ECSCluster}/${e}-${t}-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:A}),R.targetCPU)this.builder.addResource(`${e}${t}RealtimeCPUPolicy`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${e}-${t}-realtime-cpu-scaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:y},TargetTrackingScalingPolicyConfiguration:{PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},TargetValue:R.targetCPU,ScaleInCooldown:300,ScaleOutCooldown:60}}})}if(r.monitoring?.enabled){let R=r.monitoring,y=R.notificationTopicArn;if(!y&&R.notificationEmails?.length){let m=`${e}${t}RealtimeAlarmTopic`.replace(/[^a-zA-Z0-9]/g,"");this.builder.addResource(m,{Type:"AWS::SNS::Topic",Properties:{TopicName:`${e}-${t}-realtime-alarms`,DisplayName:"Realtime Server Alarms"}}),R.notificationEmails.forEach((o,g)=>{this.builder.addResource(`${m}Sub${g}`,{Type:"AWS::SNS::Subscription",Properties:{TopicArn:{Ref:m},Protocol:"email",Endpoint:o}})}),y={Ref:m}}this.builder.addResource(`${e}${t}RealtimeCPUAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-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:`${e}-${t}-realtime`}],...y&&{AlarmActions:[y]}},DependsOn:A}),this.builder.addResource(`${e}${t}RealtimeMemoryAlarm`.replace(/[^a-zA-Z0-9]/g,""),{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${e}-${t}-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:`${e}-${t}-realtime`}],...y&&{AlarmActions:[y]}},DependsOn:A})}this.builder.addOutput(`${e}${t}RealtimeEndpoint`.replace(/[^a-zA-Z0-9]/g,""),{Description:"Realtime WebSocket server endpoint",Value:{"Fn::Sub":`wss://${e}-${t}-realtime.\${AWS::Region}.elb.amazonaws.com:${i}`},Export:{Name:{"Fn::Sub":"${AWS::StackName}-realtime-endpoint"}}})}generateBroadcastConfig(){let e=this.mergedConfig.infrastructure?.realtime;if(!e||e.mode!=="server")return"";let t=e.server||{};return`import type { BroadcastConfig } from 'ts-broadcasting'
171
174
 
172
175
  export default {
173
176
  verbose: ${this.environment!=="production"},
174
- driver: '${M.driver||"bun"}',
177
+ driver: '${t.driver||"bun"}',
175
178
  default: 'bun',
176
179
 
177
180
  connections: {
178
181
  bun: {
179
182
  driver: 'bun',
180
- host: process.env.BROADCAST_HOST || '${M.host||"0.0.0.0"}',
181
- port: Number(process.env.BROADCAST_PORT) || ${M.port||6001},
182
- scheme: '${M.scheme||"wss"}',
183
+ host: process.env.BROADCAST_HOST || '${t.host||"0.0.0.0"}',
184
+ port: Number(process.env.BROADCAST_PORT) || ${t.port||6001},
185
+ scheme: '${t.scheme||"wss"}',
183
186
  options: {
184
- idleTimeout: ${M.idleTimeout||120},
185
- maxPayloadLength: ${M.maxPayloadLength||16777216},
186
- backpressureLimit: ${M.backpressureLimit||1048576},
187
- closeOnBackpressureLimit: ${M.closeOnBackpressureLimit||!1},
188
- sendPings: ${M.sendPings!==!1},
189
- perMessageDeflate: ${M.perMessageDeflate!==!1},
187
+ idleTimeout: ${t.idleTimeout||120},
188
+ maxPayloadLength: ${t.maxPayloadLength||16777216},
189
+ backpressureLimit: ${t.backpressureLimit||1048576},
190
+ closeOnBackpressureLimit: ${t.closeOnBackpressureLimit||!1},
191
+ sendPings: ${t.sendPings!==!1},
192
+ perMessageDeflate: ${t.perMessageDeflate!==!1},
190
193
  },
191
194
  },
192
195
  },
193
- ${M.redis?.enabled?`
196
+ ${t.redis?.enabled?`
194
197
  redis: {
195
- host: process.env.REDIS_HOST || '${M.redis.host||"localhost"}',
196
- port: Number(process.env.REDIS_PORT) || ${M.redis.port||6379},
197
- ${M.redis.password?`password: process.env.REDIS_PASSWORD || '${M.redis.password}',`:""}
198
- database: ${M.redis.database||0},
199
- keyPrefix: '${M.redis.keyPrefix||"broadcasting:"}',
198
+ host: process.env.REDIS_HOST || '${t.redis.host||"localhost"}',
199
+ port: Number(process.env.REDIS_PORT) || ${t.redis.port||6379},
200
+ ${t.redis.password?`password: process.env.REDIS_PASSWORD || '${t.redis.password}',`:""}
201
+ database: ${t.redis.database||0},
202
+ keyPrefix: '${t.redis.keyPrefix||"broadcasting:"}',
200
203
  },
201
204
  `:""}
202
- ${M.rateLimit?.enabled?`
205
+ ${t.rateLimit?.enabled?`
203
206
  rateLimit: {
204
- max: ${M.rateLimit.max||100},
205
- window: ${M.rateLimit.window||60000},
206
- perChannel: ${M.rateLimit.perChannel!==!1},
207
- perUser: ${M.rateLimit.perUser!==!1},
207
+ max: ${t.rateLimit.max||100},
208
+ window: ${t.rateLimit.window||60000},
209
+ perChannel: ${t.rateLimit.perChannel!==!1},
210
+ perUser: ${t.rateLimit.perUser!==!1},
208
211
  },
209
212
  `:""}
210
- ${M.loadManagement?.enabled?`
213
+ ${t.loadManagement?.enabled?`
211
214
  loadManagement: {
212
215
  enabled: true,
213
- maxConnections: ${M.loadManagement.maxConnections||1e4},
214
- maxSubscriptionsPerConnection: ${M.loadManagement.maxSubscriptionsPerConnection||100},
215
- shedLoadThreshold: ${M.loadManagement.shedLoadThreshold||0.8},
216
+ maxConnections: ${t.loadManagement.maxConnections||1e4},
217
+ maxSubscriptionsPerConnection: ${t.loadManagement.maxSubscriptionsPerConnection||100},
218
+ shedLoadThreshold: ${t.loadManagement.shedLoadThreshold||0.8},
216
219
  },
217
220
  `:""}
218
221
  } satisfies BroadcastConfig
219
- `}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function c0($){let M=[],J=[];if(!$.AWSTemplateFormatVersion)M.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if($.AWSTemplateFormatVersion!=="2010-09-09")J.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!$.Resources||Object.keys($.Resources).length===0)M.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[X,W]of Object.entries($.Resources))u0(X,W,M,J);if($.Resources){let X=r0($.Resources);if(X.length>0)M.push({path:"Resources",message:`Circular dependencies detected: ${X.join(" -> ")}`,severity:"error"})}if($.Parameters)for(let[X,W]of Object.entries($.Parameters))d0(X,W,M,J);if($.Outputs)for(let[X,W]of Object.entries($.Outputs))t0(X,W,M,J);return{valid:M.length===0,errors:M,warnings:J}}function u0($,M,J,X){if(!M.Type)J.push({path:`Resources.${$}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test($))X.push({path:`Resources.${$}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(M.Type&&!M.Type.startsWith("AWS::")&&!M.Type.startsWith("Custom::"))J.push({path:`Resources.${$}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(M.Properties){for(let[W,F]of Object.entries(M.Properties))if(F===void 0||F===null)X.push({path:`Resources.${$}.Properties.${W}`,message:"Property has undefined or null value",severity:"warning"})}if(M.DependsOn){if(typeof M.DependsOn==="string"){if(M.DependsOn===$)J.push({path:`Resources.${$}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(M.DependsOn)){if(M.DependsOn.includes($))J.push({path:`Resources.${$}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function d0($,M,J,X){if(!M.Type)J.push({path:`Parameters.${$}.Type`,message:"Parameter Type is required",severity:"error"});let W=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(M.Type&&!W.includes(M.Type)&&!M.Type.startsWith("AWS::"))X.push({path:`Parameters.${$}.Type`,message:`Uncommon parameter type: ${M.Type}`,severity:"warning"});if(M.NoEcho&&M.Default)X.push({path:`Parameters.${$}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function t0($,M,J,X){if(!M.Value)J.push({path:`Outputs.${$}.Value`,message:"Output Value is required",severity:"error"})}function r0($){let M={};for(let[Q,_]of Object.entries($)){if(M[Q]=[],_.DependsOn){if(typeof _.DependsOn==="string")M[Q].push(_.DependsOn);else if(Array.isArray(_.DependsOn))M[Q].push(..._.DependsOn)}let K=J0(_);M[Q].push(...K)}let J=new Set,X=new Set,W=[];function F(Q,_){J.add(Q),X.add(Q),_.push(Q);let K=M[Q]||[];for(let O of K)if(!J.has(O)){if(F(O,_))return!0}else if(X.has(O)){let H=_.indexOf(O);return W.push(..._.slice(H),O),!0}return _.pop(),X.delete(Q),!1}for(let Q of Object.keys(M))if(!J.has(Q)){if(F(Q,[]))return W}return[]}function J0($,M=[]){if(typeof $!=="object"||$===null)return M;if(Array.isArray($)){for(let J of $)J0(J,M);return M}if($.Ref&&typeof $.Ref==="string"&&!$.Ref.startsWith("AWS::"))M.push($.Ref);if($["Fn::GetAtt"]){let J=$["Fn::GetAtt"];if(Array.isArray(J)&&J.length>0)M.push(J[0])}for(let J of Object.values($))J0(J,M);return M}function l0($){let M=[],J=[],X=new TextEncoder().encode($).length,W=51200,F=460800;if(X>51200)if(X>460800)M.push({path:"template",message:`Template size (${X} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else J.push({path:"template",message:`Template size (${X} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:M.length===0,errors:M,warnings:J}}function g0($){let M=[],J=[],X=$.Resources?Object.keys($.Resources).length:0,W=$.Parameters?Object.keys($.Parameters).length:0,F=$.Outputs?Object.keys($.Outputs).length:0;if(X>500)M.push({path:"Resources",message:`Template has ${X} resources, exceeding the limit of 500`,severity:"error"});else if(X>200)J.push({path:"Resources",message:`Template has ${X} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(W>200)M.push({path:"Parameters",message:`Template has ${W} parameters, exceeding the limit of 200`,severity:"error"});if(F>200)M.push({path:"Outputs",message:`Template has ${F} outputs, exceeding the limit of 200`,severity:"error"});return{valid:M.length===0,errors:M,warnings:J}}function m8($){let{domains:M,email:J,staging:X=!1,challengeType:W="http-01",certPath:F="/etc/letsencrypt/live",autoRenew:Q=!0}=$,_=M[0],K=M.map((H)=>`-d ${H}`).join(" "),O=X?"--staging":"";if(W==="http-01")return i0({domains:M,email:J,staging:X,certPath:F,autoRenew:Q,domainFlags:K,stagingFlag:O,primaryDomain:_});else{let H=$.dnsProvider?.provider||($.hostedZoneId?"route53":void 0);return o0({domains:M,email:J,staging:X,certPath:F,autoRenew:Q,domainFlags:K,stagingFlag:O,primaryDomain:_,hostedZoneId:$.hostedZoneId,dnsProvider:$.dnsProvider,dnsProviderType:H})}}function i0($){let{email:M,certPath:J,autoRenew:X,domainFlags:W,stagingFlag:F,primaryDomain:Q}=$;return`
222
+ `}toYAML(){return this.builder.toYAML()}toJSON(){return this.builder.toJSON()}getBuilder(){return this.builder}}function He(e){let t=[],r=[];if(!e.AWSTemplateFormatVersion)t.push({path:"AWSTemplateFormatVersion",message:"AWSTemplateFormatVersion is required",severity:"error"});else if(e.AWSTemplateFormatVersion!=="2010-09-09")r.push({path:"AWSTemplateFormatVersion",message:'AWSTemplateFormatVersion should be "2010-09-09"',severity:"warning"});if(!e.Resources||Object.keys(e.Resources).length===0)t.push({path:"Resources",message:"At least one resource is required",severity:"error"});else for(let[n,i]of Object.entries(e.Resources))Ge(n,i,t,r);if(e.Resources){let n=Ze(e.Resources);if(n.length>0)t.push({path:"Resources",message:`Circular dependencies detected: ${n.join(" -> ")}`,severity:"error"})}if(e.Parameters)for(let[n,i]of Object.entries(e.Parameters))Ke(n,i,t,r);if(e.Outputs)for(let[n,i]of Object.entries(e.Outputs))Ue(n,i,t,r);return{valid:t.length===0,errors:t,warnings:r}}function Ge(e,t,r,n){if(!t.Type)r.push({path:`Resources.${e}.Type`,message:"Resource Type is required",severity:"error"});if(!/^[a-zA-Z0-9]+$/.test(e))n.push({path:`Resources.${e}`,message:"Logical ID should only contain alphanumeric characters",severity:"warning"});if(t.Type&&!t.Type.startsWith("AWS::")&&!t.Type.startsWith("Custom::"))r.push({path:`Resources.${e}.Type`,message:'Resource Type must start with "AWS::" or "Custom::"',severity:"error"});if(t.Properties){for(let[i,l]of Object.entries(t.Properties))if(l===void 0||l===null)n.push({path:`Resources.${e}.Properties.${i}`,message:"Property has undefined or null value",severity:"warning"})}if(t.DependsOn){if(typeof t.DependsOn==="string"){if(t.DependsOn===e)r.push({path:`Resources.${e}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}else if(Array.isArray(t.DependsOn)){if(t.DependsOn.includes(e))r.push({path:`Resources.${e}.DependsOn`,message:"Resource cannot depend on itself",severity:"error"})}}}function Ke(e,t,r,n){if(!t.Type)r.push({path:`Parameters.${e}.Type`,message:"Parameter Type is required",severity:"error"});let i=["String","Number","List<Number>","CommaDelimitedList","AWS::SSM::Parameter::Value<String>"];if(t.Type&&!i.includes(t.Type)&&!t.Type.startsWith("AWS::"))n.push({path:`Parameters.${e}.Type`,message:`Uncommon parameter type: ${t.Type}`,severity:"warning"});if(t.NoEcho&&t.Default)n.push({path:`Parameters.${e}`,message:"NoEcho parameters should not have default values",severity:"warning"})}function Ue(e,t,r,n){if(!t.Value)r.push({path:`Outputs.${e}.Value`,message:"Output Value is required",severity:"error"})}function Ze(e){let t={};for(let[c,s]of Object.entries(e)){if(t[c]=[],s.DependsOn){if(typeof s.DependsOn==="string")t[c].push(s.DependsOn);else if(Array.isArray(s.DependsOn))t[c].push(...s.DependsOn)}let d=ne(s);t[c].push(...d)}let r=new Set,n=new Set,i=[];function l(c,s){r.add(c),n.add(c),s.push(c);let d=t[c]||[];for(let h of d)if(!r.has(h)){if(l(h,s))return!0}else if(n.has(h)){let u=s.indexOf(h);return i.push(...s.slice(u),h),!0}return s.pop(),n.delete(c),!1}for(let c of Object.keys(t))if(!r.has(c)){if(l(c,[]))return i}return[]}function ne(e,t=[]){if(typeof e!=="object"||e===null)return t;if(Array.isArray(e)){for(let r of e)ne(r,t);return t}if(e.Ref&&typeof e.Ref==="string"&&!e.Ref.startsWith("AWS::"))t.push(e.Ref);if(e["Fn::GetAtt"]){let r=e["Fn::GetAtt"];if(Array.isArray(r)&&r.length>0)t.push(r[0])}for(let r of Object.values(e))ne(r,t);return t}function qe(e){let t=[],r=[],n=new TextEncoder().encode(e).length,i=51200,l=460800;if(n>51200)if(n>460800)t.push({path:"template",message:`Template size (${n} bytes) exceeds maximum allowed size of 460800 bytes`,severity:"error"});else r.push({path:"template",message:`Template size (${n} bytes) exceeds direct upload limit (51200 bytes). You must upload to S3 first.`,severity:"warning"});return{valid:t.length===0,errors:t,warnings:r}}function je(e){let t=[],r=[],n=e.Resources?Object.keys(e.Resources).length:0,i=e.Parameters?Object.keys(e.Parameters).length:0,l=e.Outputs?Object.keys(e.Outputs).length:0;if(n>500)t.push({path:"Resources",message:`Template has ${n} resources, exceeding the limit of 500`,severity:"error"});else if(n>200)r.push({path:"Resources",message:`Template has ${n} resources. Consider using nested stacks for better organization.`,severity:"warning"});if(i>200)t.push({path:"Parameters",message:`Template has ${i} parameters, exceeding the limit of 200`,severity:"error"});if(l>200)t.push({path:"Outputs",message:`Template has ${l} outputs, exceeding the limit of 200`,severity:"error"});return{valid:t.length===0,errors:t,warnings:r}}function Zi(e){let{domains:t,email:r,staging:n=!1,challengeType:i="http-01",certPath:l="/etc/letsencrypt/live",autoRenew:c=!0}=e,s=t[0],d=t.map((u)=>`-d ${u}`).join(" "),h=n?"--staging":"";if(i==="http-01")return Ye({domains:t,email:r,staging:n,certPath:l,autoRenew:c,domainFlags:d,stagingFlag:h,primaryDomain:s});else{let u=e.dnsProvider?.provider||(e.hostedZoneId?"route53":void 0);return Qe({domains:t,email:r,staging:n,certPath:l,autoRenew:c,domainFlags:d,stagingFlag:h,primaryDomain:s,hostedZoneId:e.hostedZoneId,dnsProvider:e.dnsProvider,dnsProviderType:u})}}function Ye(e){let{email:t,certPath:r,autoRenew:n,domainFlags:i,stagingFlag:l,primaryDomain:c}=e;return`
220
223
  # ==========================================
221
224
  # Let's Encrypt Certificate Setup (HTTP-01)
222
225
  # ==========================================
@@ -232,29 +235,29 @@ certbot certonly \\
232
235
  --standalone \\
233
236
  --non-interactive \\
234
237
  --agree-tos \\
235
- --email ${M} \\
236
- ${F} \\
237
- ${W}
238
+ --email ${t} \\
239
+ ${l} \\
240
+ ${i}
238
241
 
239
242
  # Check if certificate was obtained
240
- if [ -f "${J}/${Q}/fullchain.pem" ]; then
243
+ if [ -f "${r}/${c}/fullchain.pem" ]; then
241
244
  echo "Certificate obtained successfully!"
242
245
 
243
246
  # Create symlinks for easier access
244
247
  mkdir -p /etc/ssl/stacks
245
- ln -sf ${J}/${Q}/fullchain.pem /etc/ssl/stacks/fullchain.pem
246
- ln -sf ${J}/${Q}/privkey.pem /etc/ssl/stacks/privkey.pem
247
- ln -sf ${J}/${Q}/cert.pem /etc/ssl/stacks/cert.pem
248
- ln -sf ${J}/${Q}/chain.pem /etc/ssl/stacks/chain.pem
248
+ ln -sf ${r}/${c}/fullchain.pem /etc/ssl/stacks/fullchain.pem
249
+ ln -sf ${r}/${c}/privkey.pem /etc/ssl/stacks/privkey.pem
250
+ ln -sf ${r}/${c}/cert.pem /etc/ssl/stacks/cert.pem
251
+ ln -sf ${r}/${c}/chain.pem /etc/ssl/stacks/chain.pem
249
252
  else
250
253
  echo "Failed to obtain certificate!"
251
254
  fi
252
255
 
253
- ${X?X0(Q):"# Auto-renewal disabled"}
256
+ ${n?ie(c):"# Auto-renewal disabled"}
254
257
 
255
258
  # Restart the application
256
259
  systemctl start stacks
257
- `}function o0($){let{email:M,certPath:J,autoRenew:X,domainFlags:W,stagingFlag:F,primaryDomain:Q,hostedZoneId:_,dnsProvider:K,dnsProviderType:O}=$;if(O==="route53"||_){if(!_)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
260
+ `}function Qe(e){let{email:t,certPath:r,autoRenew:n,domainFlags:i,stagingFlag:l,primaryDomain:c,hostedZoneId:s,dnsProvider:d,dnsProviderType:h}=e;if(h==="route53"||s){if(!s)throw Error("hostedZoneId is required for DNS-01 challenge with Route53");return`
258
261
  # ==========================================
259
262
  # Let's Encrypt Certificate Setup (DNS-01 via Route53)
260
263
  # ==========================================
@@ -267,49 +270,49 @@ certbot certonly \\
267
270
  --dns-route53 \\
268
271
  --non-interactive \\
269
272
  --agree-tos \\
270
- --email ${M} \\
271
- ${F} \\
272
- ${W}
273
+ --email ${t} \\
274
+ ${l} \\
275
+ ${i}
273
276
 
274
277
  # Check if certificate was obtained
275
- if [ -f "${J}/${Q}/fullchain.pem" ]; then
278
+ if [ -f "${r}/${c}/fullchain.pem" ]; then
276
279
  echo "Certificate obtained successfully!"
277
280
 
278
281
  # Create symlinks for easier access
279
282
  mkdir -p /etc/ssl/stacks
280
- ln -sf ${J}/${Q}/fullchain.pem /etc/ssl/stacks/fullchain.pem
281
- ln -sf ${J}/${Q}/privkey.pem /etc/ssl/stacks/privkey.pem
282
- ln -sf ${J}/${Q}/cert.pem /etc/ssl/stacks/cert.pem
283
- ln -sf ${J}/${Q}/chain.pem /etc/ssl/stacks/chain.pem
283
+ ln -sf ${r}/${c}/fullchain.pem /etc/ssl/stacks/fullchain.pem
284
+ ln -sf ${r}/${c}/privkey.pem /etc/ssl/stacks/privkey.pem
285
+ ln -sf ${r}/${c}/cert.pem /etc/ssl/stacks/cert.pem
286
+ ln -sf ${r}/${c}/chain.pem /etc/ssl/stacks/chain.pem
284
287
  else
285
288
  echo "Failed to obtain certificate!"
286
289
  fi
287
290
 
288
- ${X?X0(Q):"# Auto-renewal disabled"}
289
- `}if(!K)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let H=K.provider.toUpperCase(),R=s0(K);return`
291
+ ${n?ie(c):"# Auto-renewal disabled"}
292
+ `}if(!d)throw Error("dnsProvider configuration is required for DNS-01 challenge with external DNS providers");let u=d.provider.toUpperCase(),b=Xe(d);return`
290
293
  # ==========================================
291
- # Let's Encrypt Certificate Setup (DNS-01 via ${H})
294
+ # Let's Encrypt Certificate Setup (DNS-01 via ${u})
292
295
  # ==========================================
293
296
 
294
297
  # Install certbot
295
298
  dnf install -y certbot jq curl
296
299
 
297
- ${R}
300
+ ${b}
298
301
 
299
302
  # Create DNS challenge hook scripts directory
300
303
  mkdir -p /etc/letsencrypt/hooks
301
304
 
302
- # Create authenticator hook for ${H}
305
+ # Create authenticator hook for ${u}
303
306
  cat > /etc/letsencrypt/hooks/auth-hook.sh << 'AUTHHOOK'
304
307
  #!/bin/bash
305
- # DNS-01 authenticator hook for ${H}
308
+ # DNS-01 authenticator hook for ${u}
306
309
  # This creates the TXT record for ACME challenge
307
310
 
308
311
  DOMAIN="$CERTBOT_DOMAIN"
309
312
  VALIDATION="$CERTBOT_VALIDATION"
310
313
  RECORD_NAME="_acme-challenge.$DOMAIN"
311
314
 
312
- ${n0(K)}
315
+ ${et(d)}
313
316
 
314
317
  # Wait for DNS propagation
315
318
  echo "Waiting 60 seconds for DNS propagation..."
@@ -318,17 +321,17 @@ AUTHHOOK
318
321
 
319
322
  chmod +x /etc/letsencrypt/hooks/auth-hook.sh
320
323
 
321
- # Create cleanup hook for ${H}
324
+ # Create cleanup hook for ${u}
322
325
  cat > /etc/letsencrypt/hooks/cleanup-hook.sh << 'CLEANUPHOOK'
323
326
  #!/bin/bash
324
- # DNS-01 cleanup hook for ${H}
327
+ # DNS-01 cleanup hook for ${u}
325
328
  # This removes the TXT record after validation
326
329
 
327
330
  DOMAIN="$CERTBOT_DOMAIN"
328
331
  VALIDATION="$CERTBOT_VALIDATION"
329
332
  RECORD_NAME="_acme-challenge.$DOMAIN"
330
333
 
331
- ${e0(K)}
334
+ ${tt(d)}
332
335
  CLEANUPHOOK
333
336
 
334
337
  chmod +x /etc/letsencrypt/hooks/cleanup-hook.sh
@@ -341,37 +344,37 @@ certbot certonly \\
341
344
  --manual-cleanup-hook /etc/letsencrypt/hooks/cleanup-hook.sh \\
342
345
  --non-interactive \\
343
346
  --agree-tos \\
344
- --email ${M} \\
345
- ${F} \\
346
- ${W}
347
+ --email ${t} \\
348
+ ${l} \\
349
+ ${i}
347
350
 
348
351
  # Check if certificate was obtained
349
- if [ -f "${J}/${Q}/fullchain.pem" ]; then
352
+ if [ -f "${r}/${c}/fullchain.pem" ]; then
350
353
  echo "Certificate obtained successfully!"
351
354
 
352
355
  # Create symlinks for easier access
353
356
  mkdir -p /etc/ssl/stacks
354
- ln -sf ${J}/${Q}/fullchain.pem /etc/ssl/stacks/fullchain.pem
355
- ln -sf ${J}/${Q}/privkey.pem /etc/ssl/stacks/privkey.pem
356
- ln -sf ${J}/${Q}/cert.pem /etc/ssl/stacks/cert.pem
357
- ln -sf ${J}/${Q}/chain.pem /etc/ssl/stacks/chain.pem
357
+ ln -sf ${r}/${c}/fullchain.pem /etc/ssl/stacks/fullchain.pem
358
+ ln -sf ${r}/${c}/privkey.pem /etc/ssl/stacks/privkey.pem
359
+ ln -sf ${r}/${c}/cert.pem /etc/ssl/stacks/cert.pem
360
+ ln -sf ${r}/${c}/chain.pem /etc/ssl/stacks/chain.pem
358
361
  else
359
362
  echo "Failed to obtain certificate!"
360
363
  fi
361
364
 
362
- ${X?X0(Q):"# Auto-renewal disabled"}
363
- `}function s0($){switch($.provider){case"porkbun":return`
365
+ ${n?ie(c):"# Auto-renewal disabled"}
366
+ `}function Xe(e){switch(e.provider){case"porkbun":return`
364
367
  # Porkbun API credentials
365
- export PORKBUN_API_KEY="${$.apiKey}"
366
- export PORKBUN_SECRET_KEY="${$.secretKey}"
368
+ export PORKBUN_API_KEY="${e.apiKey}"
369
+ export PORKBUN_SECRET_KEY="${e.secretKey}"
367
370
  `;case"godaddy":return`
368
371
  # GoDaddy API credentials
369
- export GODADDY_API_KEY="${$.apiKey}"
370
- export GODADDY_API_SECRET="${$.apiSecret}"
371
- export GODADDY_ENV="${$.environment||"production"}"
372
+ export GODADDY_API_KEY="${e.apiKey}"
373
+ export GODADDY_API_SECRET="${e.apiSecret}"
374
+ export GODADDY_ENV="${e.environment||"production"}"
372
375
  `;case"route53":return`
373
376
  # Route53 uses IAM role credentials
374
- `;default:return""}}function n0($){switch($.provider){case"porkbun":return`
377
+ `;default:return""}}function et(e){switch(e.provider){case"porkbun":return`
375
378
  # Extract root domain (last two parts)
376
379
  ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
377
380
  SUBDOMAIN="_acme-challenge"
@@ -415,7 +418,7 @@ curl -s -X PATCH "$API_URL/v1/domains/$ROOT_DOMAIN/records" \\
415
418
  "data": "'"$VALIDATION"'",
416
419
  "ttl": 600
417
420
  }]'
418
- `;default:return'echo "Unsupported DNS provider"'}}function e0($){switch($.provider){case"porkbun":return`
421
+ `;default:return'echo "Unsupported DNS provider"'}}function tt(e){switch(e.provider){case"porkbun":return`
419
422
  # Extract root domain
420
423
  ROOT_DOMAIN=$(echo "$DOMAIN" | awk -F. '{print $(NF-1)"."$NF}')
421
424
 
@@ -458,7 +461,7 @@ fi
458
461
 
459
462
  curl -s -X DELETE "$API_URL/v1/domains/$ROOT_DOMAIN/records/TXT/$RECORD_NAME" \\
460
463
  -H "Authorization: sso-key $GODADDY_API_KEY:$GODADDY_API_SECRET"
461
- `;default:return'echo "Unsupported DNS provider"'}}function X0($){return`
464
+ `;default:return'echo "Unsupported DNS provider"'}}function ie(e){return`
462
465
  # ==========================================
463
466
  # Certificate Auto-Renewal Setup
464
467
  # ==========================================
@@ -503,13 +506,13 @@ systemctl enable certbot-renewal.timer
503
506
  systemctl start certbot-renewal.timer
504
507
 
505
508
  echo "Certificate auto-renewal configured"
506
- `}function v8($){let{httpPort:M=80,httpsPort:J=443,certPath:X="/etc/ssl/stacks",redirectHttp:W=!0}=$;return`
509
+ `}function qi(e){let{httpPort:t=80,httpsPort:r=443,certPath:n="/etc/ssl/stacks",redirectHttp:i=!0}=e;return`
507
510
  // HTTPS Server with Let's Encrypt certificates
508
511
  import { readFileSync, existsSync } from 'node:fs'
509
512
 
510
- const CERT_PATH = '${X}'
511
- const HTTP_PORT = ${M}
512
- const HTTPS_PORT = ${J}
513
+ const CERT_PATH = '${n}'
514
+ const HTTP_PORT = ${t}
515
+ const HTTPS_PORT = ${r}
513
516
 
514
517
  // Check if certificates exist
515
518
  const hasCerts = existsSync(\`\${CERT_PATH}/fullchain.pem\`) && existsSync(\`\${CERT_PATH}/privkey.pem\`)
@@ -529,7 +532,7 @@ if (hasCerts) {
529
532
  })
530
533
  console.log(\`HTTPS server running on port \${HTTPS_PORT}\`)
531
534
 
532
- ${W?`
535
+ ${i?`
533
536
  // Start HTTP server for redirect
534
537
  const httpServer = Bun.serve({
535
538
  port: HTTP_PORT,
@@ -589,5 +592,5 @@ async function handleRequest(request: Request): Promise<Response> {
589
592
  // Implement your request handling here
590
593
  return new Response('Hello from Stacks!')
591
594
  }
592
- `}async function c8($){let{domain:M,challengeValue:J,hostedZoneId:X,dnsProvider:W,region:F="us-east-1"}=$;if(W){let _=await a(W).upsertRecord(M,{name:`_acme-challenge.${M}`,type:"TXT",content:J,ttl:60});if(!_.success)throw Error(`Failed to create DNS challenge record: ${_.message}`);return}if(X){await new g(F).changeResourceRecordSets({HostedZoneId:X,ChangeBatch:{Comment:"ACME DNS-01 challenge",Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:`_acme-challenge.${M}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${J}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}async function u8($){let{domain:M,challengeValue:J,hostedZoneId:X,dnsProvider:W,region:F="us-east-1"}=$;if(W){let _=await a(W).deleteRecord(M,{name:`_acme-challenge.${M}`,type:"TXT",content:J});if(!_.success)console.warn(`Failed to delete DNS challenge record: ${_.message}`);return}if(X){await new g(F).changeResourceRecordSets({HostedZoneId:X,ChangeBatch:{Comment:"Remove ACME DNS-01 challenge",Changes:[{Action:"DELETE",ResourceRecordSet:{Name:`_acme-challenge.${M}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${J}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}function d8($){try{let{execSync:M}=a0("node:child_process"),J=M(`openssl x509 -checkend 2592000 -noout -in ${$}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as T0,createSign as $$,generateKeyPairSync as B0}from"node:crypto";var D0={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class M${directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor($){this.directoryUrl=$.staging?D0.staging:D0.production,this.email=$.email,this.accountKey=$.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:$}=B0("ec",{namedCurve:"P-256"});return $.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let $=await fetch(this.directoryUrl);if(!$.ok)throw Error(`Failed to fetch ACME directory: ${$.status}`);return this.directory=await $.json(),this.directory}async getNonce(){if(this.nonce){let X=this.nonce;return this.nonce=null,X}let $=await this.getDirectory(),J=(await fetch($.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!J)throw Error("Failed to get nonce from ACME server");return J}getJwk(){let $=this.accountKey.split(`
593
- `).filter((F)=>!F.startsWith("-----")).join(""),M=Buffer.from($,"base64"),J=M.length-65,X=M.subarray(J+1,J+33),W=M.subarray(J+33,J+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(X),y:this.base64UrlEncode(W)}}getJwkThumbprint(){let $=this.getJwk(),M=JSON.stringify({crv:$.crv,kty:$.kty,x:$.x,y:$.y}),J=T0("sha256").update(M).digest();return this.base64UrlEncode(J)}base64UrlEncode($){return(typeof $==="string"?Buffer.from($):$).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload($,M){let J=await this.getNonce(),X=this.getJwk(),W={alg:"ES256",nonce:J,url:$};if(this.accountUrl)W.kid=this.accountUrl;else W.jwk=X;let F=this.base64UrlEncode(JSON.stringify(W)),Q=M===""?"":this.base64UrlEncode(JSON.stringify(M)),_=`${F}.${Q}`,K=$$("SHA256");K.update(_);let O=K.sign(this.accountKey),H=O.subarray(4,4+O[3]),R=4+O[3]+2,z=O.subarray(R,R+O[R-1]),q=Buffer.alloc(32),A=Buffer.alloc(32);H.copy(q,32-H.length),z.copy(A,32-z.length);let G=Buffer.concat([q,A]);return JSON.stringify({protected:F,payload:Q,signature:this.base64UrlEncode(G)})}async acmeRequest($,M){let J=await this.signPayload($,M),X=await fetch($,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:J}),W=X.headers.get("replay-nonce");if(W)this.nonce=W;let F,Q=X.headers.get("content-type");if(Q?.includes("application/json")||Q?.includes("application/problem+json"))F=await X.json();else F=await X.text();if(!X.ok)throw Error(`ACME request failed: ${JSON.stringify(F)}`);return{body:F,headers:X.headers}}async registerAccount(){let $=await this.getDirectory(),{body:M,headers:J}=await this.acmeRequest($.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),X=J.get("location");if(!X)throw Error("No account URL returned");return this.accountUrl=X,X}async createOrder($){if(!this.accountUrl)await this.registerAccount();let M=await this.getDirectory(),{body:J,headers:X}=await this.acmeRequest(M.newOrder,{identifiers:$.map((F)=>({type:"dns",value:F}))}),W=X.get("location");if(!W)throw Error("No order URL returned");return{orderUrl:W,authorizations:J.authorizations,finalize:J.finalize}}async getAuthorization($){let{body:M}=await this.acmeRequest($,""),J=M.identifier.value,X=this.getJwkThumbprint(),W=M.challenges.filter((F)=>F.type==="http-01"||F.type==="dns-01").map((F)=>{let Q=`${F.token}.${X}`;if(F.type==="http-01")return{type:"http-01",token:F.token,keyAuthorization:Q,identifier:`/.well-known/acme-challenge/${F.token}`};else{let _=this.base64UrlEncode(T0("sha256").update(Q).digest());return{type:"dns-01",token:F.token,keyAuthorization:Q,identifier:`_acme-challenge.${J}`,dnsValue:_}}});return{domain:J,challenges:W}}async respondToChallenge($){await this.acmeRequest($,{})}async waitForAuthorization($,M=30){for(let J=0;J<M;J++){let{body:X}=await this.acmeRequest($,"");if(X.status==="valid")return;if(X.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(X)}`);await new Promise((W)=>setTimeout(W,2000))}throw Error("Authorization timed out")}generateCsr($){let{privateKey:M}=B0("rsa",{modulusLength:2048}),J=M.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr($,M),privateKey:J}}createSimpleCsr($,M){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder($,M){let{csr:J,privateKey:X}=this.generateCsr(M),{body:W}=await this.acmeRequest($,{csr:this.base64UrlEncode(Buffer.from(J,"base64"))}),F=W.certificate;if(!F)throw Error("Certificate not immediately available - polling not implemented");let _=await(await fetch(F)).text(),K=_.split(/(?=-----BEGIN CERTIFICATE-----)/g),O=K[0],H=K.slice(1).join("");return{certificate:O,privateKey:X,chain:H,fullchain:_,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var k0=["js","mjs","cjs","css","map","woff","woff2","ttf","otf","eot","png","jpg","jpeg","gif","webp","avif","svg","ico","mp4","webm","ogg","mp3","wav","pdf","wasm"];function Y0($){return`"${$.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`}function L0($){return`{${$.map(Y0).join(" ")}}`}function W0($){if($.length===1)return`http.host eq ${Y0($[0])}`;return`http.host in ${L0($)}`}function U0($,M={}){if(M.enabled===!1||$.length===0)return[];let J=W0($),X=[],W=M.bypassPaths??[],F=W.length>0?`(${W.map((O)=>`starts_with(http.request.uri.path, ${Y0(O)})`).join(" or ")})`:void 0;if(F)X.push({action:"set_cache_settings",description:"bypass cache",expression:`(${J} and ${F})`,enabled:!0,action_parameters:{cache:!1}});let Q=F?`${J} and not ${F}`:J,_=M.assetExtensions??k0,K=_.length>0?`lower(http.request.uri.path.extension) in ${L0([..._])}`:void 0;if(K)X.push({action:"set_cache_settings",description:"cache fingerprinted assets",expression:`(${Q} and ${K})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:M.assetEdgeTtl??2592000},browser_ttl:{mode:"override_origin",default:M.assetBrowserTtl??31536000}}});return X.push({action:"set_cache_settings",description:"cache documents",expression:K?`(${Q} and not ${K})`:`(${Q})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:M.documentEdgeTtl??3600},browser_ttl:{mode:"override_origin",default:M.documentBrowserTtl??0}}}),X}function _0($,M,J){if($.length===0||!M||!J)return[];return[{action:"rewrite",description:"origin guard header",expression:`(${W0($)})`,enabled:!0,action_parameters:{headers:{[M]:{operation:"set",value:J}}}}]}var y=($)=>$===void 0?void 0:$?"on":"off";function Q0($){let M={ssl:$.ssl,always_use_https:y($.alwaysUseHttps),automatic_https_rewrites:y($.automaticHttpsRewrites),min_tls_version:$.minTlsVersion,tls_1_3:y($.tls13),brotli:y($.brotli),http3:y($.http3),"0rtt":y($.zeroRtt),early_hints:y($.earlyHints),browser_cache_ttl:$.browserCacheTtl,always_online:y($.alwaysOnline),websockets:y($.websockets)};if($.hsts)M.security_header={strict_transport_security:{enabled:$.hsts.enabled,max_age:$.hsts.maxAge??31536000,include_subdomains:$.hsts.includeSubdomains??!1,preload:$.hsts.preload??!1,nosniff:$.hsts.noSniff??!0}};for(let J of Object.keys(M))if(M[J]===void 0)delete M[J];return{...M,...$.raw??{}}}var v={ssl:"strict",alwaysUseHttps:!0,automaticHttpsRewrites:!0,minTlsVersion:"1.2",tls13:!0,brotli:!0,http3:!0,earlyHints:!0,alwaysOnline:!0,browserCacheTtl:0};import{connect as J$}from"node:tls";async function F0($){let{address:M,serverName:J,port:X=443,timeoutMs:W=5000}=$;return new Promise((F)=>{let Q=!1,_=(O)=>{if(Q)return;Q=!0;try{K.destroy()}catch{}F(O)},K=J$({host:M,port:X,servername:J,rejectUnauthorized:!1,timeout:W});K.once("secureConnect",()=>{if(K.authorized){_({reachable:!0,trusted:!0});return}_({reachable:!0,trusted:!1,reason:K.authorizationError?String(K.authorizationError):"origin certificate is not trusted for this hostname"})}),K.once("timeout",()=>{_({reachable:!1,trusted:!1,reason:`no TLS handshake within ${W}ms`})}),K.once("error",(O)=>{_({reachable:!1,trusted:!1,reason:O.message})})})}async function X$($){let{provider:M,zone:J,hosts:X,ipv4:W,ipv6:F,proxied:Q=!0,settings:_=v,cache:K,originGuard:O,purge:H=!0,ttl:R=300,skipOriginProbe:z=!1}=$,q={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(X.length===0)return q;let A=[];for(let Y of X){let V=Q;if(Q&&!z){let x=await F0({address:W,serverName:Y});if(!x.trusted){V=!1;let E=x.reason||"origin is not serving a trusted certificate";q.deferredProxy.push({host:Y,reason:E}),q.warnings.push(`${Y}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${E}). 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(V)A.push(Y);let U=[{type:"A",content:W}];if(F&&K0(Y))U.push({type:"AAAA",content:F});for(let{type:x,content:E}of U){let Z=await M.upsertRecord(J,{name:Y,type:x,content:E,ttl:R,proxied:V});if(Z.success)q.records.push({host:Y,type:x,content:E,proxied:V});else q.warnings.push(`${Y} ${x} → ${E} failed: ${Z.message||"unknown provider error"}`)}}if(A.length===0){if(Q)q.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return q}try{let Y=Q0(_),V=await M.applyZoneSettings(J,Y);q.settingsChanged=V.changed;for(let U of V.failed)q.warnings.push(`zone setting '${U.id}' could not be applied: ${U.error}`)}catch(Y){q.warnings.push(`zone settings could not be read: ${Y instanceof Error?Y.message:String(Y)}`)}let G=U0(A,K);if(G.length>0){let Y=await M.putManagedPhaseRules(J,"http_request_cache_settings",G);if(Y.success)q.cacheRules=G.length;else q.warnings.push(`cache rules could not be written: ${Y.message}`)}if(O){let Y=_0(A,O.header,O.value);if(Y.length>0){let V=await M.putManagedPhaseRules(J,"http_request_late_transform",Y);if(V.success)q.originGuard=!0;else q.warnings.push(`origin guard header could not be written: ${V.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(H){if(q.purged=await M.purgeCache(J,{hosts:A}),!q.purged)q.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return q}var Y$=($)=>process.env[$];function y0($,M){let J=$.replace(/\.$/,"").toLowerCase();if(M){let X=M.replace(/\.$/,"").toLowerCase();if(J===X||J.endsWith(`.${X}`))return X}return J.split(".").slice(-2).join(".")}function W$($,M={}){let J=M.env??Y$,X=$.infrastructure?.compute?.proxy?.cdn,W=[];if(!X||X.provider!=="cloudflare")return{plan:null,errors:W};if(X.originDomain)W.push(`compute.proxy.cdn.originDomain (${X.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 F=J("CLOUDFLARE_API_TOKEN");if(!F)return W.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:W};let Q=$.sites??{},_=X.frontedHosts?.length?[...new Set(X.frontedHosts.map((z)=>z.toLowerCase()))]:H0(Q,{autoWww:$.infrastructure?.compute?.proxy?.autoWww!==!1});if(_.length===0)return W.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:W};let K=$.infrastructure?.dns?.domain,O=new Set(_.map((z)=>y0(z,K)));if(O.size>1)return W.push(`Fronted hosts span more than one zone (${[...O].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:W};let H=X.cloudflare??{},R=X.secret?{header:X.secretHeader??"X-Origin-Verify",value:X.secret}:void 0;return{plan:{zone:[...O][0],hosts:_,apiToken:F,zoneId:H.zoneId??J("CLOUDFLARE_ZONE_ID"),accountId:H.accountId??J("CLOUDFLARE_ACCOUNT_ID"),proxied:H.proxied!==!1,settings:H.settings??v,cache:H.cache,originGuard:R,purge:H.purgeOnDeploy!==!1,skipOriginProbe:H.skipOriginProbe===!0},errors:W}}export{pU as zonedParts,mU as zoneOffsetMs,b_ as zeroFill,aF as zeroCapacity,HY as xrayManager,K3 as wrapCloudInitUserData,g9 as withTimeout,a1 as withSecurity,n1 as withQueue,g1 as withMonitoring,s2 as withInvocation,i1 as withDatabase,o1 as withCache,s1 as withCDN,AU as webhookEndpoint,R3 as waitForSsh,z3 as waitForCloudInit,Y3 as wafEventTelemetry,v5 as volumeCapabilities,VK as verifyUpdateSignature,yW as verifyTotp,S8 as verifyMediaAccessToken,hQ as verifyArtifactSignature,r6 as verifyAddressRecord,l0 as validateTemplateSize,c0 as validateTemplate,g0 as validateResourceLimits,c5 as validateMountPath,o6 as validateDeploymentConfig,j9 as validateCredentials,q9 as validateConfiguration,uJ as validateCommand,NK as validateBackupDestination,u5 as validateAttachment,YJ as validateAgainstSchema,TX as validateAccountStructure,vU as utcInstantOfLocal,gU as usageDeltaKey,X8 as uploadStaticFiles,GK as updateCompatibility,m5 as unsupportedVolumeCapabilities,dQ as unsupportedCapabilities,hW as totpUri,LW as totp,D_ as toFocusRecords,k_ as toFocusJsonl,Q0 as toCloudflareZoneSettings,kU as tieredMicroCents,zU as testSourceConnection,b9 as templateCache,u_ as telemetryPolicyKey,o_ as telemetryPercentile,r_ as telemetryEstimatedMonthlyCost,i_ as telemetryCursor,s_ as telemetryBucketLabel,JF as systemdWorkloads,D$ as sysctlHardening,AY as syntheticsManager,jF as synchronizeConfiguredJobs,aK as synchronizeConfiguredConfiguration,i5 as synchronizeComposeVolumes,qU as syncSourceRepositories,VX as suggestRegions,GX as suggestRegionPairs,k9 as suggestQuotaIncrease,w9 as suggestIAMPolicy,mJ as suggestFlags,bJ as suggestCommand,H_ as strongestActiveAction,L_ as streamFocusJsonl,AW as storageAdvancedManager,OW as staticSiteManager,N4 as statePath,q4 as stateDir,_Q as startSpendLoop,R8 as startLocalDashboardServer,YX as stackDependencyManager,A3 as sshExecOrThrow,x3 as sshExec,OQ as spendOpenApiPaths,MQ as spendNotificationText,S_ as signalDefinition,Y4 as signRequestAsync,X4 as signRequest,q8 as signCloudFrontUrl,N8 as signCloudFrontCookies,s6 as shipsARelease,u2 as sharedRuntimeLoop,a2 as sharedRecursionGuard,D2 as sha256,c8 as setupDns01Challenge,z4 as setStateDir,G8 as setMaintenance,cY as serviceMeshManager,S3 as serverPublicIpv4,uK as serializeDotenv,l9 as sequence,H2 as senderReputationManager,cW as sendAuthenticationEmail,CQ as securityScope,bY as securityScanningManager,MY as securityHubManager,cQ as secureContainerRelease,TY as secretsRotationManager,DY as secretsManager,F5 as searchControlPlane,fJ as searchCommands,Z3 as scpUpload,sU as scopeKey,nW as scopeContains,NQ as scanForSecrets,t_ as saveTelemetryPolicy,tW as sanitizeOidcReturnPath,y4 as sanitizeName,_5 as sanitizeControlPlaneValue,x8 as sanitizeCloudConfig,uQ as runtimeId,O8 as runRemoteCommand,HW as runPhpBuildHooks,K_ as runEnforcement,B2 as runBuildHooks,c3 as ruleMatches,q_ as routeMatches,M2 as route53RoutingManager,W2 as route53ResolverManager,hU as roundCents,V8 as rollbackServerlessApp,WU as rollbackImmutableRelease,sW as roleCapabilities,O_ as robustZScore,$W as responseToResult,jW as resourceManagementManager,y0 as resolveZoneApex,y3 as resolveUiSource,f4 as resolveStorageBucketName,j4 as resolveStatePath,h4 as resolveSiteStackName,C4 as resolveSiteResourceName,i6 as resolveSiteKind,a6 as resolveSiteDeployTarget,I4 as resolveSiteBucketName,b2 as resolveServerlessRuntime,c4 as resolveServerlessAssetBucketName,v4 as resolveServerlessArtifactBucketName,m4 as resolveServerlessAppStackName,_F as resolveRuntimeInventory,_9 as resolveRegion,l2 as resolveRecursionConfig,h2 as resolveQueues,f5 as resolveQueuedDeploymentCommand,C2 as resolveQueueNames,l6 as resolveProxyUpstreams,b4 as resolveProjectStackName,v$ as resolveObjectStorage,c1 as resolveManagementDashboardSites,u1 as resolveManagementDashboardSite,Q3 as resolveHetznerApiToken,P3 as resolveExecStart,w4 as resolveDeploymentMode,p4 as resolveDeployBucketName,s$ as resolveDeclaredRecords,I1 as resolveDashboardDomains,C1 as resolveDashboardDomain,L3 as resolveDashboardAuth,Z8 as resolveDashboardAction,U9 as resolveCredentials,W$ as resolveCloudflareCdnPlan,D4 as resolveCloudProvider,dW as resolveAuthEncryptionKey,B4 as resolveAppDatabase,n2 as resolveApp,i2 as resetRecursionRuntime,e9 as requiresReplacement,EQ as requestHash,qY as replicaManager,p3 as renewRpxCertificates,X3 as renderWafInstallScript,J3 as renderWafConfig,k$ as renderSysctlFile,xF as renderServerCron,L$ as renderNftablesRuleset,y$ as renderDdosInstallScript,q5 as renderComposeTemplate,c6 as removeStaleServerAddressRecords,SU as removeSourceWebhook,I$ as remapKey,f3 as reloadRpxGateway,XU as releaseTrafficPlan,e5 as releaseStrategyCapabilities,XX as regionPairManager,E8 as redeployServerlessApp,g_ as redactTelemetryValue,l_ as redactTelemetryText,lQ as redactRuntimeConfig,O$ as recursionBlockedResponse,pQ as recordSkippedSecretScan,fQ as recordPreDeploySecretScan,mQ as recordDashboardHostPosture,jU as reconcileSourceWebhook,ZF as reconcileJobObservation,n$ as reconcileDeclaredRecords,X$ as reconcileCloudflareCdn,t6 as reconcileAddressRecords,u3 as rateLimitKey,t3 as rateLimitHeaders,m9 as quickHash,P2 as queueManagementManager,o$ as qualifyName,EK as publicKeyFingerprint,m$ as providerEndpoint,G$ as propagationHeaders,$_ as projectSpend,FY as progressiveDeploymentManager,vQ as productionChangeReview,xU as processSourceWebhook,o9 as processInChunks,F0 as probeOriginTls,bU as priceUsageLines,yU as priceUsage,uU as previousBudgetWindow,GF as previewSchedule,qJ as previewNotifications,xJ as previewManager,i$ as policyTag,b$ as planMitigation,F_ as planEnforcement,j5 as planComposeTemplateUpgrade,UW as phpRuntimeLayerAssets,p2 as phpLayerPackages,m2 as phpLayerBuildStage,jY as performanceManager,M_ as percentOfLimit,a_ as pathTemplate,K4 as parseXMLResponse,MF as parseSystemdRecords,H4 as parseJSONResponse,cK as parseDotenv,nQ as parseDockerInspect,N5 as parseComposeCatalog,x5 as parseCompose,H$ as parseChain,r9 as parallelWithRetry,t9 as parallelMap,u9 as parallel,L2 as packageServerlessApp,VW as packagePhpApp,qX as organizationManager,w_ as optionsForSignal,AQ as openApiDocument,c_ as normalizeTelemetryPolicy,F3 as normalizeSshPublicKey,OU as normalizeSourceEvent,EF as normalizeScheduleExpression,rQ as normalizeRuntimeStatus,u6 as normalizePublicIpv6,VF as nextScheduleRuns,qW as networkSecurityManager,d8 as needsRenewal,oJ as multiRegionManager,zX as multiAccountManager,RY as migrationManager,p$ as migrateObjectStorage,VY as metricsManager,iU as meterTelemetry,CU as mergePriceBooks,l1 as mergeInfrastructure,U_ as mergeDecisions,G_ as medianAbsoluteDeviation,V_ as median,P8 as mediaObjectHeaders,bW as matchTotpCounter,KK as manifestDigest,m1 as managementDashboardSiteName,Q4 as makeAWSRequestOnce,F4 as makeAWSRequestAsync,_4 as makeAWSRequest,xK as maintenanceWindowOpen,T_ as lookbackHoursForSignal,OY as logsManager,d_ as loadTelemetryPolicy,wW as loadCloudConfig,NU as listSourceReferences,R5 as listComposeTemplates,_W as laravelServerlessEnvDefaults,sQ as lambdaWorkloads,rY as lambdaVersionsManager,sY as lambdaVPCManager,dY as lambdaLayersManager,iY as lambdaDestinationsManager,eY as lambdaDLQManager,gY as lambdaConcurrencyManager,f$ as keyMatchesFilters,OF as jobProviderCapability,O4 as isWebCryptoAvailable,fU as isValidTimeZone,HX as isValidRegion,B$ as isValidCidr,S4 as isStatePath,$3 as isSafePattern,j$ as isQuietHours,E_ as isOperationAllowed,G4 as isNodeCryptoAvailable,v1 as isManagementDashboardSiteName,_J as isLocalDevelopment,CJ as isLikelyTypo,r2 as invocationContext,Y8 as invalidateCache,g2 as installRecursionFetch,E$ as inspectInvocation,F8 as infraEnvFromOutputs,CY as imageScanningManager,tU as hourBucketsBetween,dU as hourBucket,kW as hotp,W0 as hostCondition,K0 as hostAcceptsIpv6,RW as healthCheckManager,C9 as hashString,p9 as hashManifest,h9 as hashFile,f9 as hashDirectory,I9 as hashBuffer,g6 as hasProxyUpstream,f1 as hasManagementDashboardSite,n6 as hasAutoWwwVariant,GQ as handleSpendRequest,eX as guardDutyManager,Y_ as governingLimitCents,JX as globalResourceManager,M3 as globToRegex,v3 as globMatches,L4 as getTimestamp,V4 as getSigningKeyCacheSize,P9 as getRequiredPermissions,KX as getRegionsByPricingTier,QX as getRegionsByLocation,FX as getRegionsByCompliance,AX as getRegionStats,UX as getRegion,PX as getRecommendedStructure,D9 as getQuotaUsageSummary,KJ as getLocalEnvVars,QJ as getLocalEndpoint,FJ as getLocalCredentials,UJ as getLocalConfig,Z9 as getErrorDetails,n9 as getDiffSummary,JJ as getDiffStats,MJ as getDeploymentStrategy,Y9 as getCredentials,IJ as getContextualHelp,PW as getConfig,z5 as getComposeTemplate,cJ as getCommandUsage,EX as getClosestRegion,_X as getAllRegions,Q9 as getAccountId,W3 as generateUbuntuAppCloudInit,M8 as generateStaticSiteTemplate,yX as generateScheduledWorkflow,fX as generateScheduledPipeline,cX as generateScheduledConfig,R0 as generateResourceName,AJ as generatePreviewWorkflow,IX as generatePreviewPipeline,v2 as generatePhpLayerDockerfile,WW as generatePhpFpmConfig,dX as generateParallelConfig,LX as generatePRPreviewWorkflow,kX as generateMultiEnvWorkflow,CX as generateMultiEnvPipeline,vX as generateMultiEnvConfig,bX as generateMatrixWorkflow,pX as generateManualPipeline,z0 as generateLogicalId,m8 as generateLetsEncryptUserData,DQ as generateImageSbom,v8 as generateHttpsServerCode,n3 as generateExternalDnsStaticSiteTemplate,DX as generateDeploymentWorkflow,hX as generateDeploymentPipeline,mX as generateDeploymentConfig,BQ as generateCycloneDxSbom,wX as generateCrossAccountRoleCF,RJ as generateCostReportWorkflow,ZJ as generateCleanupWorkflow,T2 as generateBootstrap,uX as generateApprovalConfig,c2 as generateAppImageDockerfile,H0 as gatewayHostnames,F$ as functionFingerprint,X9 as fromWebIdentity,$9 as fromSharedCredentials,e1 as fromEnvironment,J9 as fromECSMetadata,M9 as fromEC2Metadata,jJ as formatTree,J_ as formatTimeToExhaustion,NJ as formatTable,hJ as formatSuggestion,jQ as formatScanResults,xX as formatRegionList,OX as formatRegion,SJ as formatProgressBar,TJ as formatList,BJ as formatKeyValue,aJ as formatHistoryStats,gJ as formatHistory,vJ as formatFlagSuggestions,wJ as formatDuration,t4 as formatDiff,$Q as formatCents,PJ as formatBytes,BX as formatAccountStructure,LU as findPriceEntry,lU as findMapping,v9 as findChangedFiles,R2 as fifoQueueManager,d1 as extendPreset,A5 as exportCompose,x_ as ewma,e2 as eventToRequest,AF as eventBridgeScheduleInput,w$ as evaluateTelemetryAlertRules,W_ as evaluateBudget,e6 as escapeSecLang,q3 as ensureSshKey,j3 as ensureServer,b3 as ensureManagementDashboard,N3 as ensureFirewall,IQ as ensureDefaultSecurityPolicies,SK as encryptBackup,BW as encodeBase32,V2 as emailTemplateManager,F2 as emailAnalyticsManager,$5 as effectiveCapabilities,oQ as ecsWorkloads,gX as drManager,HK as documentDigest,eQ as dockerWorkloads,X2 as dnssecManager,U6 as dnsProviders,q2 as dlqMonitoringManager,iQ as discoverRuntimeInventory,rW as discoverOidcProvider,ZU as discoverGitRefs,s9 as diffTemplates,Z5 as diffCompose,J4 as detectServiceRegion,N9 as detectMisconfigurations,Z_ as detectLatestAnomaly,Y6 as detectDnsProvider,P4 as detectDeploymentTargets,A_ as detectAnomalies,RF as desiredJobProviderState,i3 as describePosture,h1 as deriveManagementDashboardPort,T4 as deploymentCoexistenceError,$8 as deployStaticSiteWithExternalDnsFull,e3 as deployStaticSiteWithExternalDns,U8 as deployStaticSiteFull,J8 as deployStaticSite,C3 as deploySiteRelease,_8 as deploySite,H8 as deployServerlessApp,I3 as deployAllComputeSites,W8 as deleteStaticSite,r3 as defaultRateLimitRules,WJ as defaultLocalConfig,SW as defaultConfig,PK as decryptBackup,yK as decompressBackup,DW as decodeBase32,PY as databaseUserManager,TF as dataServiceCapabilities,k3 as dashboardCredentialsFile,A8 as dashboardActions,MX as crossRegionReferenceManager,w2 as createZip,z1 as createWordPressPreset,t5 as createVolumeQueueHandlers,w1 as createTraditionalWebAppPreset,V1 as createStaticSitePreset,GU as createSourceAdapter,x1 as createServerlessNodePreset,B1 as createServerlessLaravelPreset,MK as createServerBuildDriver,K9 as createS3Client,UF as createRuntimeAdapters,X6 as createRoute53Validator,eF as createRemoteBuildQueueHandlers,_U as createReleaseQueueHandlers,yQ as createReleaseProvenance,UK as createRegionQueueHandlers,j1 as createRealtimeAppPreset,JW as createQueueHandler,U4 as createPresignedUrlAsync,W4 as createPresignedUrl,r1 as createPreset,M6 as createPorkbunValidator,c$ as createObjectStorageClient,O1 as createNodeJsServerlessPreset,G1 as createNodeJsServerPreset,GJ as createMockAWS,N1 as createMicroservicesPreset,j8 as createMediaAccessToken,ZK as createMaintenanceQueueHandlers,P1 as createMLApiPreset,T1 as createLaravelPreset,PF as createJobQueueHandlers,q1 as createJamstackPreset,MW as createHttpHandler,YW as createHandlers,J6 as createGoDaddyValidator,Z1 as createFullStackAppPreset,rF as createFleetQueueHandlers,A1 as createExistingStaticFullStackPreset,R9 as createError,p_ as createEnforcementHandlers,JK as createEcsBuildDriver,a as createDnsProvider,p5 as createDeploymentQueueHandlers,LF as createDataServiceQueueHandlers,S1 as createDataPipelinePreset,D1 as createDashboardSite,W9 as createCredentialProvider,A0 as createCloudFrontPolicy,E3 as createCloudDriver,XW as createCliHandler,DK as createBackupQueueHandlers,XK as createAsgBuildDriver,ZQ as createApiV1Handler,R1 as createApiBackendPreset,iW as controlPlaneMigrations,Y5 as controlPlaneDatabaseFile,mY as containerRegistryManager,DF as connectionGuidance,TW as config,LK as compressBackup,KQ as compositeSpendTransport,I2 as composeServerlessAppTemplate,S5 as composeProjectName,t1 as composePresets,gW as completeOidcAuthorization,o5 as completeComposeVolumeDeletion,v6 as collectServerDnsDomains,EW as collectPhpAppEntries,sX as cloudTrailManager,G3 as cloudDrivers,XJ as cloudConfigSchema,RU as cloneSourceBinding,E4 as clearSigningKeyCache,u8 as cleanupDns01Challenge,i9 as chunk,B9 as checkServiceQuotas,o2 as checkInvocation,S9 as checkIAMPermissions,LY as certificateManager,$J as categorizeChanges,iF as capacity,tQ as capabilities,FK as canonicalJson,WY as canaryManager,aQ as bytes,T3 as buildStaticSiteDeployScript,U0 as buildStaticSiteCacheRules,O3 as buildSshArgs,w3 as buildSiteDeployScript,FW as buildPhpRuntimeLayerZip,_0 as buildOriginGuardRule,fY as buildOptimizationManager,d2 as buildNodeRuntimeLayerZip,w8 as buildMediaCdnPlan,h3 as buildManagementDashboardArtifact,B3 as buildHostCleanupScript,K8 as buildFunctionEnv,B5 as buildComposeShellCommand,w5 as buildComposeScaleCommand,P5 as buildComposeRuntimeCommand,T5 as buildComposeLogsCommand,E1 as buildCloudFormationTemplate,t2 as buildBunRuntimeLayerZip,Q8 as buildAndPushServerlessImage,cU as budgetWindow,_2 as bounceComplaintHandler,XY as blueGreenManager,lW as beginOidcAuthorization,j2 as batchProcessingManager,d9 as batch,rX as backupManager,wK as backupCredentialStatus,iX as awsConfigManager,pJ as autocomplete,QF as authorizeRuntimePath,eW as authorizeOrganization,uW as authEncryptionKeyFile,LQ as attachVulnerabilitySummary,kQ as attachSbomToRelease,bQ as attachProvenanceToRelease,f_ as assertSpendAllows,$U as assertReleaseStrategy,k2 as artifactKey,h$ as applyMitigationFactor,o3 as applyControlsToRateLimits,s3 as applyControlsToDdos,R_ as anomalyOptionsForSignal,d4 as analyzeStackDiff,oU as aggregateDeltas,gQ as ageSeconds,YU as activateImmutableRelease,_Y as abTestManager,KY as XRayManager,M1 as Workflow,a5 as VolumeStore,d5 as VolumeService,f6 as VoiceClient,O9 as ValidationError,X5 as UnsupportedSchemaVersionError,$6 as UnifiedDnsValidator,QK as UnavailableRegionalDriver,Q_ as USER_VISIBLE_ACTIONS,e_ as URGENT_SPEND_EVENTS,O5 as TsCloudClient,G5 as TsCloudApiError,wQ as TrivyImageScanner,$K as TransportRemoteBuildDriver,RK as TransportPlatformMaintenanceDriver,qK as TransportDisasterRecoveryDriver,D6 as TranslateClient,N6 as TranscribeClient,T6 as TextractClient,y9 as TemplateCache,Z0 as TemplateBuilder,n_ as TelemetryStore,yJ as TaskList,Q$ as TRACE_HEADER,XF as SystemdDiscoveryAdapter,dF as SystemFleetSshTransport,xY as SyntheticsManager,p6 as SupportClient,xW as StorageAdvancedManager,n as Storage,GW as StaticSiteManager,s4 as StacksIntegration,$X as StackDependencyManager,tF as SshFleetDriver,LJ as Spinner,eU as SpendStore,y_ as SpendService,WQ as SpendRunner,JQ as SpendNotificationRouter,YQ as SpendLoopLease,C_ as SpendGate,I_ as SpendCapError,FU as SourceProviderError,QU as SourceConnectionStore,n4 as SmsHandlers,I6 as SmsClient,A2 as SmsAdvanced,P_ as SignalSource,N0 as Sftp,vY as ServiceMeshManager,l5 as ServerPathVolumeDriver,CF as ServerDataAdapter,zF as ServerCronJobAdapter,K2 as SenderReputationManager,yY as SecurityScanningManager,SQ as SecurityScannerRunner,RQ as SecurityPostureStore,$Y as SecurityHubManager,e as Security,wY as SecretsRotationManager,E6 as SecretsManagerClient,BY as SecretsManager,W1 as Secrets,PQ as SecretFindingScanner,w0 as Search,h6 as SchedulerClient,C$ as STSClient,v as STATIC_SITE_ZONE_SETTINGS,R4 as STATE_DIR_ENV_VAR,H6 as SSMClient,G6 as SQSClient,XQ as SPEND_LEASE_SETTING,h_ as SPEND_GATE_SETTING,UQ as SPEND_CYCLE_SECONDS,V6 as SNSClient,e4 as SMS,R$ as SESClient,z_ as SENSITIVITY_THRESHOLDS,zQ as SECRET_PATTERNS,F9 as S3Error,Z$ as S3Client,TK as S3BackupDestinationAdapter,HF as RuntimeStreamRegistry,KF as RuntimeOperationService,$2 as Route53RoutingManager,Y2 as Route53ResolverManager,e$ as Route53Provider,d$ as Route53DomainsClient,g as Route53Client,L5 as RetryableOperationError,NW as ResourceManagementManager,zY as ReplicaManager,nF as RemoteBuildService,MU as ReleaseStore,JU as ReleaseService,w6 as RekognitionClient,r4 as Registry,YK as RegionStore,WK as RegionService,eJ as RegionPairManager,l as Redirects,V$ as RecursionGuard,m_ as RecordingSpendTransport,A4 as RealtimePresets,a9 as RateLimiter,tJ as REPLContext,rJ as REPLCommandBuilder,dJ as REPL,UU as RELEASE_QUEUE_KINDS,jX as RECOMMENDED_SCPS,NX as RECOMMENDED_ACCOUNT_STRUCTURES,R6 as RDSClient,m3 as RATE_LIMIT_KEY_SEPARATOR,k5 as QueueTimeoutError,x4 as QueuePresets,S2 as QueueManagementManager,D5 as QueueCancellationError,$0 as Queue,k4 as Pseudo,a3 as ProtectionControlStore,QY as ProgressiveDeploymentManager,DJ as ProgressBar,zJ as PreviewNotificationService,h5 as PreviewEnvironmentStore,C5 as PreviewEnvironmentService,OJ as PreviewEnvironmentManager,qQ as PreDeployScanner,r$ as PorkbunProvider,B6 as PollyClient,oF as PlacementStore,sF as PlacementService,a4 as PhoneHandlers,x2 as PhoneAdvanced,i4 as Phone,k6 as PersonalizeClient,j0 as Permissions,NY as PerformanceManager,U1 as ParameterStore,t$ as PROXIABLE_RECORD_TYPES,f2 as PHP_LAYER_EXTENSIONS,KW as PHP_DEFAULT_EXCLUDES,RX as OrganizationManager,M5 as OptimisticConcurrencyError,q6 as OpenSearchClient,S$ as NotificationRouter,zW as NetworkSecurityManager,q0 as Network,kJ as MultiStepProgress,iJ as MultiRegionManager,ZX as MultiAccountManager,P0 as Monitoring,EJ as MockS3,VJ as MockDynamoDB,HJ as MockCloudFormation,ZY as MigrationManager,EY as MetricsManager,$1 as Messaging,OK as MaintenanceStore,AK as MaintenanceService,X_ as MIN_PROJECTION_CONFIDENCE,DU as MICRO_CENTS,PU as METER_KEYS,wU as METERS,W5 as MAX_CONTROL_PLANE_JSON_BYTES,U5 as MAX_CONTROL_PLANE_ERROR_BYTES,l3 as MAX_CONTROL_HOURS,p1 as MANAGEMENT_DASHBOARD_SITE_PREFIX,D3 as MANAGEMENT_DASHBOARD_SITE,y2 as MANAGED_NODE_VERSIONS,GY as LogsManager,CK as LogicalDatabaseBackupSource,dK as LocalEncryptedConfigurationBackend,tY as LambdaVersionsManager,oY as LambdaVPCManager,WF as LambdaRuntimeAdapter,uY as LambdaLayersManager,aY as LambdaDestinationsManager,nY as LambdaDLQManager,lY as LambdaConcurrencyManager,O6 as LambdaClient,QW as LARAVEL_SERVERLESS_BUILD_STEPS,L6 as KendraClient,wF as JobStore,SF as JobService,NF as JobProviderReconciler,o4 as JobLoader,J5 as InvalidOperationTransitionError,v0 as InfrastructureGenerator,hY as ImageScanningManager,d6 as IPV6_EXCLUDED_HOST_LABELS,A$ as IAMClient,H3 as HetznerDriver,_3 as HetznerClient,P$ as HealthCheckRunner,ZW as HealthCheckManager,c9 as HashCache,nX as GuardDutyManager,l$ as GoDaddyProvider,nJ as GlobalResourceManager,HU as GitlabSourceAdapter,KU as GithubSourceAdapter,VU as GiteaSourceAdapter,Q1 as Fn,lF as FleetStore,gF as FleetService,hK as FilesystemBackupSource,t as FileSystem,L9 as FileCache,B_ as FOCUS_VERSION,Z2 as FIFOQueueManager,lK as ExternalConfigurationBackend,qF as EventBridgeJobAdapter,y6 as EventBridgeClient,A9 as ErrorCodes,uF as EncryptedDataSecretStore,E2 as EmailTemplateManager,O2 as EmailHandlers,z$ as EmailClient,Q2 as EmailAnalyticsManager,G2 as EmailAdvanced,h as Email,b6 as ElastiCacheClient,d3 as EdgeRateLimiter,YF as EcsRuntimeAdapter,BU as ENFORCEMENT_SEVERITY,__ as ENFORCEMENT_DESCRIPTIONS,TU as ENFORCEMENT_ACTIONS,Z6 as ELBv2Client,m6 as EFSClient,K6 as ECSClient,F6 as ECRClient,u$ as EC2Client,z6 as DynamoDBClient,b5 as DurableQueueWorker,y5 as DurableOperationQueue,fK as DockerVolumeBackupSource,r5 as DockerNamedVolumeDriver,$F as DockerDiscoveryAdapter,cF as DockerDataTransport,W6 as DnsProviderFactory,lX as DisasterRecoveryManager,G9 as DeploymentError,X1 as Deployment,u4 as DependencyGraph,z9 as DebugLogger,SY as DatabaseUserManager,r as Database,BF as DataServiceStore,kF as DataServiceLifecycle,J2 as DNSSECManager,g4 as DNS,z2 as DLQMonitoringManager,FF as DIAGNOSTIC_PRESETS,j_ as DETECTABLE_SIGNALS,U$ as DEPTH_HEADER,I5 as DEPLOYMENT_QUEUE_KINDS,nU as DEFAULT_THRESHOLDS,v_ as DEFAULT_TELEMETRY_POLICY,k0 as DEFAULT_STATIC_ASSET_EXTENSIONS,Z4 as DEFAULT_STATE_DIR,T9 as DEFAULT_SERVICE_LIMITS,K$ as DEFAULT_RECURSION_LIMITS,IU as DEFAULT_PRICE_BOOK,rU as DEFAULT_METER_MAPPINGS,T$ as DEFAULT_DDOS_THRESHOLDS,g3 as DEFAULT_ATTACK_MODE_HOURS,k1 as DASHBOARD_STATE_DIR,b1 as DASHBOARD_PORT_SPAN,y1 as DASHBOARD_PORT_BASE,L1 as DASHBOARD_ENTRY,sJ as CrossRegionReferenceManager,V9 as CredentialError,aU as CounterTracker,Q5 as ControlPlaneStore,zK as ControlPlaneCleanupDriver,pK as ControlPlaneBackupSource,pY as ContainerRegistryManager,IF as ContainerDataAdapter,A6 as ConnectClient,vK as ConfigurationStore,gK as ConfigurationService,E9 as ConfigurationError,FQ as ComputeSpendTransport,B as Compute,P6 as ComprehendClient,s5 as ComposeApplicationStore,n5 as ComposeApplicationService,_1 as Communication,lJ as CommandHistory,a$ as CloudflareProvider,x6 as CloudWatchLogsClient,oX as CloudTrailManager,h0 as CloudFrontClient,b0 as CloudFormationClient,H1 as CloudFormationBuilder,H9 as CloudError,V3 as CloudDriverFactory,g5 as CloudBlockVolumeDriver,kY as CertificateManager,YY as CanaryManager,M0 as Cache,aW as CONTROL_PLANE_SCHEMA_VERSION,SX as COMMON_CROSS_ACCOUNT_ROLES,g$ as CLOUDFLARE_MANAGED_RULE_PREFIX,_$ as CHAIN_HEADER,l4 as CDN,bK as BunFilesystemArchiveRuntime,IK as BunDockerVolumeRuntime,vF as BunDockerRuntime,IY as BuildOptimizationManager,U2 as BounceComplaintHandler,JY as BlueGreenManager,EU as BitbucketSourceAdapter,j6 as BedrockRuntimeClient,S6 as BedrockClient,N2 as BatchProcessingManager,jK as BackupStore,tX as BackupManager,BK as BackupCoordinator,rK as AwsSsmConfigurationBackend,QQ as AwsSpendTransport,tK as AwsSecretsManagerConfigurationBackend,_K as AwsRegionalDriver,fF as AwsRdsTransport,yF as AwsRdsDataAdapter,mK as AwsInfrastructureBackupSource,TQ as AwsIamCapabilityScanner,mF as AwsElastiCacheTransport,hF as AwsElastiCacheDataAdapter,U3 as AwsDriver,kK as AwsDatabaseBackupSource,pF as AwsAuroraTransport,bF as AwsAuroraDataAdapter,V5 as AutomationIdentityStore,VQ as AutomationApiService,vW as AuthenticationStore,J1 as Auth,Y1 as AssetHasher,F1 as Arn,C6 as ApplicationAutoScalingClient,HQ as ApiServiceError,S0 as ApiGateway,N_ as AnomalyConfigStore,q$ as AlertStore,N$ as AlertEvaluator,M$ as AcmeClient,WX as AWS_REGIONS,K1 as AWS_PSEUDO_PARAMETERS,aX as AWSConfigManager,h0 as AWSCloudFrontClient,b0 as AWSCloudFormationClient,x$ as AWSClient,x9 as AWSAPIError,CW as AUTH_SESSION_IDLE_TTL_MS,IW as AUTH_SESSION_ABSOLUTE_TTL_MS,mW as AUTH_OIDC_TRANSACTION_TTL_MS,pW as AUTH_MFA_CHALLENGE_TTL_MS,fW as AUTH_ACTION_TOKEN_TTL_MS,oW as AUTHORIZATION_CAPABILITIES,xQ as API_VERSION,H5 as API_TOKEN_MAX_TTL_MS,K5 as API_TOKEN_DEFAULT_TTL_MS,E5 as API_IDEMPOTENCY_TTL_MS,C as AI,D0 as ACME_DIRECTORIES,Q6 as ACMDnsValidator,_6 as ACMClient,UY as ABTestManager};
595
+ `}async function ji(e){let{domain:t,challengeValue:r,hostedZoneId:n,dnsProvider:i,region:l="us-east-1"}=e;if(i){let s=await j(i).upsertRecord(t,{name:`_acme-challenge.${t}`,type:"TXT",content:r,ttl:60});if(!s.success)throw Error(`Failed to create DNS challenge record: ${s.message}`);return}if(n){await new q(l).changeResourceRecordSets({HostedZoneId:n,ChangeBatch:{Comment:"ACME DNS-01 challenge",Changes:[{Action:"UPSERT",ResourceRecordSet:{Name:`_acme-challenge.${t}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${r}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}async function Ji(e){let{domain:t,challengeValue:r,hostedZoneId:n,dnsProvider:i,region:l="us-east-1"}=e;if(i){let s=await j(i).deleteRecord(t,{name:`_acme-challenge.${t}`,type:"TXT",content:r});if(!s.success)console.warn(`Failed to delete DNS challenge record: ${s.message}`);return}if(n){await new q(l).changeResourceRecordSets({HostedZoneId:n,ChangeBatch:{Comment:"Remove ACME DNS-01 challenge",Changes:[{Action:"DELETE",ResourceRecordSet:{Name:`_acme-challenge.${t}`,Type:"TXT",TTL:60,ResourceRecords:[{Value:`"${r}"`}]}}]}});return}throw Error("Either dnsProvider or hostedZoneId must be provided")}function Yi(e){try{let{execSync:t}=Je("node:child_process"),r=t(`openssl x509 -checkend 2592000 -noout -in ${e}/cert.pem`,{encoding:"utf-8",stdio:["pipe","pipe","pipe"]});return!1}catch{return!0}}import{createHash as we,createSign as rt,generateKeyPairSync as Oe}from"node:crypto";var ve={production:"https://acme-v02.api.letsencrypt.org/directory",staging:"https://acme-staging-v02.api.letsencrypt.org/directory"};class nt{directoryUrl;email;accountKey;accountUrl=null;directory=null;nonce=null;constructor(e){this.directoryUrl=e.staging?ve.staging:ve.production,this.email=e.email,this.accountKey=e.accountKey||this.generateAccountKey()}generateAccountKey(){let{privateKey:e}=Oe("ec",{namedCurve:"P-256"});return e.export({type:"pkcs8",format:"pem"})}async getDirectory(){if(this.directory)return this.directory;let e=await fetch(this.directoryUrl);if(!e.ok)throw Error(`Failed to fetch ACME directory: ${e.status}`);return this.directory=await e.json(),this.directory}async getNonce(){if(this.nonce){let n=this.nonce;return this.nonce=null,n}let e=await this.getDirectory(),r=(await fetch(e.newNonce,{method:"HEAD"})).headers.get("replay-nonce");if(!r)throw Error("Failed to get nonce from ACME server");return r}getJwk(){let e=this.accountKey.split(`
596
+ `).filter((l)=>!l.startsWith("-----")).join(""),t=Buffer.from(e,"base64"),r=t.length-65,n=t.subarray(r+1,r+33),i=t.subarray(r+33,r+65);return{kty:"EC",crv:"P-256",x:this.base64UrlEncode(n),y:this.base64UrlEncode(i)}}getJwkThumbprint(){let e=this.getJwk(),t=JSON.stringify({crv:e.crv,kty:e.kty,x:e.x,y:e.y}),r=we("sha256").update(t).digest();return this.base64UrlEncode(r)}base64UrlEncode(e){return(typeof e==="string"?Buffer.from(e):e).toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async signPayload(e,t){let r=await this.getNonce(),n=this.getJwk(),i={alg:"ES256",nonce:r,url:e};if(this.accountUrl)i.kid=this.accountUrl;else i.jwk=n;let l=this.base64UrlEncode(JSON.stringify(i)),c=t===""?"":this.base64UrlEncode(JSON.stringify(t)),s=`${l}.${c}`,d=rt("SHA256");d.update(s);let h=d.sign(this.accountKey),u=h.subarray(4,4+h[3]),b=4+h[3]+2,A=h.subarray(b,b+h[b-1]),R=Buffer.alloc(32),y=Buffer.alloc(32);u.copy(R,32-u.length),A.copy(y,32-A.length);let m=Buffer.concat([R,y]);return JSON.stringify({protected:l,payload:c,signature:this.base64UrlEncode(m)})}async acmeRequest(e,t){let r=await this.signPayload(e,t),n=await fetch(e,{method:"POST",headers:{"Content-Type":"application/jose+json"},body:r}),i=n.headers.get("replay-nonce");if(i)this.nonce=i;let l,c=n.headers.get("content-type");if(c?.includes("application/json")||c?.includes("application/problem+json"))l=await n.json();else l=await n.text();if(!n.ok)throw Error(`ACME request failed: ${JSON.stringify(l)}`);return{body:l,headers:n.headers}}async registerAccount(){let e=await this.getDirectory(),{body:t,headers:r}=await this.acmeRequest(e.newAccount,{termsOfServiceAgreed:!0,contact:[`mailto:${this.email}`]}),n=r.get("location");if(!n)throw Error("No account URL returned");return this.accountUrl=n,n}async createOrder(e){if(!this.accountUrl)await this.registerAccount();let t=await this.getDirectory(),{body:r,headers:n}=await this.acmeRequest(t.newOrder,{identifiers:e.map((l)=>({type:"dns",value:l}))}),i=n.get("location");if(!i)throw Error("No order URL returned");return{orderUrl:i,authorizations:r.authorizations,finalize:r.finalize}}async getAuthorization(e){let{body:t}=await this.acmeRequest(e,""),r=t.identifier.value,n=this.getJwkThumbprint(),i=t.challenges.filter((l)=>l.type==="http-01"||l.type==="dns-01").map((l)=>{let c=`${l.token}.${n}`;if(l.type==="http-01")return{type:"http-01",token:l.token,keyAuthorization:c,identifier:`/.well-known/acme-challenge/${l.token}`};else{let s=this.base64UrlEncode(we("sha256").update(c).digest());return{type:"dns-01",token:l.token,keyAuthorization:c,identifier:`_acme-challenge.${r}`,dnsValue:s}}});return{domain:r,challenges:i}}async respondToChallenge(e){await this.acmeRequest(e,{})}async waitForAuthorization(e,t=30){for(let r=0;r<t;r++){let{body:n}=await this.acmeRequest(e,"");if(n.status==="valid")return;if(n.status==="invalid")throw Error(`Authorization failed: ${JSON.stringify(n)}`);await new Promise((i)=>setTimeout(i,2000))}throw Error("Authorization timed out")}generateCsr(e){let{privateKey:t}=Oe("rsa",{modulusLength:2048}),r=t.export({type:"pkcs8",format:"pem"});return{csr:this.createSimpleCsr(e,t),privateKey:r}}createSimpleCsr(e,t){throw Error("CSR generation requires additional implementation. Consider using the shell-based certbot approach instead.")}async finalizeOrder(e,t){let{csr:r,privateKey:n}=this.generateCsr(t),{body:i}=await this.acmeRequest(e,{csr:this.base64UrlEncode(Buffer.from(r,"base64"))}),l=i.certificate;if(!l)throw Error("Certificate not immediately available - polling not implemented");let s=await(await fetch(l)).text(),d=s.split(/(?=-----BEGIN CERTIFICATE-----)/g),h=d[0],u=d.slice(1).join("");return{certificate:h,privateKey:n,chain:u,fullchain:s,expiresAt:new Date(Date.now()+7776000000)}}getAccountKey(){return this.accountKey}}var Ne=["js","mjs","cjs","css","map","woff","woff2","ttf","otf","eot","png","jpg","jpeg","gif","webp","avif","svg","ico","mp4","webm","ogg","mp3","wav","pdf","wasm"];function oe(e){return`"${e.replace(/\\/g,"\\\\").replace(/"/g,"\\\"")}"`}function ke(e){return`{${e.map(oe).join(" ")}}`}function ae(e){if(e.length===1)return`http.host eq ${oe(e[0])}`;return`http.host in ${ke(e)}`}function se(e,t={}){if(t.enabled===!1||e.length===0)return[];let r=ae(e),n=[],i=t.bypassPaths??[],l=i.length>0?`(${i.map((h)=>`starts_with(http.request.uri.path, ${oe(h)})`).join(" or ")})`:void 0;if(l)n.push({action:"set_cache_settings",description:"bypass cache",expression:`(${r} and ${l})`,enabled:!0,action_parameters:{cache:!1}});let c=l?`${r} and not ${l}`:r,s=t.assetExtensions??Ne,d=s.length>0?`lower(http.request.uri.path.extension) in ${ke([...s])}`:void 0;if(d)n.push({action:"set_cache_settings",description:"cache fingerprinted assets",expression:`(${c} and ${d})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:t.assetEdgeTtl??2592000},browser_ttl:{mode:"override_origin",default:t.assetBrowserTtl??31536000}}});return n.push({action:"set_cache_settings",description:"cache documents",expression:d?`(${c} and not ${d})`:`(${c})`,enabled:!0,action_parameters:{cache:!0,edge_ttl:{mode:"override_origin",default:t.documentEdgeTtl??3600},browser_ttl:{mode:"override_origin",default:t.documentBrowserTtl??0}}}),n}function ce(e,t,r){if(e.length===0||!t||!r)return[];return[{action:"rewrite",description:"origin guard header",expression:`(${ae(e)})`,enabled:!0,action_parameters:{headers:{[t]:{operation:"set",value:r}}}}]}var k=(e)=>e===void 0?void 0:e?"on":"off";function le(e){let t={ssl:e.ssl,always_use_https:k(e.alwaysUseHttps),automatic_https_rewrites:k(e.automaticHttpsRewrites),min_tls_version:e.minTlsVersion,tls_1_3:k(e.tls13),brotli:k(e.brotli),http3:k(e.http3),"0rtt":k(e.zeroRtt),early_hints:k(e.earlyHints),browser_cache_ttl:e.browserCacheTtl,always_online:k(e.alwaysOnline),websockets:k(e.websockets)};if(e.hsts)t.security_header={strict_transport_security:{enabled:e.hsts.enabled,max_age:e.hsts.maxAge??31536000,include_subdomains:e.hsts.includeSubdomains??!1,preload:e.hsts.preload??!1,nosniff:e.hsts.noSniff??!0}};for(let r of Object.keys(t))if(t[r]===void 0)delete t[r];return{...t,...e.raw??{}}}var W={ssl:"strict",alwaysUseHttps:!0,automaticHttpsRewrites:!0,minTlsVersion:"1.2",tls13:!0,brotli:!0,http3:!0,earlyHints:!0,alwaysOnline:!0,browserCacheTtl:0};import{connect as it}from"node:tls";async function de(e){let{address:t,serverName:r,port:n=443,timeoutMs:i=5000}=e;return new Promise((l)=>{let c=!1,s=(h)=>{if(c)return;c=!0;try{d.destroy()}catch{}l(h)},d=it({host:t,port:n,servername:r,rejectUnauthorized:!1,timeout:i});d.once("secureConnect",()=>{if(d.authorized){s({reachable:!0,trusted:!0});return}s({reachable:!0,trusted:!1,reason:d.authorizationError?String(d.authorizationError):"origin certificate is not trusted for this hostname"})}),d.once("timeout",()=>{s({reachable:!1,trusted:!1,reason:`no TLS handshake within ${i}ms`})}),d.once("error",(h)=>{s({reachable:!1,trusted:!1,reason:h.message})})})}async function ot(e){let{provider:t,zone:r,hosts:n,ipv4:i,ipv6:l,proxied:c=!0,settings:s=W,cache:d,originGuard:h,purge:u=!0,ttl:b=300,skipOriginProbe:A=!1}=e,R={records:[],settingsChanged:[],cacheRules:0,originGuard:!1,purged:!1,deferredProxy:[],warnings:[]};if(n.length===0)return R;let y=[];for(let o of n){let g=c;if(c&&!A){let f=await de({address:i,serverName:o});if(!f.trusted){g=!1;let p=f.reason||"origin is not serving a trusted certificate";R.deferredProxy.push({host:o,reason:p}),R.warnings.push(`${o}: publishing DNS-only for now — the origin does not yet serve a certificate this proxy can verify (${p}). 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(g)y.push(o);let a=[{type:"A",content:i}];if(l&&ue(o))a.push({type:"AAAA",content:l});for(let{type:f,content:p}of a){let C=await t.upsertRecord(r,{name:o,type:f,content:p,ttl:b,proxied:g});if(C.success)R.records.push({host:o,type:f,content:p,proxied:g});else R.warnings.push(`${o} ${f} → ${p} failed: ${C.message||"unknown provider error"}`)}}if(y.length===0){if(c)R.warnings.push("No host is proxied yet, so zone settings, cache rules and purge were skipped — they only take effect through the proxy.");return R}try{let o=le(s),g=await t.applyZoneSettings(r,o);R.settingsChanged=g.changed;for(let a of g.failed)R.warnings.push(`zone setting '${a.id}' could not be applied: ${a.error}`)}catch(o){R.warnings.push(`zone settings could not be read: ${o instanceof Error?o.message:String(o)}`)}let m=se(y,d);if(m.length>0){let o=await t.putManagedPhaseRules(r,"http_request_cache_settings",m);if(o.success)R.cacheRules=m.length;else R.warnings.push(`cache rules could not be written: ${o.message}`)}if(h){let o=ce(y,h.header,h.value);if(o.length>0){let g=await t.putManagedPhaseRules(r,"http_request_late_transform",o);if(g.success)R.originGuard=!0;else R.warnings.push(`origin guard header could not be written: ${g.message}. `+"The gateway will reject requests that lack it — disable the guard or grant the token Transform Rules: Edit.")}}if(u){if(R.purged=await t.purgeCache(r,{hosts:y}),!R.purged)R.warnings.push("edge cache purge failed — new content may take until TTL expiry to appear.")}return R}var at=(e)=>process.env[e];function xe(e,t){let r=e.replace(/\.$/,"").toLowerCase();if(t){let n=t.replace(/\.$/,"").toLowerCase();if(r===n||r.endsWith(`.${n}`))return n}return r.split(".").slice(-2).join(".")}function st(e,t={}){let r=t.env??at,n=e.infrastructure?.compute?.proxy?.cdn,i=[];if(!n||n.provider!=="cloudflare")return{plan:null,errors:i};if(n.originDomain)i.push(`compute.proxy.cdn.originDomain (${n.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 l=r("CLOUDFLARE_API_TOKEN");if(!l)return i.push("CLOUDFLARE_API_TOKEN is not set — the Cloudflare CDN cannot be reconciled."),{plan:null,errors:i};let c=e.sites??{},s=n.frontedHosts?.length?[...new Set(n.frontedHosts.map((A)=>A.toLowerCase()))]:pe(c,{autoWww:e.infrastructure?.compute?.proxy?.autoWww!==!1});if(s.length===0)return i.push("No hostnames to front — set compute.proxy.cdn.frontedHosts, or give a site a domain."),{plan:null,errors:i};let d=e.infrastructure?.dns?.domain,h=new Set(s.map((A)=>xe(A,d)));if(h.size>1)return i.push(`Fronted hosts span more than one zone (${[...h].join(", ")}). A Cloudflare zone is configured as a unit, so run one CDN config per zone.`),{plan:null,errors:i};let u=n.cloudflare??{},b=n.secret?{header:n.secretHeader??"X-Origin-Verify",value:n.secret}:void 0;return{plan:{zone:[...h][0],hosts:s,apiToken:l,zoneId:u.zoneId??r("CLOUDFLARE_ZONE_ID"),accountId:u.accountId??r("CLOUDFLARE_ACCOUNT_ID"),proxied:u.proxied!==!1,settings:u.settings??W,cache:u.cache,originGuard:b,purge:u.purgeOnDeploy!==!1,skipOriginProbe:u.skipOriginProbe===!0},errors:i}}export{Au as ABTestManager,mr as ACMClient,fr as ACMDnsValidator,ve as ACME_DIRECTORIES,M as AI,Df as API_IDEMPOTENCY_TTL_MS,Pf as API_TOKEN_DEFAULT_TTL_MS,If as API_TOKEN_MAX_TTL_MS,vy as API_VERSION,uf as AUTHORIZATION_CAPABILITIES,Ym as AUTH_ACTION_TOKEN_TTL_MS,Qm as AUTH_MFA_CHALLENGE_TTL_MS,Xm as AUTH_OIDC_TRANSACTION_TTL_MS,Jm as AUTH_SESSION_ABSOLUTE_TTL_MS,jm as AUTH_SESSION_IDLE_TTL_MS,Oc as AWSAPIError,Ct as AWSClient,Le as AWSCloudFormationClient,Me as AWSCloudFrontClient,cu as AWSConfigManager,$s as AWS_PSEUDO_PARAMETERS,Sd as AWS_REGIONS,nt as AcmeClient,$t as AlertEvaluator,Tt as AlertStore,Fh as AnomalyConfigStore,Pe as ApiGateway,Iy as ApiServiceError,Wr as ApplicationAutoScalingClient,Ts as Arn,Cs as AssetHasher,hs as Auth,ef as AuthenticationStore,Ey as AutomationApiService,Ef as AutomationIdentityStore,qC as AwsAuroraDataAdapter,XC as AwsAuroraTransport,KS as AwsDatabaseBackupSource,mn as AwsDriver,jC as AwsElastiCacheDataAdapter,eS as AwsElastiCacheTransport,zy as AwsIamCapabilityScanner,eA as AwsInfrastructureBackupSource,ZC as AwsRdsDataAdapter,QC as AwsRdsTransport,RS as AwsRegionalDriver,oA as AwsSecretsManagerConfigurationBackend,Ty as AwsSpendTransport,aA as AwsSsmConfigurationBackend,HS as BackupCoordinator,iu as BackupManager,VS as BackupStore,Mp as BatchProcessingManager,Or as BedrockClient,wr as BedrockRuntimeClient,Dg as BitbucketSourceAdapter,hu as BlueGreenManager,Ap as BounceComplaintHandler,Ju as BuildOptimizationManager,tS as BunDockerRuntime,YS as BunDockerVolumeRuntime,qS as BunFilesystemArchiveRuntime,as as CDN,lt as CHAIN_HEADER,jt as CLOUDFLARE_MANAGED_RULE_PREFIX,Vd as COMMON_CROSS_ACCOUNT_ROLES,lf as CONTROL_PLANE_SCHEMA_VERSION,re as Cache,Cu as CanaryManager,Gu as CertificateManager,lg as CloudBlockVolumeDriver,An as CloudDriverFactory,Pc as CloudError,Ps as CloudFormationBuilder,Le as CloudFormationClient,Me as CloudFrontClient,du as CloudTrailManager,Rr as CloudWatchLogsClient,Jt as CloudflareProvider,ad as CommandHistory,bs as Communication,mg as ComposeApplicationService,pg as ComposeApplicationStore,vr as ComprehendClient,w as Compute,$y as ComputeSpendTransport,Ic as ConfigurationError,cA as ConfigurationService,tA as ConfigurationStore,Tr as ConnectClient,YC as ContainerDataAdapter,Qu as ContainerRegistryManager,XS as ControlPlaneBackupSource,LS as ControlPlaneCleanupDriver,Tf as ControlPlaneStore,lh as CounterTracker,Dc as CredentialError,ud as CrossRegionReferenceManager,Ks as DASHBOARD_ENTRY,Us as DASHBOARD_PORT_BASE,Zs as DASHBOARD_PORT_SPAN,Gs as DASHBOARD_STATE_DIR,ei as DEFAULT_ATTACK_MODE_HOURS,wt as DEFAULT_DDOS_THRESHOLDS,ah as DEFAULT_METER_MAPPINGS,Yg as DEFAULT_PRICE_BOOK,pt as DEFAULT_RECURSION_LIMITS,Wc as DEFAULT_SERVICE_LIMITS,Ea as DEFAULT_STATE_DIR,Ne as DEFAULT_STATIC_ASSET_EXTENSIONS,ty as DEFAULT_TELEMETRY_POLICY,mh as DEFAULT_THRESHOLDS,Yf as DEPLOYMENT_QUEUE_KINDS,ct as DEPTH_HEADER,Vh as DETECTABLE_SIGNALS,$C as DIAGNOSTIC_PRESETS,xp as DLQMonitoringManager,ss as DNS,hp as DNSSECManager,KC as DataServiceLifecycle,HC as DataServiceStore,U as Database,Vu as DatabaseUserManager,xc as DebugLogger,rs as DependencyGraph,ys as Deployment,Ec as DeploymentError,au as DisasterRecoveryManager,ur as DnsProviderFactory,rS as DockerDataTransport,gC as DockerDiscoveryAdapter,sg as DockerNamedVolumeDriver,QS as DockerVolumeBackupSource,Zf as DurableOperationQueue,qf as DurableQueueWorker,Ir as DynamoDBClient,Gt as EC2Client,gr as ECRClient,hr as ECSClient,Kr as EFSClient,$r as ELBv2Client,zg as ENFORCEMENT_ACTIONS,Rh as ENFORCEMENT_DESCRIPTIONS,Hg as ENFORCEMENT_SEVERITY,SC as EcsRuntimeAdapter,Jn as EdgeRateLimiter,_r as ElastiCacheClient,L as Email,Ep as EmailAdvanced,Rp as EmailAnalyticsManager,Rt as EmailClient,wp as EmailHandlers,Ip as EmailTemplateManager,nS as EncryptedDataSecretStore,vc as ErrorCodes,Vr as EventBridgeClient,FC as EventBridgeJobAdapter,sA as ExternalConfigurationBackend,Np as FIFOQueueManager,Hh as FOCUS_VERSION,Kc as FileCache,K as FileSystem,jS as FilesystemBackupSource,cS as FleetService,sS as FleetStore,Rs as Fn,Eg as GiteaSourceAdapter,Pg as GithubSourceAdapter,Ig as GitlabSourceAdapter,pd as GlobalResourceManager,qt as GoDaddyProvider,pu as GuardDutyManager,tl as HashCache,Nm as HealthCheckManager,Dt as HealthCheckRunner,fn as HetznerClient,Cn as HetznerDriver,St as IAMClient,jr as IPV6_EXCLUDED_HOST_LABELS,qu as ImageScanningManager,ze as InfrastructureGenerator,yf as InvalidOperationTransitionError,ds as JobLoader,VC as JobProviderReconciler,BC as JobService,xC as JobStore,Fr as KendraClient,Rm as LARAVEL_SERVERLESS_BUILD_STEPS,br as LambdaClient,ap as LambdaConcurrencyManager,pp as LambdaDLQManager,cp as LambdaDestinationsManager,rp as LambdaLayersManager,AC as LambdaRuntimeAdapter,dp as LambdaVPCManager,ip as LambdaVersionsManager,iA as LocalEncryptedConfigurationBackend,JS as LogicalDatabaseBackupSource,Eu as LogsManager,Up as MANAGED_NODE_VERSIONS,Mn as MANAGEMENT_DASHBOARD_SITE,Qs as MANAGEMENT_DASHBOARD_SITE_PREFIX,Xn as MAX_CONTROL_HOURS,bf as MAX_CONTROL_PLANE_ERROR_BYTES,Af as MAX_CONTROL_PLANE_JSON_BYTES,Wg as METERS,Bg as METER_KEYS,Gg as MICRO_CENTS,Ch as MIN_PROJECTION_CONFIDENCE,NS as MaintenanceService,OS as MaintenanceStore,fs as Messaging,Iu as MetricsManager,Nu as MigrationManager,Pl as MockCloudFormation,Dl as MockDynamoDB,Il as MockS3,Ie as Monitoring,Nd as MultiAccountManager,ld as MultiRegionManager,Gl as MultiStepProgress,Re as Network,xm as NetworkSecurityManager,It as NotificationRouter,Dr as OpenSearchClient,hf as OptimisticConcurrencyError,kd as OrganizationManager,$m as PHP_DEFAULT_EXCLUDES,Yp as PHP_LAYER_EXTENSIONS,Ut as PROXIABLE_RECORD_TYPES,As as ParameterStore,Mu as PerformanceManager,$e as Permissions,Mr as PersonalizeClient,ls as Phone,Op as PhoneAdvanced,cs as PhoneHandlers,pS as PlacementService,uS as PlacementStore,xr as PollyClient,Zt as PorkbunProvider,My as PreDeployScanner,wl as PreviewEnvironmentManager,Jf as PreviewEnvironmentService,jf as PreviewEnvironmentStore,xl as PreviewNotificationService,Hl as ProgressBar,Ru as ProgressiveDeploymentManager,ti as ProtectionControlStore,Ga as Pseudo,te as Queue,Gf as QueueCancellationError,Vp as QueueManagementManager,Ia as QueuePresets,Kf as QueueTimeoutError,Un as RATE_LIMIT_KEY_SEPARATOR,Pr as RDSClient,Md as RECOMMENDED_ACCOUNT_STRUCTURES,Fd as RECOMMENDED_SCPS,bg as RELEASE_QUEUE_KINDS,nd as REPL,od as REPLCommandBuilder,id as REPLContext,cl as RateLimiter,Da as RealtimePresets,ey as RecordingSpendTransport,gt as RecursionGuard,Z as Redirects,md as RegionPairManager,AS as RegionService,SS as RegionStore,os as Registry,Nr as RekognitionClient,yg as ReleaseService,hg as ReleaseStore,mS as RemoteBuildService,xu as ReplicaManager,Mm as ResourceManagementManager,Uf as RetryableOperationError,q as Route53Client,Kt as Route53DomainsClient,tr as Route53Provider,Cp as Route53ResolverManager,fp as Route53RoutingManager,PC as RuntimeOperationService,IC as RuntimeStreamRegistry,zS as S3BackupDestinationAdapter,At as S3Client,Tc as S3Error,Ly as SECRET_PATTERNS,Lh as SENSITIVITY_THRESHOLDS,bt as SESClient,ms as SMS,Sr as SNSClient,by as SPEND_CYCLE_SECONDS,jh as SPEND_GATE_SETTING,Cy as SPEND_LEASE_SETTING,Ar as SQSClient,yr as SSMClient,wa as STATE_DIR_ENV_VAR,W as STATIC_SITE_ZONE_SETTINGS,Ft as STSClient,Br as SchedulerClient,De as Search,By as SecretFindingScanner,Ss as Secrets,zu as SecretsManager,Cr as SecretsManagerClient,Bu as SecretsRotationManager,ee as Security,fu as SecurityHubManager,xy as SecurityPostureStore,_y as SecurityScannerRunner,Uu as SecurityScanningManager,$p as SenderReputationManager,MC as ServerCronJobAdapter,JC as ServerDataAdapter,cg as ServerPathVolumeDriver,ep as ServiceMeshManager,Te as Sftp,Bh as SignalSource,vp as SmsAdvanced,zr as SmsClient,ps as SmsHandlers,Tg as SourceConnectionStore,$g as SourceProviderError,Yh as SpendCapError,Jh as SpendGate,Sy as SpendLoopLease,yy as SpendNotificationRouter,Ay as SpendRunner,Zh as SpendService,fh as SpendStore,Kl as Spinner,oS as SshFleetDriver,fd as StackDependencyManager,us as StacksIntegration,Em as StaticSiteManager,X as Storage,Om as StorageAdvancedManager,Gr as SupportClient,Ou as SyntheticsManager,iS as SystemFleetSshTransport,CC as SystemdDiscoveryAdapter,dt as TRACE_HEADER,Ul as TaskList,my as TelemetryStore,Se as TemplateBuilder,Uc as TemplateCache,kr as TextractClient,Er as TranscribeClient,Lr as TranslateClient,MS as TransportDisasterRecoveryDriver,xS as TransportPlatformMaintenanceDriver,gS as TransportRemoteBuildDriver,Wy as TrivyImageScanner,wf as TsCloudApiError,Of as TsCloudClient,fy as URGENT_SPEND_EVENTS,Th as USER_VISIBLE_ACTIONS,TS as UnavailableRegionalDriver,ar as UnifiedDnsValidator,Cf as UnsupportedSchemaVersionError,wc as ValidationError,Hr as VoiceClient,og as VolumeService,eg as VolumeStore,gs as Workflow,$u as XRayManager,bu as abTestManager,Sg as activateImmutableRelease,cC as ageSeconds,uh as aggregateDeltas,ns as analyzeStackDiff,xh as anomalyOptionsForSignal,ii as applyControlsToDdos,ni as applyControlsToRateLimits,Mt as applyMitigationFactor,ir as applyZoneMigration,Gp as artifactKey,gg as assertReleaseStrategy,Qh as assertSpendAllows,qy as attachProvenanceToRelease,Ky as attachSbomToRelease,Uy as attachVulnerabilitySummary,rf as authEncryptionKeyFile,ff as authorizeOrganization,TC as authorizeRuntimePath,Ql as autocomplete,lu as awsConfigManager,WS as backupCredentialStatus,ou as backupManager,nl as batch,Fp as batchProcessingManager,sf as beginOidcAuthorization,yu as blueGreenManager,bp as bounceComplaintHandler,rh as budgetWindow,gi as buildAndPushServerlessImage,im as buildBunRuntimeLayerZip,Is as buildCloudFormationTemplate,zf as buildComposeLogsCommand,Bf as buildComposeRuntimeCommand,Wf as buildComposeScaleCommand,Hf as buildComposeShellCommand,yi as buildFunctionEnv,Ln as buildHostCleanupScript,za as buildMailEnv,Wn as buildManagementDashboardArtifact,ki as buildMediaCdnPlan,nm as buildNodeRuntimeLayerZip,Yu as buildOptimizationManager,ce as buildOriginGuardRule,Tm as buildPhpRuntimeLayerZip,kn as buildSiteDeployScript,Rn as buildSshArgs,se as buildStaticSiteCacheRules,xn as buildStaticSiteDeployScript,lC as bytes,Su as canaryManager,$S as canonicalJson,oC as capabilities,dS as capacity,fl as categorizeChanges,Ku as certificateManager,Vc as checkIAMPermissions,dm as checkInvocation,zc as checkServiceQuotas,ll as chunk,Ji as cleanupDns01Challenge,Ra as clearSigningKeyCache,xg as cloneSourceBinding,yl as cloudConfigSchema,bn as cloudDrivers,uu as cloudTrailManager,Im as collectPhpAppEntries,Ur as collectServerDnsDomains,ug as completeComposeVolumeDeletion,cf as completeOidcAuthorization,ic as composePresets,_f as composeProjectName,Jp as composeServerlessAppTemplate,Py as compositeSpendTransport,US as compressBackup,Wm as config,GC as connectionGuidance,Xu as containerRegistryManager,Sf as controlPlaneDatabaseFile,df as controlPlaneMigrations,ks as createApiBackendPreset,ky as createApiV1Handler,CS as createAsgBuildDriver,GS as createBackupQueueHandlers,ym as createCliHandler,Sn as createCloudDriver,Ce as createCloudFrontPolicy,Sc as createCredentialProvider,Hs as createDashboardSite,Vs as createDataPipelinePreset,UC as createDataServiceQueueHandlers,Xf as createDeploymentQueueHandlers,j as createDnsProvider,yS as createEcsBuildDriver,Xh as createEnforcementHandlers,kc as createError,vs as createExistingStaticFullStackPreset,aS as createFleetQueueHandlers,Ns as createFullStackAppPreset,cr as createGoDaddyValidator,Cm as createHandlers,gm as createHttpHandler,Ls as createJamstackPreset,WC as createJobQueueHandlers,Ws as createLaravelPreset,_s as createMLApiPreset,kS as createMaintenanceQueueHandlers,Oi as createMediaAccessToken,Ms as createMicroservicesPreset,El as createMockAWS,Es as createNodeJsServerPreset,ws as createNodeJsServerlessPreset,Ht as createObjectStorageClient,sr as createPorkbunValidator,oc as createPreset,ga as createPresignedUrl,ha as createPresignedUrlAsync,hm as createQueueHandler,Fs as createRealtimeAppPreset,bS as createRegionQueueHandlers,Zy as createReleaseProvenance,Rg as createReleaseQueueHandlers,fS as createRemoteBuildQueueHandlers,lr as createRoute53Validator,bC as createRuntimeAdapters,$c as createS3Client,hS as createServerBuildDriver,zs as createServerlessLaravelPreset,Os as createServerlessNodePreset,wg as createSourceAdapter,Ds as createStaticSitePreset,Bs as createTraditionalWebAppPreset,ag as createVolumeQueueHandlers,xs as createWordPressPreset,Bp as createZip,gd as crossRegionReferenceManager,$i as dashboardActions,Fn as dashboardCredentialsFile,zC as dataServiceCapabilities,_u as databaseUserManager,Hm as decodeBase32,ZS as decompressBackup,BS as decryptBackup,Vm as defaultConfig,Sl as defaultLocalConfig,Qn as defaultRateLimitRules,pi as deleteStaticSite,Hn as deployAllComputeSites,Ci as deployServerlessApp,fi as deploySite,zn as deploySiteRelease,li as deployStaticSite,mi as deployStaticSiteFull,ai as deployStaticSiteWithExternalDns,si as deployStaticSiteWithExternalDnsFull,Fa as deploymentCoexistenceError,qs as deriveManagementDashboardPort,ri as describePosture,LC as desiredJobProviderState,Nh as detectAnomalies,La as detectDeploymentTargets,dr as detectDnsProvider,kh as detectLatestAnomaly,Mc as detectMisconfigurations,pa as detectServiceRegion,kf as diffCompose,ul as diffTemplates,kg as discoverGitRefs,af as discoverOidcProvider,dC as discoverRuntimeInventory,Lp as dlqMonitoringManager,pr as dnsProviders,yp as dnssecManager,fC as dockerWorkloads,IS as documentDigest,su as drManager,uC as ecsWorkloads,gf as effectiveCapabilities,Tp as emailAnalyticsManager,Dp as emailTemplateManager,zm as encodeBase32,_S as encryptBackup,Yy as ensureDefaultSecurityPolicies,wn as ensureFirewall,Bn as ensureManagementDashboard,On as ensureServer,En as ensureSshKey,an as escapeSecLang,Ah as evaluateBudget,Et as evaluateTelemetryAlertRules,NC as eventBridgeScheduleInput,mm as eventToRequest,vh as ewma,Nf as exportCompose,rr as exportRoute53Zone,nc as extendPreset,kp as fifoQueueManager,el as findChangedFiles,sh as findMapping,Ug as findPriceEntry,zd as formatAccountStructure,_l as formatBytes,gy as formatCents,is as formatDiff,Bl as formatDuration,ed as formatFlagSuggestions,sd as formatHistory,cd as formatHistoryStats,zl as formatKeyValue,Wl as formatList,Vl as formatProgressBar,wd as formatRegion,Od as formatRegionList,Vy as formatScanResults,ql as formatSuggestion,Ml as formatTable,yh as formatTimeToExhaustion,Fl as formatTree,gc as fromEC2Metadata,hc as fromECSMetadata,mc as fromEnvironment,fc as fromSharedCredentials,yc as fromWebIdentity,ut as functionFingerprint,pe as gatewayHostnames,tm as generateAppImageDockerfile,ru as generateApprovalConfig,Wp as generateBootstrap,Nl as generateCleanupWorkflow,kl as generateCostReportWorkflow,Bd as generateCrossAccountRoleCF,Hy as generateCycloneDxSbom,Xd as generateDeploymentConfig,qd as generateDeploymentPipeline,Hd as generateDeploymentWorkflow,oi as generateExternalDnsStaticSiteTemplate,qi as generateHttpsServerCode,Gy as generateImageSbom,Zi as generateLetsEncryptUserData,be as generateLogicalId,Qd as generateManualPipeline,Zd as generateMatrixWorkflow,eu as generateMultiEnvConfig,jd as generateMultiEnvPipeline,Gd as generateMultiEnvWorkflow,Kd as generatePRPreviewWorkflow,nu as generateParallelConfig,Sm as generatePhpFpmConfig,em as generatePhpLayerDockerfile,Jd as generatePreviewPipeline,vl as generatePreviewWorkflow,Ae as generateResourceName,tu as generateScheduledConfig,Yd as generateScheduledPipeline,Ud as generateScheduledWorkflow,ci as generateStaticSiteTemplate,pn as generateUbuntuAppCloudInit,Rc as getAccountId,bd as getAllRegions,Id as getClosestRegion,td as getCommandUsage,Lf as getComposeTemplate,_m as getConfig,Jl as getContextualHelp,Cc as getCredentials,gl as getDeploymentStrategy,hl as getDiffStats,pl as getDiffSummary,Nc as getErrorDetails,Al as getLocalConfig,Tl as getLocalCredentials,Rl as getLocalEndpoint,$l as getLocalEnvVars,Hc as getQuotaUsageSummary,_d as getRecommendedStructure,Ad as getRegion,vd as getRegionStats,Td as getRegionsByCompliance,Rd as getRegionsByLocation,$d as getRegionsByPricingTier,_c as getRequiredPermissions,Ta as getSigningKeyCacheSize,Ka as getTimestamp,Zn as globMatches,cn as globToRegex,hd as globalResourceManager,Sh as governingLimitCents,mu as guardDutyManager,wy as handleSpendRequest,on as hasAutoWwwVariant,Ys as hasManagementDashboardSite,Xr as hasProxyUpstream,Jc as hashBuffer,Yc as hashDirectory,qc as hashFile,Qc as hashManifest,jc as hashString,km as healthCheckManager,ue as hostAcceptsIpv6,ae as hostCondition,Gm as hotp,ih as hourBucket,oh as hourBucketsBetween,ju as imageScanningManager,hi as infraEnvFromOutputs,ft as inspectInvocation,sm as installRecursionFetch,ui as invalidateCache,om as invocationContext,jl as isLikelyTypo,bl as isLocalDevelopment,ec as isManagementDashboardSiteName,$a as isNodeCryptoAvailable,Dh as isOperationAllowed,Pt as isQuietHours,sn as isSafePattern,xa as isStatePath,Ot as isValidCidr,Pd as isValidRegion,Qg as isValidTimeZone,Pa as isWebCryptoAvailable,OC as jobProviderCapability,_t as keyMatchesFilters,sp as lambdaConcurrencyManager,mp as lambdaDLQManager,lp as lambdaDestinationsManager,np as lambdaLayersManager,up as lambdaVPCManager,op as lambdaVersionsManager,pC as lambdaWorkloads,bm as laravelServerlessEnvDefaults,xf as listComposeTemplates,Fg as listSourceReferences,Bm as loadCloudConfig,iy as loadTelemetryPolicy,wu as logsManager,zh as lookbackHoursForSignal,_a as mailEnabled,Wa as mailFirewallPorts,vS as maintenanceWindowOpen,ya as makeAWSRequest,Sa as makeAWSRequestAsync,Ca as makeAWSRequestOnce,Xs as managementDashboardSiteName,PS as manifestDigest,Zm as matchTotpCounter,Ni as mediaObjectHeaders,Eh as median,wh as medianAbsoluteDeviation,bh as mergeDecisions,ac as mergeInfrastructure,Jg as mergePriceBooks,dh as meterTelemetry,Du as metricsManager,Bt as migrateObjectStorage,ku as migrationManager,xd as multiAccountManager,dd as multiRegionManager,Yi as needsRenewal,Lm as networkSecurityManager,EC as nextScheduleRuns,qr as normalizePublicIpv6,aC as normalizeRuntimeStatus,DC as normalizeScheduleExpression,Og as normalizeSourceEvent,hn as normalizeSshPublicKey,ry as normalizeTelemetryPolicy,Ny as openApiDocument,Wh as optionsForSignal,Ld as organizationManager,Dm as packagePhpApp,Kp as packageServerlessApp,rl as parallel,il as parallelMap,ol as parallelWithRetry,mt as parseChain,vf as parseCompose,Ff as parseComposeCatalog,mC as parseDockerInspect,rA as parseDotenv,ba as parseJSONResponse,hC as parseSystemdRecords,Aa as parseXMLResponse,ly as pathTemplate,hh as percentOfLimit,Fu as performanceManager,Xp as phpLayerBuildStage,Qp as phpLayerPackages,Am as phpRuntimeLayerAssets,Vf as planComposeTemplateUpgrade,$h as planEnforcement,Lt as planMitigation,nr as planZoneMigration,Yt as policyTag,Ol as previewManager,Ll as previewNotifications,wC as previewSchedule,nh as previousBudgetWindow,Zg as priceUsage,qg as priceUsageLines,de as probeOriginTls,dl as processInChunks,vg as processSourceWebhook,tC as productionChangeReview,Tu as progressiveDeploymentManager,gh as projectSpend,ht as propagationHeaders,Wt as providerEndpoint,DS as publicKeyFingerprint,Qt as qualifyName,_p as queueManagementManager,Xc as quickHash,Yn as rateLimitHeaders,jn as rateLimitKey,Jr as reconcileAddressRecords,ot as reconcileCloudflareCdn,er as reconcileDeclaredRecords,kC as reconcileJobObservation,Vg as reconcileSourceWebhook,eC as recordDashboardHostPosture,Qy as recordPreDeploySecretScan,Xy as recordSkippedSecretScan,yt as recursionBlockedResponse,sC as redactRuntimeConfig,sy as redactTelemetryText,cy as redactTelemetryValue,Si as redeployServerlessApp,yd as regionPairManager,fg as releaseStrategyCapabilities,Cg as releaseTrafficPlan,Gn as reloadRpxGateway,Vt as remapKey,_g as removeSourceWebhook,Zr as removeStaleServerAddressRecords,Mf as renderComposeTemplate,xt as renderDdosInstallScript,kt as renderNftablesRuleset,vC as renderServerCron,Nt as renderSysctlFile,ln as renderWafConfig,dn as renderWafInstallScript,Kn as renewRpxCertificates,Lu as replicaManager,Dy as requestHash,ml as requiresReplacement,lm as resetRecursionRuntime,pm as resolveApp,Va as resolveAppDatabase,nf as resolveAuthEncryptionKey,Ha as resolveCloudProvider,st as resolveCloudflareCdnPlan,Ac as resolveCredentials,Pi as resolveDashboardAction,Vn as resolveDashboardAuth,js as resolveDashboardDomain,Js as resolveDashboardDomains,Xt as resolveDeclaredRecords,Qa as resolveDeployBucketName,Ma as resolveDeploymentMode,Nn as resolveExecStart,gn as resolveHetznerApiToken,Ba as resolveMailService,rc as resolveManagementDashboardSite,tc as resolveManagementDashboardSites,zt as resolveObjectStorage,Za as resolveProjectStackName,Qr as resolveProxyUpstreams,jp as resolveQueueNames,Qf as resolveQueuedDeploymentCommand,qp as resolveQueues,am as resolveRecursionConfig,bc as resolveRegion,RC as resolveRuntimeInventory,Xa as resolveServerlessAppStackName,es as resolveServerlessArtifactBucketName,ts as resolveServerlessAssetBucketName,Zp as resolveServerlessRuntime,Ja as resolveSiteBucketName,en as resolveSiteDeployTarget,tn as resolveSiteKind,ja as resolveSiteResourceName,qa as resolveSiteStackName,ka as resolveStatePath,Ya as resolveStorageBucketName,_n as resolveUiSource,xe as resolveZoneApex,Fm as resourceManagementManager,fm as responseToResult,Oh as robustZScore,pf as roleCapabilities,Ag as rollbackImmutableRelease,Ai as rollbackServerlessApp,jg as roundCents,Sp as route53ResolverManager,gp as route53RoutingManager,Mh as routeMatches,qn as ruleMatches,zp as runBuildHooks,Ph as runEnforcement,Pm as runPhpBuildHooks,Ri as runRemoteCommand,nC as runtimeId,Ti as sanitizeCloudConfig,Rf as sanitizeControlPlaneValue,Ua as sanitizeName,of as sanitizeOidcReturnPath,oy as saveTelemetryPolicy,Fy as scanForSecrets,mf as scopeContains,ph as scopeKey,Pn as scpUpload,Yl as searchCommands,$f as searchControlPlane,Hu as secretsManager,Wu as secretsRotationManager,rC as secureContainerRelease,gu as securityHubManager,Zu as securityScanningManager,Jy as securityScope,tf as sendAuthenticationEmail,Pp as senderReputationManager,al as sequence,nA as serializeDotenv,vn as serverPublicIpv4,tp as serviceMeshManager,bi as setMaintenance,Oa as setStateDir,ji as setupDns01Challenge,Hp as sha256,cm as sharedRecursionGuard,rm as sharedRuntimeLoop,nn as shipsARelease,wi as signCloudFrontCookies,Ei as signCloudFrontUrl,ma as signRequest,fa as signRequestAsync,_h as signalDefinition,hy as spendNotificationText,Oy as spendOpenApiPaths,Tn as sshExec,$n as sshExecOrThrow,Cd as stackDependencyManager,Ii as startLocalDashboardServer,Ry as startSpendLoop,va as stateDir,Na as statePath,wm as staticSiteManager,vm as storageAdvancedManager,Uh as streamFocusJsonl,Ih as strongestActiveAction,Zl as suggestCommand,Xl as suggestFlags,Bc as suggestIAMPolicy,Gc as suggestQuotaIncrease,Ed as suggestRegionPairs,Dd as suggestRegions,Mg as syncSourceRepositories,dg as synchronizeComposeVolumes,lA as synchronizeConfiguredConfiguration,_C as synchronizeConfiguredJobs,vu as syntheticsManager,vt as sysctlHardening,yC as systemdWorkloads,py as telemetryBucketLabel,dy as telemetryCursor,ay as telemetryEstimatedMonthlyCost,uy as telemetryPercentile,ny as telemetryPolicyKey,Zc as templateCache,Lg as testSourceConnection,Kg as tieredMicroCents,le as toCloudflareZoneSettings,Kh as toFocusJsonl,Gh as toFocusRecords,Km as totp,qm as totpUri,iC as unsupportedCapabilities,tg as unsupportedVolumeCapabilities,wS as updateCompatibility,di as uploadStaticFiles,ch as usageDeltaKey,th as utcInstantOfLocal,Wd as validateAccountStructure,Cl as validateAgainstSchema,ig as validateAttachment,FS as validateBackupDestination,rd as validateCommand,Lc as validateConfiguration,Fc as validateCredentials,rn as validateDeploymentConfig,ng as validateMountPath,je as validateResourceLimits,He as validateTemplate,qe as validateTemplateSize,Yr as verifyAddressRecord,jy as verifyArtifactSignature,vi as verifyMediaAccessToken,Um as verifyTotp,ES as verifyUpdateSignature,or as verifyZoneParity,rg as volumeCapabilities,un as wafEventTelemetry,Dn as waitForCloudInit,In as waitForSsh,Ng as webhookEndpoint,uc as withCDN,dc as withCache,lc as withDatabase,um as withInvocation,sc as withMonitoring,pc as withQueue,cc as withSecurity,sl as withTimeout,yn as wrapCloudInitUserData,Pu as xrayManager,lS as zeroCapacity,qh as zeroFill,eh as zoneOffsetMs,Xg as zonedParts};