@stacksjs/ts-cloud 0.16.24 → 0.16.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/aws/index.js +1 -1
  2. package/dist/bin/{chunk-0md2h0an.js → chunk-0xxc6dy8.js} +6 -6
  3. package/dist/bin/{chunk-257sygzm.js → chunk-21jwbrap.js} +1 -1
  4. package/dist/bin/{chunk-4sq6cvz5.js → chunk-3kvz4kyq.js} +2 -2
  5. package/dist/bin/chunk-4261t3bq.js +1 -0
  6. package/dist/bin/chunk-4a98nszr.js +1 -0
  7. package/dist/bin/{chunk-prj5b597.js → chunk-4r46kw46.js} +2 -2
  8. package/dist/bin/chunk-5mk3sxpw.js +34 -0
  9. package/dist/bin/{chunk-k9mzq7z9.js → chunk-78tzgf65.js} +1 -1
  10. package/dist/bin/{chunk-hez48c69.js → chunk-82sbpydz.js} +2 -2
  11. package/dist/bin/{chunk-wffaqgcc.js → chunk-8wnpx6n2.js} +24 -24
  12. package/dist/bin/{chunk-c35qm7as.js → chunk-9066j2kz.js} +1 -1
  13. package/dist/bin/{chunk-8e7n357e.js → chunk-9rya3733.js} +58 -58
  14. package/dist/bin/chunk-ajv4z454.js +1 -0
  15. package/dist/bin/chunk-aqreqn37.js +1 -0
  16. package/dist/bin/chunk-cnmngqqg.js +1 -0
  17. package/dist/bin/{chunk-0ytk5g2t.js → chunk-db9zx72q.js} +1 -1
  18. package/dist/bin/{chunk-5kc8s9gp.js → chunk-dh6kj6ce.js} +2 -2
  19. package/dist/bin/chunk-dhj4786e.js +1 -0
  20. package/dist/bin/chunk-eh3235zq.js +1 -0
  21. package/dist/bin/chunk-es4sdbrr.js +1 -0
  22. package/dist/bin/{chunk-wfa8j3wg.js → chunk-fdsh3m2q.js} +2 -2
  23. package/dist/bin/{chunk-r3hkc2s3.js → chunk-g0gqwszk.js} +1 -1
  24. package/dist/bin/{chunk-1fde3e2c.js → chunk-gj530nqd.js} +1 -1
  25. package/dist/bin/{chunk-jwdcx0mm.js → chunk-h1618tyv.js} +1 -1
  26. package/dist/bin/chunk-hje6rsxj.js +2 -0
  27. package/dist/bin/chunk-ksfr2ya8.js +1 -0
  28. package/dist/bin/{chunk-d1psxeqj.js → chunk-mdbzfvba.js} +1 -1
  29. package/dist/bin/{chunk-4y20ry45.js → chunk-mfer1e5z.js} +1 -1
  30. package/dist/bin/{chunk-3b8a3knq.js → chunk-mrte8smv.js} +1 -1
  31. package/dist/bin/{chunk-hjv1k8s9.js → chunk-n5zwm2z4.js} +5 -5
  32. package/dist/bin/chunk-n8ya6q6d.js +2 -0
  33. package/dist/bin/{chunk-m2gwzksz.js → chunk-ntmnpteh.js} +6 -6
  34. package/dist/bin/{chunk-6eesa8d1.js → chunk-nxyhheav.js} +1 -1
  35. package/dist/bin/chunk-p1cv4n00.js +2 -0
  36. package/dist/bin/chunk-s7axkfrs.js +1 -0
  37. package/dist/bin/{chunk-jdfbahjb.js → chunk-t5gkbppg.js} +14 -14
  38. package/dist/bin/{chunk-988qv730.js → chunk-td8zgch7.js} +4 -4
  39. package/dist/bin/{chunk-5x59x4qw.js → chunk-tnzp96vn.js} +1 -1
  40. package/dist/bin/{chunk-9e7pqhj1.js → chunk-v4e4726j.js} +1 -1
  41. package/dist/bin/{chunk-ax41jhq7.js → chunk-w23en85y.js} +2 -2
  42. package/dist/bin/{chunk-xh5jcv64.js → chunk-y4g86dpe.js} +3 -3
  43. package/dist/bin/chunk-yavtz60y.js +1 -0
  44. package/dist/bin/{chunk-apw5bbjg.js → chunk-z96ssb7e.js} +1 -1
  45. package/dist/bin/cli.js +283 -283
  46. package/dist/bin/dashboard-server.js +1 -1
  47. package/dist/{chunk-bzbryxfm.js → chunk-08tswmb3.js} +1 -1
  48. package/dist/{chunk-4rkjhvgw.js → chunk-0p7ddjt6.js} +9 -9
  49. package/dist/chunk-2nma0bd8.js +92 -0
  50. package/dist/chunk-31qham3c.js +1 -0
  51. package/dist/chunk-3zv0e36t.js +34 -0
  52. package/dist/{chunk-d8w90gsb.js → chunk-49p5cx21.js} +21 -21
  53. package/dist/{chunk-mv7hne2c.js → chunk-5db32a4x.js} +2 -2
  54. package/dist/chunk-7fbfmpyx.js +1 -0
  55. package/dist/{chunk-rgq7m90a.js → chunk-7p1653g6.js} +56 -56
  56. package/dist/{chunk-vtm83crj.js → chunk-826gp2kd.js} +129 -129
  57. package/dist/{chunk-hzbyj0xd.js → chunk-98qx6m9h.js} +1 -1
  58. package/dist/{chunk-zv85cpt2.js → chunk-b10n1xy5.js} +1 -1
  59. package/dist/chunk-dschvakr.js +1 -0
  60. package/dist/chunk-e44ajkha.js +5 -0
  61. package/dist/{chunk-65yh2h1e.js → chunk-jwx5t3vf.js} +11 -11
  62. package/dist/chunk-kmwnzw91.js +1 -0
  63. package/dist/{chunk-9ca1yafd.js → chunk-q0g0rjn3.js} +1 -1
  64. package/dist/{chunk-jrrw3ezm.js → chunk-r1730x8g.js} +4 -4
  65. package/dist/chunk-rxs4y74z.js +2 -0
  66. package/dist/{chunk-97trx8p9.js → chunk-setpnrtg.js} +2 -2
  67. package/dist/chunk-tvwrthfq.js +2 -0
  68. package/dist/{chunk-v7y50hhf.js → chunk-w23wrsa4.js} +70 -70
  69. package/dist/deploy/index.js +1 -1
  70. package/dist/dns/index.js +1 -1
  71. package/dist/drivers/index.js +1 -1
  72. package/dist/index.js +36 -36
  73. package/dist/operations/index.js +1 -1
  74. package/dist/protection/index.js +1 -1
  75. package/dist/spend/index.js +1 -1
  76. package/dist/ui/404.html +1 -1
  77. package/dist/ui/accept-invitation.html +1 -1
  78. package/dist/ui/access-denied.html +1 -1
  79. package/dist/ui/account/automation.html +6 -6
  80. package/dist/ui/account/security.html +2 -2
  81. package/dist/ui/applications/compose.html +6 -6
  82. package/dist/ui/applications/new.html +2 -2
  83. package/dist/ui/data/backups.html +6 -6
  84. package/dist/ui/data/services.html +6 -6
  85. package/dist/ui/data/volumes.html +6 -6
  86. package/dist/ui/index.html +6 -6
  87. package/dist/ui/infrastructure/topology.html +6 -6
  88. package/dist/ui/integrations.html +2 -2
  89. package/dist/ui/operations/alerts.html +6 -6
  90. package/dist/ui/operations/configuration.html +6 -6
  91. package/dist/ui/operations/jobs.html +6 -6
  92. package/dist/ui/operations/maintenance.html +5 -5
  93. package/dist/ui/operations/observability.html +6 -6
  94. package/dist/ui/operations/previews.html +6 -6
  95. package/dist/ui/operations/queue.html +6 -6
  96. package/dist/ui/operations/regions.html +6 -6
  97. package/dist/ui/operations/releases.html +6 -6
  98. package/dist/ui/operations/spend.html +6 -6
  99. package/dist/ui/operations/workloads.html +6 -6
  100. package/dist/ui/security.html +2 -2
  101. package/dist/ui/server/actions.html +6 -6
  102. package/dist/ui/server/activity.html +1 -1
  103. package/dist/ui/server/capacity.html +5 -5
  104. package/dist/ui/server/database.html +5 -5
  105. package/dist/ui/server/deployments.html +5 -5
  106. package/dist/ui/server/diagnostics.html +2 -2
  107. package/dist/ui/server/firewall.html +6 -6
  108. package/dist/ui/server/fleet.html +6 -6
  109. package/dist/ui/server/logs.html +6 -6
  110. package/dist/ui/server/metrics.html +5 -5
  111. package/dist/ui/server/security.html +2 -2
  112. package/dist/ui/server/services.html +2 -2
  113. package/dist/ui/server/sites.html +5 -5
  114. package/dist/ui/server/ssh-keys.html +6 -6
  115. package/dist/ui/server/team.html +6 -6
  116. package/dist/ui/server/terminal.html +2 -2
  117. package/dist/ui/serverless/alarms.html +6 -6
  118. package/dist/ui/serverless/assets.html +2 -2
  119. package/dist/ui/serverless/cost.html +2 -2
  120. package/dist/ui/serverless/data.html +6 -6
  121. package/dist/ui/serverless/deployments.html +2 -2
  122. package/dist/ui/serverless/firewall.html +2 -2
  123. package/dist/ui/serverless/functions.html +6 -6
  124. package/dist/ui/serverless/logs.html +6 -6
  125. package/dist/ui/serverless/metrics.html +2 -2
  126. package/dist/ui/serverless/queues.html +6 -6
  127. package/dist/ui/serverless/secrets.html +5 -5
  128. package/dist/ui/serverless/traces.html +6 -6
  129. package/dist/ui/serverless.html +6 -6
  130. package/package.json +3 -3
  131. package/dist/bin/chunk-6aj3h8yk.js +0 -1
  132. package/dist/bin/chunk-78w3bn85.js +0 -1
  133. package/dist/bin/chunk-9b6af1sj.js +0 -1
  134. package/dist/bin/chunk-a07jfqvs.js +0 -1
  135. package/dist/bin/chunk-a3rq51az.js +0 -2
  136. package/dist/bin/chunk-f0fpp4mk.js +0 -2
  137. package/dist/bin/chunk-fpy7nv5g.js +0 -1
  138. package/dist/bin/chunk-fq4nxfec.js +0 -1
  139. package/dist/bin/chunk-ghe1nawv.js +0 -1
  140. package/dist/bin/chunk-kf1p7s61.js +0 -1
  141. package/dist/bin/chunk-q8crt80d.js +0 -1
  142. package/dist/bin/chunk-rpfvv7hw.js +0 -2
  143. package/dist/bin/chunk-wg20x65t.js +0 -34
  144. package/dist/bin/chunk-xb82bmgf.js +0 -1
  145. package/dist/bin/chunk-xxgybh3b.js +0 -1
  146. package/dist/chunk-1ba6keyk.js +0 -1
  147. package/dist/chunk-3x9g48ey.js +0 -92
  148. package/dist/chunk-e3axmek0.js +0 -1
  149. package/dist/chunk-e7m70ex1.js +0 -2
  150. package/dist/chunk-qa6jjv3m.js +0 -1
  151. package/dist/chunk-qrchr75r.js +0 -5
  152. package/dist/chunk-rnjgde95.js +0 -1
  153. package/dist/chunk-t4ynyk8k.js +0 -34
@@ -1,26 +1,26 @@
1
- import{createRequire as er}from"node:module";import{isAbsolute as xt,join as ht,relative as cr}from"node:path";import{existsSync as He,readdirSync as gr}from"node:fs";import{join as ve}from"node:path";import{createHash as Nr}from"node:crypto";import{copyFileSync as Dr,existsSync as Nt,readdirSync as kr,readFileSync as st,statSync as $r,writeFileSync as ot}from"node:fs";import{basename as Lr,dirname as da,extname as ma,join as Je}from"node:path";import{existsSync as Ma,readFileSync as Qt}from"node:fs";import{homedir as Oa}from"node:os";import{join as xa}from"node:path";import{createHash as _a}from"node:crypto";import{existsSync as lt,mkdirSync as Ln,readdirSync as ya,readFileSync as fa,unlinkSync as Ye,writeFileSync as Mn}from"node:fs";import{join as kt}from"node:path";import{createHash as Yt}from"node:crypto";import{createReadStream as On,readdirSync as xn,statSync as St}from"node:fs";import{join as Bn,relative as _n}from"node:path";import{deflateRawSync as zn}from"node:zlib";import{execSync as Xn}from"node:child_process";import{createHash as ei}from"node:crypto";import{cpSync as ti,mkdtempSync as ai,rmSync as ri,writeFileSync as ni}from"node:fs";import{tmpdir as ii}from"node:os";import{dirname as si,isAbsolute as oi,join as Oe,resolve as ci}from"node:path";import{fileURLToPath as li}from"node:url";import{execFileSync as Tt}from"node:child_process";import{mkdtempSync as Fa,readFileSync as wt,rmSync as Ua}from"node:fs";import{tmpdir as Va}from"node:os";import{dirname as pi,join as we}from"node:path";import{fileURLToPath as gi}from"node:url";import{AsyncLocalStorage as yi}from"node:async_hooks";import{createHash as fi}from"node:crypto";import{readFileSync as Ti}from"node:fs";import{dirname as wi,join as za}from"node:path";import{fileURLToPath as Ei}from"node:url";import{execFileSync as ut}from"node:child_process";import{existsSync as Ri,mkdirSync as $i,mkdtempSync as Li,readdirSync as Mi,readFileSync as Oi,rmSync as Wi,statSync as Qa,writeFileSync as Gi}from"node:fs";import{tmpdir as Fi}from"node:os";import{join as xe,relative as Ui}from"node:path";import{execSync as Vi}from"node:child_process";import{createHash as ji}from"node:crypto";import{readdirSync as Ki,readFileSync as qi,statSync as Ya}from"node:fs";import{join as Hi,relative as Za,resolve as ua}from"node:path";var tr=Object.defineProperty,ar=(n)=>n;function rr(n,i){this[n]=ar.bind(null,i)}var Ge=(n,i)=>{for(var s in i)tr(n,s,{get:i[s],enumerable:!0,configurable:!0,set:rr.bind(i,s)})},nr=(n,i,s)=>()=>{if(n)try{i=n(n=0)}catch(o){s=[o]}if(s)throw s[0];return i},ir=er(import.meta.url);function cg(n){let i=typeof n==="string"?new URL(n):n,{hostname:s,pathname:o}=i;if(s.endsWith(".on.aws")){let h=s.match(/^[^.]+\.lambda-url\.([^.]+)\.on\.aws$/);if(h)return{service:"lambda",region:h[1]};return{service:"",region:""}}if(s.endsWith(".r2.cloudflarestorage.com"))return{service:"s3",region:"auto"};if(s.endsWith(".backblazeb2.com")){let h=s.match(/^(?:[^.]+\.)?s3\.([^.]+)\.backblazeb2\.com$/);if(h)return{service:"s3",region:h[1]};return{service:"",region:""}}let c=s.replace("dualstack.","").match(/([^.]+)\.(?:([^.]+)\.)?amazonaws\.com(?:\.cn)?$/);if(!c)return{service:"",region:""};let l=c[1],u=c[2]||"";if(u==="us-gov")u="us-gov-west-1";else if(u==="s3"||u==="s3-accelerate")u="us-east-1",l="s3";else if(l==="iot")if(s.startsWith("iot."))l="execute-api";else if(s.startsWith("data.jobs.iot."))l="iot-jobs-data";else l=o==="/mqtt"?"iotdevicegateway":"iotdata";else if(l==="autoscaling");else if(!u&&l.startsWith("s3-"))u=l.slice(3).replace(/^fips-|^external-1/,""),l="s3";else if(l.endsWith("-fips"))l=l.slice(0,-5);else if(u&&/-\d$/.test(l)&&!/-\d$/.test(u))[l,u]=[u,l];return l=Ia[l]||l,{service:l,region:u||"us-east-1"}}function O(n){let{method:i,url:s,body:o="",accessKeyId:c,secretAccessKey:l,sessionToken:u,signQuery:h=!1,expiresIn:y=86400,datetime:f}=n,b=new URL(s),C=b.hostname,T=cg(b),w=n.service||T.service,E=n.region||T.region;if(!w)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!E)throw Error("Could not detect region from URL. Please provide region explicitly.");let I=f||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),N=I.substring(0,8),D=[N,E,w,"aws4_request"].join("/"),x="AWS4-HMAC-SHA256";if(h)return sr({urlObj:b,method:i,body:o,accessKeyId:c,secretAccessKey:l,sessionToken:u,service:w,region:E,timestamp:I,date:N,credentialScope:D,algorithm:x,expiresIn:y,cache:n.cache});let R=b.pathname||"/",_=Ct(b.searchParams),B={host:C,"x-amz-date":I,...n.headers};if(u)B["x-amz-security-token"]=u;let W=Object.keys(B).some((Ee)=>Ee.toLowerCase()==="content-type");if(o&&!W)B["content-type"]="application/x-amz-json-1.0";if(w==="s3"&&!B["x-amz-content-sha256"])B["x-amz-content-sha256"]=Xe(o);let J=Aa(B),K=Ca(B),Y=B["x-amz-content-sha256"]||Xe(o),Z=[i,vt(R),_,J,K,Y].join(`
2
- `),ne=Xe(Z),de=[x,I,D,ne].join(`
3
- `),oe=n.cache??Le,le=Ta(l,N,E,w,de,oe),ie=[`${x} Credential=${c}/${D}`,`SignedHeaders=${K}`,`Signature=${le}`].join(", ");return B.authorization=ie,{url:s,method:i,headers:B,body:o||void 0}}async function dg(n){let{method:i,url:s,body:o="",accessKeyId:c,secretAccessKey:l,sessionToken:u,signQuery:h=!1,expiresIn:y=86400,datetime:f}=n,b=new URL(s),C=b.hostname,T=cg(b),w=n.service||T.service,E=n.region||T.region;if(!w)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!E)throw Error("Could not detect region from URL. Please provide region explicitly.");let I=f||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),N=I.substring(0,8),D=[N,E,w,"aws4_request"].join("/"),x="AWS4-HMAC-SHA256";if(h)return or({urlObj:b,method:i,body:o,accessKeyId:c,secretAccessKey:l,sessionToken:u,service:w,region:E,timestamp:I,date:N,credentialScope:D,algorithm:x,expiresIn:y,cache:n.cache});let R=b.pathname||"/",_=Ct(b.searchParams),B={host:C,"x-amz-date":I,...n.headers};if(u)B["x-amz-security-token"]=u;let W=Object.keys(B).some((Fe)=>Fe.toLowerCase()==="content-type");if(o&&!W)B["content-type"]="application/x-amz-json-1.0";let J=await mt(o);if(w==="s3"&&!B["x-amz-content-sha256"])B["x-amz-content-sha256"]=J;let K=Aa(B),Y=Ca(B),Z=B["x-amz-content-sha256"]||J,ne=[i,vt(R),_,K,Y,Z].join(`
4
- `),de=await mt(ne),oe=[x,I,D,de].join(`
5
- `),le=n.cache??Le,ie=await wa(l,N,E,w,oe,le),Ee=[`${x} Credential=${c}/${D}`,`SignedHeaders=${Y}`,`Signature=${ie}`].join(", ");return B.authorization=Ee,{url:s,method:i,headers:B,body:o||void 0}}function sr(n){let{urlObj:i,method:s,body:o,accessKeyId:c,secretAccessKey:l,sessionToken:u,service:h,region:y,timestamp:f,date:b,credentialScope:C,algorithm:T,expiresIn:w,cache:E}=n,I=new URL(i.toString());I.searchParams.set("X-Amz-Algorithm",T),I.searchParams.set("X-Amz-Credential",`${c}/${C}`),I.searchParams.set("X-Amz-Date",f),I.searchParams.set("X-Amz-Expires",String(w));let N=h==="s3"?"UNSIGNED-PAYLOAD":Xe(o);if(h==="s3")I.searchParams.set("X-Amz-Content-Sha256",N);let D="host";if(I.searchParams.set("X-Amz-SignedHeaders",D),u)I.searchParams.set("X-Amz-Security-Token",u);let x=vt(I.pathname||"/"),R=`host:${I.hostname}
6
- `,_=Ct(I.searchParams),B=[s,x,_,R,D,N].join(`
7
- `),W=[T,f,C,Xe(B)].join(`
8
- `),J=Ta(l,b,y,h,W,E??Le);return I.searchParams.set("X-Amz-Signature",J),{url:I.toString(),method:s,headers:{},body:o||void 0}}async function or(n){let{urlObj:i,method:s,body:o,accessKeyId:c,secretAccessKey:l,sessionToken:u,service:h,region:y,timestamp:f,date:b,credentialScope:C,algorithm:T,expiresIn:w,cache:E}=n,I=new URL(i.toString());I.searchParams.set("X-Amz-Algorithm",T),I.searchParams.set("X-Amz-Credential",`${c}/${C}`),I.searchParams.set("X-Amz-Date",f),I.searchParams.set("X-Amz-Expires",String(w));let N=h==="s3"?"UNSIGNED-PAYLOAD":await mt(o);if(h==="s3")I.searchParams.set("X-Amz-Content-Sha256",N);let D="host";if(I.searchParams.set("X-Amz-SignedHeaders",D),u)I.searchParams.set("X-Amz-Security-Token",u);let x=vt(I.pathname||"/"),R=`host:${I.hostname}
9
- `,_=Ct(I.searchParams),B=[s,x,_,R,D,N].join(`
10
- `),W=[T,f,C,await mt(B)].join(`
11
- `),J=await wa(l,b,y,h,W,E??Le);return I.searchParams.set("X-Amz-Signature",J),{url:I.toString(),method:s,headers:{},body:o||void 0}}function nA(n){let{url:i,method:s="GET",expiresIn:o=3600,...c}=n,l=Math.min(o,604800);return O({...c,url:i,method:s,signQuery:!0,expiresIn:l}).url}async function pI(n){let{url:i,method:s="GET",expiresIn:o=3600,...c}=n,l=Math.min(o,604800);return(await dg({...c,url:i,method:s,signQuery:!0,expiresIn:l})).url}function Aa(n){return Object.keys(n).sort().map((i)=>`${i.toLowerCase()}:${n[i].trim().replace(/\s+/g," ")}`).join(`
1
+ import{createRequire as er}from"node:module";import{isAbsolute as xt,join as ht,relative as cr}from"node:path";import{existsSync as He,readdirSync as gr}from"node:fs";import{join as ve}from"node:path";import{createHash as Nr}from"node:crypto";import{copyFileSync as Dr,existsSync as Nt,readdirSync as kr,readFileSync as st,statSync as $r,writeFileSync as ot}from"node:fs";import{basename as Lr,dirname as da,extname as ma,join as Je}from"node:path";import{existsSync as Ma,readFileSync as Qt}from"node:fs";import{homedir as Oa}from"node:os";import{join as xa}from"node:path";import{createHash as _a}from"node:crypto";import{existsSync as lt,mkdirSync as Ln,readdirSync as ya,readFileSync as fa,unlinkSync as Ye,writeFileSync as Mn}from"node:fs";import{join as kt}from"node:path";import{createHash as Yt}from"node:crypto";import{createReadStream as On,readdirSync as xn,statSync as St}from"node:fs";import{join as Bn,relative as _n}from"node:path";import{deflateRawSync as zn}from"node:zlib";import{execSync as Xn}from"node:child_process";import{createHash as ei}from"node:crypto";import{cpSync as ti,mkdtempSync as ai,rmSync as ri,writeFileSync as ni}from"node:fs";import{tmpdir as ii}from"node:os";import{dirname as si,isAbsolute as oi,join as Oe,resolve as ci}from"node:path";import{fileURLToPath as li}from"node:url";import{execFileSync as Tt}from"node:child_process";import{mkdtempSync as Fa,readFileSync as wt,rmSync as Ua}from"node:fs";import{tmpdir as Va}from"node:os";import{dirname as pi,join as we}from"node:path";import{fileURLToPath as gi}from"node:url";import{AsyncLocalStorage as yi}from"node:async_hooks";import{createHash as fi}from"node:crypto";import{readFileSync as Ti}from"node:fs";import{dirname as wi,join as za}from"node:path";import{fileURLToPath as Ei}from"node:url";import{execFileSync as ut}from"node:child_process";import{existsSync as Ri,mkdirSync as $i,mkdtempSync as Li,readdirSync as Mi,readFileSync as Oi,rmSync as Wi,statSync as Qa,writeFileSync as Gi}from"node:fs";import{tmpdir as Fi}from"node:os";import{join as xe,relative as Ui}from"node:path";import{execSync as Vi}from"node:child_process";import{createHash as ji}from"node:crypto";import{readdirSync as Ki,readFileSync as qi,statSync as Ya}from"node:fs";import{join as Hi,relative as Za,resolve as ua}from"node:path";var tr=Object.defineProperty,ar=(n)=>n;function rr(n,i){this[n]=ar.bind(null,i)}var Ge=(n,i)=>{for(var s in i)tr(n,s,{get:i[s],enumerable:!0,configurable:!0,set:rr.bind(i,s)})},nr=(n,i,s)=>()=>{if(n)try{i=n(n=0)}catch(o){s=[o]}if(s)throw s[0];return i},ir=er(import.meta.url);function cg(n){let i=typeof n==="string"?new URL(n):n,{hostname:s,pathname:o}=i;if(s.endsWith(".on.aws")){let h=s.match(/^[^.]+\.lambda-url\.([^.]+)\.on\.aws$/);if(h)return{service:"lambda",region:h[1]};return{service:"",region:""}}if(s.endsWith(".r2.cloudflarestorage.com"))return{service:"s3",region:"auto"};if(s.endsWith(".backblazeb2.com")){let h=s.match(/^(?:[^.]+\.)?s3\.([^.]+)\.backblazeb2\.com$/);if(h)return{service:"s3",region:h[1]};return{service:"",region:""}}let c=s.replace("dualstack.","").match(/([^.]+)\.(?:([^.]+)\.)?amazonaws\.com(?:\.cn)?$/);if(!c)return{service:"",region:""};let l=c[1],u=c[2]||"";if(u==="us-gov")u="us-gov-west-1";else if(u==="s3"||u==="s3-accelerate")u="us-east-1",l="s3";else if(l==="iot")if(s.startsWith("iot."))l="execute-api";else if(s.startsWith("data.jobs.iot."))l="iot-jobs-data";else l=o==="/mqtt"?"iotdevicegateway":"iotdata";else if(l==="autoscaling");else if(!u&&l.startsWith("s3-"))u=l.slice(3).replace(/^fips-|^external-1/,""),l="s3";else if(l.endsWith("-fips"))l=l.slice(0,-5);else if(u&&/-\d$/.test(l)&&!/-\d$/.test(u))[l,u]=[u,l];return l=Ia[l]||l,{service:l,region:u||"us-east-1"}}function O(n){let{method:i,url:s,body:o="",accessKeyId:c,secretAccessKey:l,sessionToken:u,signQuery:h=!1,expiresIn:y=86400,datetime:f}=n,S=new URL(s),b=S.hostname,v=cg(S),w=n.service||v.service,E=n.region||v.region;if(!w)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!E)throw Error("Could not detect region from URL. Please provide region explicitly.");let P=f||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),R=P.substring(0,8),D=[R,E,w,"aws4_request"].join("/"),x="AWS4-HMAC-SHA256";if(h)return sr({urlObj:S,method:i,body:o,accessKeyId:c,secretAccessKey:l,sessionToken:u,service:w,region:E,timestamp:P,date:R,credentialScope:D,algorithm:x,expiresIn:y,cache:n.cache});let I=S.pathname||"/",_=Ct(S.searchParams),B={host:b,"x-amz-date":P,...n.headers};if(u)B["x-amz-security-token"]=u;let W=Object.keys(B).some((Ee)=>Ee.toLowerCase()==="content-type");if(o&&!W)B["content-type"]="application/x-amz-json-1.0";if(w==="s3"&&!B["x-amz-content-sha256"])B["x-amz-content-sha256"]=Xe(o);let J=Aa(B),K=Ca(B),Y=B["x-amz-content-sha256"]||Xe(o),Z=[i,vt(I),_,J,K,Y].join(`
2
+ `),ne=Xe(Z),de=[x,P,D,ne].join(`
3
+ `),oe=n.cache??Le,le=Ta(l,R,E,w,de,oe),ie=[`${x} Credential=${c}/${D}`,`SignedHeaders=${K}`,`Signature=${le}`].join(", ");return B.authorization=ie,{url:s,method:i,headers:B,body:o||void 0}}async function dg(n){let{method:i,url:s,body:o="",accessKeyId:c,secretAccessKey:l,sessionToken:u,signQuery:h=!1,expiresIn:y=86400,datetime:f}=n,S=new URL(s),b=S.hostname,v=cg(S),w=n.service||v.service,E=n.region||v.region;if(!w)throw Error("Could not detect service from URL. Please provide service explicitly.");if(!E)throw Error("Could not detect region from URL. Please provide region explicitly.");let P=f||new Date().toISOString().replace(/[:-]|\.\d{3}/g,""),R=P.substring(0,8),D=[R,E,w,"aws4_request"].join("/"),x="AWS4-HMAC-SHA256";if(h)return or({urlObj:S,method:i,body:o,accessKeyId:c,secretAccessKey:l,sessionToken:u,service:w,region:E,timestamp:P,date:R,credentialScope:D,algorithm:x,expiresIn:y,cache:n.cache});let I=S.pathname||"/",_=Ct(S.searchParams),B={host:b,"x-amz-date":P,...n.headers};if(u)B["x-amz-security-token"]=u;let W=Object.keys(B).some((Fe)=>Fe.toLowerCase()==="content-type");if(o&&!W)B["content-type"]="application/x-amz-json-1.0";let J=await mt(o);if(w==="s3"&&!B["x-amz-content-sha256"])B["x-amz-content-sha256"]=J;let K=Aa(B),Y=Ca(B),Z=B["x-amz-content-sha256"]||J,ne=[i,vt(I),_,K,Y,Z].join(`
4
+ `),de=await mt(ne),oe=[x,P,D,de].join(`
5
+ `),le=n.cache??Le,ie=await wa(l,R,E,w,oe,le),Ee=[`${x} Credential=${c}/${D}`,`SignedHeaders=${Y}`,`Signature=${ie}`].join(", ");return B.authorization=Ee,{url:s,method:i,headers:B,body:o||void 0}}function sr(n){let{urlObj:i,method:s,body:o,accessKeyId:c,secretAccessKey:l,sessionToken:u,service:h,region:y,timestamp:f,date:S,credentialScope:b,algorithm:v,expiresIn:w,cache:E}=n,P=new URL(i.toString());P.searchParams.set("X-Amz-Algorithm",v),P.searchParams.set("X-Amz-Credential",`${c}/${b}`),P.searchParams.set("X-Amz-Date",f),P.searchParams.set("X-Amz-Expires",String(w));let R=h==="s3"?"UNSIGNED-PAYLOAD":Xe(o);if(h==="s3")P.searchParams.set("X-Amz-Content-Sha256",R);let D="host";if(P.searchParams.set("X-Amz-SignedHeaders",D),u)P.searchParams.set("X-Amz-Security-Token",u);let x=vt(P.pathname||"/"),I=`host:${P.hostname}
6
+ `,_=Ct(P.searchParams),B=[s,x,_,I,D,R].join(`
7
+ `),W=[v,f,b,Xe(B)].join(`
8
+ `),J=Ta(l,S,y,h,W,E??Le);return P.searchParams.set("X-Amz-Signature",J),{url:P.toString(),method:s,headers:{},body:o||void 0}}async function or(n){let{urlObj:i,method:s,body:o,accessKeyId:c,secretAccessKey:l,sessionToken:u,service:h,region:y,timestamp:f,date:S,credentialScope:b,algorithm:v,expiresIn:w,cache:E}=n,P=new URL(i.toString());P.searchParams.set("X-Amz-Algorithm",v),P.searchParams.set("X-Amz-Credential",`${c}/${b}`),P.searchParams.set("X-Amz-Date",f),P.searchParams.set("X-Amz-Expires",String(w));let R=h==="s3"?"UNSIGNED-PAYLOAD":await mt(o);if(h==="s3")P.searchParams.set("X-Amz-Content-Sha256",R);let D="host";if(P.searchParams.set("X-Amz-SignedHeaders",D),u)P.searchParams.set("X-Amz-Security-Token",u);let x=vt(P.pathname||"/"),I=`host:${P.hostname}
9
+ `,_=Ct(P.searchParams),B=[s,x,_,I,D,R].join(`
10
+ `),W=[v,f,b,await mt(B)].join(`
11
+ `),J=await wa(l,S,y,h,W,E??Le);return P.searchParams.set("X-Amz-Signature",J),{url:P.toString(),method:s,headers:{},body:o||void 0}}function nA(n){let{url:i,method:s="GET",expiresIn:o=3600,...c}=n,l=Math.min(o,604800);return O({...c,url:i,method:s,signQuery:!0,expiresIn:l}).url}async function pI(n){let{url:i,method:s="GET",expiresIn:o=3600,...c}=n,l=Math.min(o,604800);return(await dg({...c,url:i,method:s,signQuery:!0,expiresIn:l})).url}function Aa(n){return Object.keys(n).sort().map((i)=>`${i.toLowerCase()}:${n[i].trim().replace(/\s+/g," ")}`).join(`
12
12
  `)+`
13
- `}function Ca(n){return Object.keys(n).sort().map((i)=>i.toLowerCase()).join(";")}function Ct(n){let i=[];return n.forEach((s,o)=>{i.push([Ot(o),Ot(s)])}),i.sort((s,o)=>{if(s[0]<o[0])return-1;if(s[0]>o[0])return 1;if(s[1]<o[1])return-1;if(s[1]>o[1])return 1;return 0}),i.map(([s,o])=>`${s}=${o}`).join("&")}function vt(n){return n.split("/").map((i)=>Ot(i)).join("/")}function Ot(n){return encodeURIComponent(n).replace(/[!'()*]/g,(i)=>`%${i.charCodeAt(0).toString(16).toUpperCase()}`)}function Xe(n){if(!_e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return _e.createHash("sha256").update(n,"utf8").digest("hex")}function Ve(n,i){if(!_e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return _e.createHmac("sha256",n).update(i,"utf8").digest()}async function mt(n){let i=new TextEncoder().encode(n),s=await crypto.subtle.digest("SHA-256",i);return va(new Uint8Array(s))}async function qe(n,i){let s=new TextEncoder,o=typeof n==="string"?s.encode(n):n,c=s.encode(i),l=await crypto.subtle.importKey("raw",o.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),u=await crypto.subtle.sign("HMAC",l,c.buffer);return new Uint8Array(u)}function va(n){return Array.from(n).map((i)=>i.toString(16).padStart(2,"0")).join("")}function Ta(n,i,s,o,c,l){let u=`${n}:${i}:${s}:${o}`,h=l.get(u);if(!h){let y=Ve(`AWS4${n}`,i),f=Ve(y,s),b=Ve(f,o);if(h=Ve(b,"aws4_request"),l.size>=Pa){let C=l.keys().next().value;if(C)l.delete(C)}l.set(u,h)}return Ve(h,c).toString("hex")}async function wa(n,i,s,o,c,l){let u=`${n}:${i}:${s}:${o}`,h=l.get(u);if(!h){let f=await qe(`AWS4${n}`,i),b=await qe(f,s),C=await qe(b,o);if(h=await qe(C,"aws4_request"),l.size>=Pa){let T=l.keys().next().value;if(T)l.delete(T)}l.set(u,h)}let y=await qe(h,c);return va(y)}function Ea(n,i){return i.includes(n)}function pt(n,i,s){let o=i*Math.pow(2,n),c=Math.random()*0.3*o;return Math.min(o+c,s)}function gt(n){return new Promise((i)=>setTimeout(i,n))}async function iA(n,i){let{maxRetries:s=3,initialDelayMs:o=100,maxDelayMs:c=5000,retryableStatusCodes:l=[429,500,502,503,504],timeoutMs:u=30000}=i??{},h,y;for(let f=0;f<=s;f++){let b=O(n),C={method:b.method,headers:b.headers};if(b.body)C.body=b.body;let T=new AbortController,w=setTimeout(()=>T.abort(),u);C.signal=T.signal;try{let E=await fetch(b.url,C);if(clearTimeout(w),y=E,E.ok)return E;if(f<s&&Ea(E.status,l)){let N=pt(f,o,c);await gt(N);continue}let I=await E.text();throw Error(`AWS API request failed (${E.status}): ${I}`)}catch(E){if(clearTimeout(w),h=E,E instanceof Error&&E.name==="AbortError")h=Error(`Request timed out after ${u}ms`);if(f<s&&!(E instanceof Error&&E.message.includes("AWS API request failed"))){let I=pt(f,o,c);await gt(I);continue}throw h}}throw h??Error("Request failed after retries")}async function gI(n){return iA(n,{maxRetries:0})}async function mI(n,i){let{maxRetries:s=3,initialDelayMs:o=100,maxDelayMs:c=5000,retryableStatusCodes:l=[429,500,502,503,504],timeoutMs:u=30000}=i??{},h;for(let y=0;y<=s;y++){let f=await dg(n),b={method:f.method,headers:f.headers};if(f.body)b.body=f.body;let C=new AbortController,T=setTimeout(()=>C.abort(),u);b.signal=C.signal;try{let w=await fetch(f.url,b);if(clearTimeout(T),w.ok)return w;if(y<s&&Ea(w.status,l)){let I=pt(y,o,c);await gt(I);continue}let E=await w.text();throw Error(`AWS API request failed (${w.status}): ${E}`)}catch(w){if(clearTimeout(T),h=w,w instanceof Error&&w.name==="AbortError")h=Error(`Request timed out after ${u}ms`);if(y<s&&!(w instanceof Error&&w.message.includes("AWS API request failed"))){let E=pt(y,o,c);await gt(E);continue}throw h}}throw h??Error("Request failed after retries")}async function hI(n){let i=await n.text(),s={},o=/<(\w+)>([^<]+)<\/\1>/g,c;while((c=o.exec(i))!==null){let[,l,u]=c;s[l]=u}return s}async function fI(n){return await n.json()}function yI(){Le.clear()}function II(){return Le.size}function SI(){return _e!==void 0}function CI(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var _e,Le,Pa=100,Ia,rt=nr(async()=>{try{_e=await import("node:crypto")}catch{}Le=new Map,Ia={appstream2:"appstream",cloudhsmv2:"cloudhsm",email:"ses",marketplace:"aws-marketplace",mobile:"AWSMobileHubService",pinpoint:"mobiletargeting",queue:"sqs","git-codecommit":"codecommit","mturk-requester-sandbox":"mturk-requester","personalize-runtime":"personalize"}}),EI={backgroundJobs:{visibilityTimeout:120,messageRetentionPeriod:604800,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0},fifo:{fifo:!0,contentBasedDeduplication:!0,visibilityTimeout:30,encrypted:!0},highThroughput:{visibilityTimeout:30,receiveMessageWaitTime:20,encrypted:!0},delayed:{delaySeconds:60,visibilityTimeout:60,encrypted:!0},longRunning:{visibilityTimeout:900,messageRetentionPeriod:1209600,deadLetterQueue:!0,maxReceiveCount:2,encrypted:!0},monitored:{visibilityTimeout:60,messageRetentionPeriod:604800,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0,alarms:{enabled:!0,queueDepthThreshold:1000,messageAgeThreshold:3600,dlqAlarm:!0}},lambdaOptimized:{visibilityTimeout:360,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0},fanOut:{visibilityTimeout:30,receiveMessageWaitTime:20,encrypted:!0}},bI={serverless:{development:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:!0},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:1000,handlerMemory:128}},production:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:30,inactivityTimeout:60}},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST",pointInTimeRecovery:!0,connectionTTL:86400}},scaling:{maxConnections:50000,messagesPerSecond:5000,handlerMemory:256,handlerTimeout:30},monitoring:{enabled:!0,connectionThreshold:40000,errorThreshold:100,latencyThreshold:500},keepAlive:!0,keepAliveInterval:30,idleTimeout:600},notifications:{enabled:!0,mode:"serverless",channels:{public:!1,private:!0,presence:!1},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:50000,messagesPerSecond:2000,handlerMemory:128},keepAlive:!0,keepAliveInterval:60,idleTimeout:1800}},server:{development:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"ws",driver:"bun",idleTimeout:120,perMessageDeflate:!1,metrics:!1}},production:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,maxPayloadLength:16777216,backpressureLimit:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"broadcasting:"},rateLimit:{enabled:!0,max:100,window:60000,perChannel:!0,perUser:!0},loadManagement:{enabled:!0,maxConnections:1e4,maxSubscriptionsPerConnection:100,shedLoadThreshold:0.8},metrics:!0,autoScaling:{min:2,max:10,targetCPU:70}},monitoring:{enabled:!0,connectionThreshold:8000,errorThreshold:100}},highPerformance:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:60,maxPayloadLength:8388608,backpressureLimit:2097152,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!0,instances:4,redis:{enabled:!0,useElastiCache:!0,keyPrefix:"rt:"},rateLimit:{enabled:!0,max:200,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:25000,maxSubscriptionsPerConnection:50,shedLoadThreshold:0.7},metrics:{enabled:!0,path:"/metrics"},autoScaling:{min:4,max:20,targetCPU:60,targetConnections:20000}},monitoring:{enabled:!0,connectionThreshold:80000,errorThreshold:50,latencyThreshold:50}},chat:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:200,heartbeatInterval:20,inactivityTimeout:60}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:300,maxPayloadLength:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"chat:"},rateLimit:{enabled:!0,max:60,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:15000,maxSubscriptionsPerConnection:20},metrics:!0},keepAlive:!0,keepAliveInterval:25,idleTimeout:900},gaming:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:10,inactivityTimeout:30}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:30,maxPayloadLength:65536,backpressureLimit:524288,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!1,instances:4,redis:{enabled:!0,useElastiCache:!0},rateLimit:{enabled:!0,max:120,window:60000},loadManagement:{enabled:!0,maxConnections:5000,maxSubscriptionsPerConnection:10,shedLoadThreshold:0.6},metrics:!0,autoScaling:{min:4,max:16,targetCPU:50}},keepAlive:!0,keepAliveInterval:10,idleTimeout:60},single:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,sendPings:!0,perMessageDeflate:!0,instances:1,rateLimit:{enabled:!0,max:100,window:60000},loadManagement:{enabled:!0,maxConnections:1e4},metrics:!0}}}},lg=".ts-cloud",ug="TS_CLOUD_STATE_DIR",Ft=null;function Cd(n){Ft=n?.trim()||null}function Ed(){return Boolean(process.env[ug]?.trim()||Ft)}function lo(){return process.env[ug]?.trim()||Ft||lg}function L(...n){return ht(lo(),...n)}function d(n,...i){let s=lo();return xt(s)?ht(s,...i):ht(n,s,...i)}function bd(n,i=process.cwd()){let s=(c,l)=>{let u=cr(c,l);return u===""||!u.startsWith("..")&&!xt(u)},o=xt(n)?n:ht(i,n);return s(d(i),o)}function pg(n){let i=n.infrastructure?.compute!=null,s=Object.values(n.environments??{}).some((o)=>o?.app!=null);return{server:i,serverless:s}}function M(n){if(n.mode==="server"||n.mode==="serverless")return n.mode;let{serverless:i}=pg(n);return i?"serverless":"server"}function vd(n){let{server:i,serverless:s}=pg(n);if(i&&s)return"A project cannot be both a server and a serverless deployment. Found `infrastructure.compute` (server) AND `environments.<env>.app` (serverless Lambda). Keep one: remove `infrastructure.compute` for a serverless app, or remove `environments.<env>.app` for a server.";if(n.mode==="server"&&s&&!i)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(n.mode==="serverless"&&i&&!s)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function p(n){return n.infrastructure?.appDatabase??n.infrastructure?.compute?.database}function lr(n){return typeof n==="object"&&n!==null?n:{}}function sA(n){return n===!0||typeof n==="object"&&n!==null}function ur(n,i){let s=i?n.environments?.[i]:void 0;if(s?.domain)return s.domain;let o=Object.values(n.sites??{}),c=n.sites?.main?.domain??o.find((l)=>l.domain)?.domain;if(c)return c;return`${n.project?.slug??"app"}.local`}function dr(n){let i=n.indexOf(".");return i>0?n.slice(i+1):void 0}function Di(n,i={}){let s=n.infrastructure?.compute?.managedServices?.mail,o=lr(s),c=i.environmentType??(i.environment?n.environments?.[i.environment]?.type:void 0),l=o.mode??(c==="production"?"server":"catcher"),u=l==="server",h=ur(n,i.environment),y=o.hostname??(u?`mail.${h}`:"localhost"),f=o.ports??{},b=u?{smtp:f.smtp??25,submission:f.submission??587,submissions:f.submissions??465,imap:f.imap??143,imaps:f.imaps??993,webmail:f.webmail??8080,managesieve:f.managesieve}:{smtp:f.smtp??1025,submission:f.submission,submissions:f.submissions,imap:f.imap,imaps:f.imaps,webmail:f.webmail??8025,managesieve:f.managesieve},C=o.tls??{},T=C.enabled??u,w=!!(C.certPath&&C.keyPath),E=(o.accounts??[]).map((K)=>({address:K.address,password:K.password})),I=typeof o.dkim==="object"&&o.dkim!==null?o.dkim:{},N=o.dkim===!1?!1:o.dkim===!0||u,D=typeof o.webmail==="object"&&o.webmail!==null?o.webmail:{},x=o.webmail===!1?!1:D.enabled??!0,R=o.spam??{},_=o.delivery??(u?"direct":"none"),B=o.expose??u,W=dr(y),J=[...new Set([y,...W?[W]:[],...o.domains??[]])];return{enabled:sA(s),mode:l,version:o.version,hostname:y,domains:J,ports:b,tls:{enabled:T,acme:T&&!w&&(C.acme??!0),certPath:C.certPath,keyPath:C.keyPath,requireForAuth:C.requireForAuth??(T&&u),acmeEmail:C.acmeEmail??E[0]?.address},dkim:{enabled:N,selector:I.selector??"default",rotate:I.rotate??!1,rotateIntervalDays:I.rotateIntervalDays??90},webmail:{enabled:x,port:D.port??b.webmail,domain:D.domain},delivery:_,sesRegion:o.sesRegion??"us-east-1",accounts:E,storagePath:o.storagePath??"/var/lib/mail",maxMessageSize:o.maxMessageSize??26214400,spam:{enabled:R.enabled??u,enforce:R.enforce??!1,junkScore:R.junkScore??5,rejectScore:R.rejectScore??12,dnsbl:R.dnsbl??u,greylist:R.greylist??!1},webhookUrl:o.webhookUrl,expose:B,bindAddress:B?"0.0.0.0":"127.0.0.1"}}function Td(n){if(!n.enabled||!n.expose)return[];let i=[n.ports.smtp,n.ports.submission,n.ports.submissions,n.ports.imap,n.ports.imaps,n.ports.managesieve].filter((s)=>typeof s==="number");if(n.webmail.enabled&&!n.webmail.domain)i.push(n.webmail.port);return[...new Set(i)].sort((s,o)=>s-o)}function wd(n){if(!n.enabled)return{};let i=n.ports.submission??n.ports.smtp,s={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(i)};if(n.mode==="server"){s.MAIL_ENCRYPTION=n.tls.enabled?"tls":"null";let o=n.accounts[0];if(o)s.MAIL_USERNAME=o.address,s.MAIL_PASSWORD=o.password}else s.MAIL_ENCRYPTION="null",s.MAIL_USERNAME="null",s.MAIL_PASSWORD="null";return s}function ge(n){if(n.cloud?.provider)return n.cloud.provider;if(n.ssh?.hosts?.length)return"ssh";if(n.hetzner?.apiToken)return"hetzner";return"aws"}class Rd{template;constructor(n){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:n,Resources:{}}}addResource(n,i){return this.template.Resources[n]=i,this}addResources(n){return Object.assign(this.template.Resources,n),this}addParameter(n,i){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[n]=i,this}addOutput(n,i){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[n]=i,this}addMetadata(n,i){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[n]=i,this}hasResource(n){return n in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(n=!0){return JSON.stringify(this.template,null,n?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(n,i=0){let s=" ".repeat(i),o="";for(let[c,l]of Object.entries(n)){if(l===null||l===void 0)continue;if(typeof l==="object"&&!Array.isArray(l))o+=`${s}${c}:
13
+ `}function Ca(n){return Object.keys(n).sort().map((i)=>i.toLowerCase()).join(";")}function Ct(n){let i=[];return n.forEach((s,o)=>{i.push([Ot(o),Ot(s)])}),i.sort((s,o)=>{if(s[0]<o[0])return-1;if(s[0]>o[0])return 1;if(s[1]<o[1])return-1;if(s[1]>o[1])return 1;return 0}),i.map(([s,o])=>`${s}=${o}`).join("&")}function vt(n){return n.split("/").map((i)=>Ot(i)).join("/")}function Ot(n){return encodeURIComponent(n).replace(/[!'()*]/g,(i)=>`%${i.charCodeAt(0).toString(16).toUpperCase()}`)}function Xe(n){if(!_e)throw Error("Synchronous hash not available in browser. Use signRequestAsync() instead.");return _e.createHash("sha256").update(n,"utf8").digest("hex")}function Ve(n,i){if(!_e)throw Error("Synchronous hmac not available in browser. Use signRequestAsync() instead.");return _e.createHmac("sha256",n).update(i,"utf8").digest()}async function mt(n){let i=new TextEncoder().encode(n),s=await crypto.subtle.digest("SHA-256",i);return va(new Uint8Array(s))}async function qe(n,i){let s=new TextEncoder,o=typeof n==="string"?s.encode(n):n,c=s.encode(i),l=await crypto.subtle.importKey("raw",o.buffer,{name:"HMAC",hash:"SHA-256"},!1,["sign"]),u=await crypto.subtle.sign("HMAC",l,c.buffer);return new Uint8Array(u)}function va(n){return Array.from(n).map((i)=>i.toString(16).padStart(2,"0")).join("")}function Ta(n,i,s,o,c,l){let u=`${n}:${i}:${s}:${o}`,h=l.get(u);if(!h){let y=Ve(`AWS4${n}`,i),f=Ve(y,s),S=Ve(f,o);if(h=Ve(S,"aws4_request"),l.size>=Pa){let b=l.keys().next().value;if(b)l.delete(b)}l.set(u,h)}return Ve(h,c).toString("hex")}async function wa(n,i,s,o,c,l){let u=`${n}:${i}:${s}:${o}`,h=l.get(u);if(!h){let f=await qe(`AWS4${n}`,i),S=await qe(f,s),b=await qe(S,o);if(h=await qe(b,"aws4_request"),l.size>=Pa){let v=l.keys().next().value;if(v)l.delete(v)}l.set(u,h)}let y=await qe(h,c);return va(y)}function Ea(n,i){return i.includes(n)}function pt(n,i,s){let o=i*Math.pow(2,n),c=Math.random()*0.3*o;return Math.min(o+c,s)}function gt(n){return new Promise((i)=>setTimeout(i,n))}async function iA(n,i){let{maxRetries:s=3,initialDelayMs:o=100,maxDelayMs:c=5000,retryableStatusCodes:l=[429,500,502,503,504],timeoutMs:u=30000}=i??{},h,y;for(let f=0;f<=s;f++){let S=O(n),b={method:S.method,headers:S.headers};if(S.body)b.body=S.body;let v=new AbortController,w=setTimeout(()=>v.abort(),u);b.signal=v.signal;try{let E=await fetch(S.url,b);if(clearTimeout(w),y=E,E.ok)return E;if(f<s&&Ea(E.status,l)){let R=pt(f,o,c);await gt(R);continue}let P=await E.text();throw Error(`AWS API request failed (${E.status}): ${P}`)}catch(E){if(clearTimeout(w),h=E,E instanceof Error&&E.name==="AbortError")h=Error(`Request timed out after ${u}ms`);if(f<s&&!(E instanceof Error&&E.message.includes("AWS API request failed"))){let P=pt(f,o,c);await gt(P);continue}throw h}}throw h??Error("Request failed after retries")}async function gI(n){return iA(n,{maxRetries:0})}async function mI(n,i){let{maxRetries:s=3,initialDelayMs:o=100,maxDelayMs:c=5000,retryableStatusCodes:l=[429,500,502,503,504],timeoutMs:u=30000}=i??{},h;for(let y=0;y<=s;y++){let f=await dg(n),S={method:f.method,headers:f.headers};if(f.body)S.body=f.body;let b=new AbortController,v=setTimeout(()=>b.abort(),u);S.signal=b.signal;try{let w=await fetch(f.url,S);if(clearTimeout(v),w.ok)return w;if(y<s&&Ea(w.status,l)){let P=pt(y,o,c);await gt(P);continue}let E=await w.text();throw Error(`AWS API request failed (${w.status}): ${E}`)}catch(w){if(clearTimeout(v),h=w,w instanceof Error&&w.name==="AbortError")h=Error(`Request timed out after ${u}ms`);if(y<s&&!(w instanceof Error&&w.message.includes("AWS API request failed"))){let E=pt(y,o,c);await gt(E);continue}throw h}}throw h??Error("Request failed after retries")}async function hI(n){let i=await n.text(),s={},o=/<(\w+)>([^<]+)<\/\1>/g,c;while((c=o.exec(i))!==null){let[,l,u]=c;s[l]=u}return s}async function fI(n){return await n.json()}function yI(){Le.clear()}function II(){return Le.size}function SI(){return _e!==void 0}function CI(){return typeof crypto<"u"&&typeof crypto.subtle<"u"}var _e,Le,Pa=100,Ia,rt=nr(async()=>{try{_e=await import("node:crypto")}catch{}Le=new Map,Ia={appstream2:"appstream",cloudhsmv2:"cloudhsm",email:"ses",marketplace:"aws-marketplace",mobile:"AWSMobileHubService",pinpoint:"mobiletargeting",queue:"sqs","git-codecommit":"codecommit","mturk-requester-sandbox":"mturk-requester","personalize-runtime":"personalize"}}),EI={backgroundJobs:{visibilityTimeout:120,messageRetentionPeriod:604800,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0},fifo:{fifo:!0,contentBasedDeduplication:!0,visibilityTimeout:30,encrypted:!0},highThroughput:{visibilityTimeout:30,receiveMessageWaitTime:20,encrypted:!0},delayed:{delaySeconds:60,visibilityTimeout:60,encrypted:!0},longRunning:{visibilityTimeout:900,messageRetentionPeriod:1209600,deadLetterQueue:!0,maxReceiveCount:2,encrypted:!0},monitored:{visibilityTimeout:60,messageRetentionPeriod:604800,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0,alarms:{enabled:!0,queueDepthThreshold:1000,messageAgeThreshold:3600,dlqAlarm:!0}},lambdaOptimized:{visibilityTimeout:360,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3,encrypted:!0},fanOut:{visibilityTimeout:30,receiveMessageWaitTime:20,encrypted:!0}},bI={serverless:{development:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:!0},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:1000,handlerMemory:128}},production:{enabled:!0,mode:"serverless",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:30,inactivityTimeout:60}},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST",pointInTimeRecovery:!0,connectionTTL:86400}},scaling:{maxConnections:50000,messagesPerSecond:5000,handlerMemory:256,handlerTimeout:30},monitoring:{enabled:!0,connectionThreshold:40000,errorThreshold:100,latencyThreshold:500},keepAlive:!0,keepAliveInterval:30,idleTimeout:600},notifications:{enabled:!0,mode:"serverless",channels:{public:!1,private:!0,presence:!1},storage:{type:"dynamodb",dynamodb:{billingMode:"PAY_PER_REQUEST"}},scaling:{maxConnections:50000,messagesPerSecond:2000,handlerMemory:128},keepAlive:!0,keepAliveInterval:60,idleTimeout:1800}},server:{development:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"ws",driver:"bun",idleTimeout:120,perMessageDeflate:!1,metrics:!1}},production:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,maxPayloadLength:16777216,backpressureLimit:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"broadcasting:"},rateLimit:{enabled:!0,max:100,window:60000,perChannel:!0,perUser:!0},loadManagement:{enabled:!0,maxConnections:1e4,maxSubscriptionsPerConnection:100,shedLoadThreshold:0.8},metrics:!0,autoScaling:{min:2,max:10,targetCPU:70}},monitoring:{enabled:!0,connectionThreshold:8000,errorThreshold:100}},highPerformance:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:60,maxPayloadLength:8388608,backpressureLimit:2097152,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!0,instances:4,redis:{enabled:!0,useElastiCache:!0,keyPrefix:"rt:"},rateLimit:{enabled:!0,max:200,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:25000,maxSubscriptionsPerConnection:50,shedLoadThreshold:0.7},metrics:{enabled:!0,path:"/metrics"},autoScaling:{min:4,max:20,targetCPU:60,targetConnections:20000}},monitoring:{enabled:!0,connectionThreshold:80000,errorThreshold:50,latencyThreshold:50}},chat:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:200,heartbeatInterval:20,inactivityTimeout:60}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:300,maxPayloadLength:1048576,sendPings:!0,perMessageDeflate:!0,instances:2,redis:{enabled:!0,keyPrefix:"chat:"},rateLimit:{enabled:!0,max:60,window:60000,perChannel:!0},loadManagement:{enabled:!0,maxConnections:15000,maxSubscriptionsPerConnection:20},metrics:!0},keepAlive:!0,keepAliveInterval:25,idleTimeout:900},gaming:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:{enabled:!0,maxMembers:100,heartbeatInterval:10,inactivityTimeout:30}},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:30,maxPayloadLength:65536,backpressureLimit:524288,closeOnBackpressureLimit:!0,sendPings:!0,perMessageDeflate:!1,instances:4,redis:{enabled:!0,useElastiCache:!0},rateLimit:{enabled:!0,max:120,window:60000},loadManagement:{enabled:!0,maxConnections:5000,maxSubscriptionsPerConnection:10,shedLoadThreshold:0.6},metrics:!0,autoScaling:{min:4,max:16,targetCPU:50}},keepAlive:!0,keepAliveInterval:10,idleTimeout:60},single:{enabled:!0,mode:"server",channels:{public:!0,private:!0,presence:!0},server:{host:"0.0.0.0",port:6001,scheme:"wss",driver:"bun",idleTimeout:120,sendPings:!0,perMessageDeflate:!0,instances:1,rateLimit:{enabled:!0,max:100,window:60000},loadManagement:{enabled:!0,maxConnections:1e4},metrics:!0}}}},lg=".ts-cloud",ug="TS_CLOUD_STATE_DIR",Ft=null;function Cd(n){Ft=n?.trim()||null}function Ed(){return Boolean(process.env[ug]?.trim()||Ft)}function lo(){return process.env[ug]?.trim()||Ft||lg}function L(...n){return ht(lo(),...n)}function d(n,...i){let s=lo();return xt(s)?ht(s,...i):ht(n,s,...i)}function bd(n,i=process.cwd()){let s=(c,l)=>{let u=cr(c,l);return u===""||!u.startsWith("..")&&!xt(u)},o=xt(n)?n:ht(i,n);return s(d(i),o)}function pg(n){let i=n.infrastructure?.compute!=null,s=Object.values(n.environments??{}).some((o)=>o?.app!=null);return{server:i,serverless:s}}function M(n){if(n.mode==="server"||n.mode==="serverless")return n.mode;let{serverless:i}=pg(n);return i?"serverless":"server"}function vd(n){let{server:i,serverless:s}=pg(n);if(i&&s)return"A project cannot be both a server and a serverless deployment. Found `infrastructure.compute` (server) AND `environments.<env>.app` (serverless Lambda). Keep one: remove `infrastructure.compute` for a serverless app, or remove `environments.<env>.app` for a server.";if(n.mode==="server"&&s&&!i)return"Config sets `mode: 'server'` but declares a serverless app (`environments.<env>.app`). Remove the app or change the mode.";if(n.mode==="serverless"&&i&&!s)return"Config sets `mode: 'serverless'` but declares a server (`infrastructure.compute`). Remove the compute block or change the mode.";return null}function p(n){return n.infrastructure?.appDatabase??n.infrastructure?.compute?.database}function lr(n){return typeof n==="object"&&n!==null?n:{}}function sA(n){return n===!0||typeof n==="object"&&n!==null}function ur(n,i){let s=i?n.environments?.[i]:void 0;if(s?.domain)return s.domain;let o=Object.values(n.sites??{}),c=n.sites?.main?.domain??o.find((l)=>l.domain)?.domain;if(c)return c;return`${n.project?.slug??"app"}.local`}function dr(n){let i=n.indexOf(".");return i>0?n.slice(i+1):void 0}function Di(n,i={}){let s=n.infrastructure?.compute?.managedServices?.mail,o=lr(s),c=i.environmentType??(i.environment?n.environments?.[i.environment]?.type:void 0),l=o.mode??(c==="production"?"server":"catcher"),u=l==="server",h=ur(n,i.environment),y=o.hostname??(u?`mail.${h}`:"localhost"),f=o.ports??{},S=u?{smtp:f.smtp??25,submission:f.submission??587,submissions:f.submissions??465,imap:f.imap??143,imaps:f.imaps??993,webmail:f.webmail??8080,managesieve:f.managesieve}:{smtp:f.smtp??1025,submission:f.submission,submissions:f.submissions,imap:f.imap,imaps:f.imaps,webmail:f.webmail??8025,managesieve:f.managesieve},b=o.tls??{},v=b.enabled??u,w=!!(b.certPath&&b.keyPath),E=(o.accounts??[]).map((K)=>({address:K.address,password:K.password})),P=typeof o.dkim==="object"&&o.dkim!==null?o.dkim:{},R=o.dkim===!1?!1:o.dkim===!0||u,D=typeof o.webmail==="object"&&o.webmail!==null?o.webmail:{},x=o.webmail===!1?!1:D.enabled??!0,I=o.spam??{},_=o.delivery??(u?"direct":"none"),B=o.expose??u,W=dr(y),J=[...new Set([y,...W?[W]:[],...o.domains??[]])];return{enabled:sA(s),mode:l,version:o.version,hostname:y,domains:J,ports:S,tls:{enabled:v,acme:v&&!w&&(b.acme??!0),certPath:b.certPath,keyPath:b.keyPath,requireForAuth:b.requireForAuth??(v&&u),acmeEmail:b.acmeEmail??E[0]?.address},dkim:{enabled:R,selector:P.selector??"default",rotate:P.rotate??!1,rotateIntervalDays:P.rotateIntervalDays??90},webmail:{enabled:x,port:D.port??S.webmail,domain:D.domain},delivery:_,sesRegion:o.sesRegion??"us-east-1",accounts:E,storagePath:o.storagePath??"/var/lib/mail",maxMessageSize:o.maxMessageSize??26214400,spam:{enabled:I.enabled??u,enforce:I.enforce??!1,junkScore:I.junkScore??5,rejectScore:I.rejectScore??12,dnsbl:I.dnsbl??u,greylist:I.greylist??!1},webhookUrl:o.webhookUrl,expose:B,bindAddress:B?"0.0.0.0":"127.0.0.1"}}function Td(n){if(!n.enabled||!n.expose)return[];let i=[n.ports.smtp,n.ports.submission,n.ports.submissions,n.ports.imap,n.ports.imaps,n.ports.managesieve].filter((s)=>typeof s==="number");if(n.webmail.enabled&&!n.webmail.domain)i.push(n.webmail.port);return[...new Set(i)].sort((s,o)=>s-o)}function wd(n){if(!n.enabled)return{};let i=n.ports.submission??n.ports.smtp,s={MAIL_MAILER:"smtp",MAIL_HOST:"127.0.0.1",MAIL_PORT:String(i)};if(n.mode==="server"){s.MAIL_ENCRYPTION=n.tls.enabled?"tls":"null";let o=n.accounts[0];if(o)s.MAIL_USERNAME=o.address,s.MAIL_PASSWORD=o.password}else s.MAIL_ENCRYPTION="null",s.MAIL_USERNAME="null",s.MAIL_PASSWORD="null";return s}function ge(n){if(n.cloud?.provider)return n.cloud.provider;if(n.ssh?.hosts?.length)return"ssh";if(n.hetzner?.apiToken)return"hetzner";return"aws"}class Rd{template;constructor(n){this.template={AWSTemplateFormatVersion:"2010-09-09",Description:n,Resources:{}}}addResource(n,i){return this.template.Resources[n]=i,this}addResources(n){return Object.assign(this.template.Resources,n),this}addParameter(n,i){if(!this.template.Parameters)this.template.Parameters={};return this.template.Parameters[n]=i,this}addOutput(n,i){if(!this.template.Outputs)this.template.Outputs={};return this.template.Outputs[n]=i,this}addMetadata(n,i){if(!this.template.Metadata)this.template.Metadata={};return this.template.Metadata[n]=i,this}hasResource(n){return n in this.template.Resources}getResources(){return this.template.Resources}build(){return this.template}toJSON(n=!0){return JSON.stringify(this.template,null,n?2:0)}toYAML(){return this.convertToYAML(this.template)}convertToYAML(n,i=0){let s=" ".repeat(i),o="";for(let[c,l]of Object.entries(n)){if(l===null||l===void 0)continue;if(typeof l==="object"&&!Array.isArray(l))o+=`${s}${c}:
14
14
  ${this.convertToYAML(l,i+1)}`;else if(Array.isArray(l)){o+=`${s}${c}:
15
15
  `;for(let u of l)if(typeof u==="object")o+=`${s} -
16
16
  ${this.convertToYAML(u,i+2)}`;else o+=`${s} - ${u}
17
17
  `}else o+=`${s}${c}: ${l}
18
- `}return o}}var k={Ref:(n)=>({Ref:n}),GetAtt:(n,i)=>({"Fn::GetAtt":[n,i]}),Sub:(n,i)=>{if(i)return{"Fn::Sub":[n,i]};return{"Fn::Sub":n}},Join:(n,i)=>({"Fn::Join":[n,i]}),Select:(n,i)=>({"Fn::Select":[n,i]}),Split:(n,i)=>({"Fn::Split":[n,i]}),GetAZs:(n="")=>({"Fn::GetAZs":n}),ImportValue:(n)=>({"Fn::ImportValue":n}),If:(n,i,s)=>({"Fn::If":[n,i,s]}),Equals:(n,i)=>({"Fn::Equals":[n,i]}),And:(...n)=>({"Fn::And":n}),Or:(...n)=>({"Fn::Or":n}),Not:(n)=>({"Fn::Not":[n]}),Base64:(n)=>({"Fn::Base64":n})},vI={AccountId:{Ref:"AWS::AccountId"},Region:{Ref:"AWS::Region"},StackId:{Ref:"AWS::StackId"},StackName:{Ref:"AWS::StackName"},NotificationARNs:{Ref:"AWS::NotificationARNs"},Partition:{Ref:"AWS::Partition"},URLSuffix:{Ref:"AWS::URLSuffix"},NoValue:{Ref:"AWS::NoValue"}};function r(n){let{slug:i,environment:s,resourceType:o,timestamp:c,suffix:l}=n,u=[i,s,o];if(c)u.push(c);if(l)u.push(l);return u.join("-")}function t(n){return n.split("-").map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")}function TI(){return Date.now().toString()}function wI(n){return n.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function g(n,i){return n.project.stackName??`${n.project.slug}-${i}`}function RI(n,i,s,o){return s.stackName??`${n.project.slug}-${o}-${i}-site`}function DI(n,i){return`${n.project.slug}-${i}`}function PI(n,i,s,o){if(o)return o;if(s==="main")return`${n}-${i}-site`;return`${n}-${i}-${s}`}function NI(n,i,s,o){return o??`${n}-${i}-${s}`}function kI(n,i){return`${n}-${i}-deploy`}function Gt(n,i){return`${n.project.slug}-${i}-app`}function Dd(n,i){return`${n}-${i}-deployments`}function uo(n,i){return`${n}-${i}-assets`}class oA{nodes=new Map;addResource(n,i){let s=this.extractDependencies(i);this.nodes.set(n,{logicalId:n,resource:i,dependencies:s})}extractDependencies(n){let i=new Set;if(n.DependsOn)if(Array.isArray(n.DependsOn))n.DependsOn.forEach((s)=>i.add(s));else i.add(n.DependsOn);return this.findReferences(n.Properties||{},i),i}findReferences(n,i){if(!n||typeof n!=="object")return;if("Ref"in n&&typeof n.Ref==="string"){if(!n.Ref.startsWith("AWS::"))i.add(n.Ref)}if("Fn::GetAtt"in n&&Array.isArray(n["Fn::GetAtt"]))i.add(n["Fn::GetAtt"][0]);for(let s of Object.values(n))if(typeof s==="object")this.findReferences(s,i)}topologicalSort(){let n=[],i=new Set,s=new Set,o=(c)=>{if(i.has(c))return;if(s.has(c))throw Error(`Circular dependency detected: ${c}`);s.add(c);let l=this.nodes.get(c);if(l)for(let u of l.dependencies)o(u);s.delete(c),i.add(c),n.push(c)};for(let c of this.nodes.keys())o(c);return n}validate(){for(let[n,i]of this.nodes.entries())for(let s of i.dependencies)if(!this.nodes.has(s))throw Error(`Resource "${n}" depends on "${s}" which does not exist`)}getDependents(n){let i=[];for(let[s,o]of this.nodes.entries())if(o.dependencies.has(n))i.push(s);return i}}function BI(n,i){let s=[],o=[],c=[],l=[],u=[],h=n.Resources||{},y=i.Resources||{},f=new Set([...Object.keys(h),...Object.keys(y)]);for(let C of f){let T=h[C],w=y[C];if(!T&&w)s.push({logicalId:C,action:"add",resourceType:w.Type});else if(T&&!w)o.push({logicalId:C,action:"remove",resourceType:T.Type});else if(T&&w)if(T.Type!==w.Type)l.push({logicalId:C,action:"replace",resourceType:w.Type,reason:`Type changed from ${T.Type} to ${w.Type}`});else{let E=Ra(T.Properties||{},w.Properties||{});if(E.length>0)if(mr(T.Type,E))l.push({logicalId:C,action:"replace",resourceType:w.Type,changes:E,reason:"Property changes require replacement"});else c.push({logicalId:C,action:"update",resourceType:w.Type,changes:E});else u.push(C)}}let b=pr([...o,...l,...c]);return{added:s,removed:o,updated:c,replaced:l,unchanged:u,summary:{totalChanges:s.length+o.length+c.length+l.length,requiresReplacement:l.length>0,dangerousChanges:b}}}function Ra(n,i,s=""){let o=[],c=new Set([...Object.keys(n),...Object.keys(i)]);for(let l of c){let u=s?`${s}.${l}`:l,h=n[l],y=i[l];if(h===void 0&&y!==void 0)o.push({path:u,oldValue:void 0,newValue:y});else if(h!==void 0&&y===void 0)o.push({path:u,oldValue:h,newValue:void 0});else if(typeof h!==typeof y)o.push({path:u,oldValue:h,newValue:y});else if(typeof h==="object"&&h!==null)if(Array.isArray(h)&&Array.isArray(y)){if(JSON.stringify(h)!==JSON.stringify(y))o.push({path:u,oldValue:h,newValue:y})}else if(!Array.isArray(h)&&!Array.isArray(y)){let f=Ra(h,y,u);o.push(...f)}else o.push({path:u,oldValue:h,newValue:y});else if(h!==y)o.push({path:u,oldValue:h,newValue:y})}return o}function mr(n,i){let s={"AWS::S3::Bucket":new Set(["BucketName"]),"AWS::DynamoDB::Table":new Set(["TableName","KeySchema"]),"AWS::RDS::DBInstance":new Set(["DBInstanceIdentifier","DBName","Engine"]),"AWS::Lambda::Function":new Set(["FunctionName"]),"AWS::EC2::Instance":new Set(["ImageId","InstanceType","KeyName"]),"AWS::ECS::TaskDefinition":new Set(["Family","ContainerDefinitions"]),"AWS::ElastiCache::CacheCluster":new Set(["CacheNodeType","Engine"]),"AWS::CloudFront::Distribution":new Set([]),"AWS::Route53::HostedZone":new Set(["Name"]),"AWS::IAM::Role":new Set(["RoleName","Path"]),"AWS::KMS::Key":new Set(["KeyPolicy"]),"AWS::Cognito::UserPool":new Set(["UserPoolName"]),"AWS::OpenSearchService::Domain":new Set(["DomainName"])}[n];if(!s)return!1;for(let o of i){let c=o.path.split(".")[0];if(s.has(c))return!0}return!1}function pr(n){let i=[];for(let s of n){if(s.action==="remove"&&(s.resourceType==="AWS::RDS::DBInstance"||s.resourceType==="AWS::DynamoDB::Table"||s.resourceType==="AWS::ElastiCache::CacheCluster"))i.push(`Removing ${s.resourceType} ${s.logicalId} - data loss risk!`);if(s.action==="replace"&&(s.resourceType==="AWS::RDS::DBInstance"||s.resourceType==="AWS::DynamoDB::Table"))i.push(`Replacing ${s.resourceType} ${s.logicalId} - data loss risk!`);if((s.action==="remove"||s.action==="replace")&&s.resourceType==="AWS::S3::Bucket")i.push(`${s.action==="remove"?"Removing":"Replacing"} S3 bucket ${s.logicalId} - data loss risk!`);if(s.action==="replace"&&s.resourceType==="AWS::EC2::Instance")i.push(`Replacing EC2 instance ${s.logicalId} - downtime expected`);if(s.action==="update"&&s.resourceType==="AWS::EC2::SecurityGroup")i.push(`Updating security group ${s.logicalId} - may affect connectivity`);if((s.action==="update"||s.action==="replace")&&(s.resourceType==="AWS::IAM::Role"||s.resourceType==="AWS::IAM::Policy"))i.push(`Modifying IAM ${s.resourceType.split("::")[2]} ${s.logicalId} - may affect permissions`)}return i}function _I(n){let i=[];if(i.push(`=== Stack Update Analysis ===
18
+ `}return o}}var k={Ref:(n)=>({Ref:n}),GetAtt:(n,i)=>({"Fn::GetAtt":[n,i]}),Sub:(n,i)=>{if(i)return{"Fn::Sub":[n,i]};return{"Fn::Sub":n}},Join:(n,i)=>({"Fn::Join":[n,i]}),Select:(n,i)=>({"Fn::Select":[n,i]}),Split:(n,i)=>({"Fn::Split":[n,i]}),GetAZs:(n="")=>({"Fn::GetAZs":n}),ImportValue:(n)=>({"Fn::ImportValue":n}),If:(n,i,s)=>({"Fn::If":[n,i,s]}),Equals:(n,i)=>({"Fn::Equals":[n,i]}),And:(...n)=>({"Fn::And":n}),Or:(...n)=>({"Fn::Or":n}),Not:(n)=>({"Fn::Not":[n]}),Base64:(n)=>({"Fn::Base64":n})},vI={AccountId:{Ref:"AWS::AccountId"},Region:{Ref:"AWS::Region"},StackId:{Ref:"AWS::StackId"},StackName:{Ref:"AWS::StackName"},NotificationARNs:{Ref:"AWS::NotificationARNs"},Partition:{Ref:"AWS::Partition"},URLSuffix:{Ref:"AWS::URLSuffix"},NoValue:{Ref:"AWS::NoValue"}};function r(n){let{slug:i,environment:s,resourceType:o,timestamp:c,suffix:l}=n,u=[i,s,o];if(c)u.push(c);if(l)u.push(l);return u.join("-")}function t(n){return n.split("-").map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")}function TI(){return Date.now().toString()}function wI(n){return n.toLowerCase().replace(/[^a-z0-9-]/g,"-").replace(/^-+|-+$/g,"").replace(/-+/g,"-")}function g(n,i){return n.project.stackName??`${n.project.slug}-${i}`}function RI(n,i,s,o){return s.stackName??`${n.project.slug}-${o}-${i}-site`}function DI(n,i){return`${n.project.slug}-${i}`}function PI(n,i,s,o){if(o)return o;if(s==="main")return`${n}-${i}-site`;return`${n}-${i}-${s}`}function NI(n,i,s,o){return o??`${n}-${i}-${s}`}function kI(n,i){return`${n}-${i}-deploy`}function Gt(n,i){return`${n.project.slug}-${i}-app`}function Dd(n,i){return`${n}-${i}-deployments`}function uo(n,i){return`${n}-${i}-assets`}class oA{nodes=new Map;addResource(n,i){let s=this.extractDependencies(i);this.nodes.set(n,{logicalId:n,resource:i,dependencies:s})}extractDependencies(n){let i=new Set;if(n.DependsOn)if(Array.isArray(n.DependsOn))n.DependsOn.forEach((s)=>i.add(s));else i.add(n.DependsOn);return this.findReferences(n.Properties||{},i),i}findReferences(n,i){if(!n||typeof n!=="object")return;if("Ref"in n&&typeof n.Ref==="string"){if(!n.Ref.startsWith("AWS::"))i.add(n.Ref)}if("Fn::GetAtt"in n&&Array.isArray(n["Fn::GetAtt"]))i.add(n["Fn::GetAtt"][0]);for(let s of Object.values(n))if(typeof s==="object")this.findReferences(s,i)}topologicalSort(){let n=[],i=new Set,s=new Set,o=(c)=>{if(i.has(c))return;if(s.has(c))throw Error(`Circular dependency detected: ${c}`);s.add(c);let l=this.nodes.get(c);if(l)for(let u of l.dependencies)o(u);s.delete(c),i.add(c),n.push(c)};for(let c of this.nodes.keys())o(c);return n}validate(){for(let[n,i]of this.nodes.entries())for(let s of i.dependencies)if(!this.nodes.has(s))throw Error(`Resource "${n}" depends on "${s}" which does not exist`)}getDependents(n){let i=[];for(let[s,o]of this.nodes.entries())if(o.dependencies.has(n))i.push(s);return i}}function BI(n,i){let s=[],o=[],c=[],l=[],u=[],h=n.Resources||{},y=i.Resources||{},f=new Set([...Object.keys(h),...Object.keys(y)]);for(let b of f){let v=h[b],w=y[b];if(!v&&w)s.push({logicalId:b,action:"add",resourceType:w.Type});else if(v&&!w)o.push({logicalId:b,action:"remove",resourceType:v.Type});else if(v&&w)if(v.Type!==w.Type)l.push({logicalId:b,action:"replace",resourceType:w.Type,reason:`Type changed from ${v.Type} to ${w.Type}`});else{let E=Ra(v.Properties||{},w.Properties||{});if(E.length>0)if(mr(v.Type,E))l.push({logicalId:b,action:"replace",resourceType:w.Type,changes:E,reason:"Property changes require replacement"});else c.push({logicalId:b,action:"update",resourceType:w.Type,changes:E});else u.push(b)}}let S=pr([...o,...l,...c]);return{added:s,removed:o,updated:c,replaced:l,unchanged:u,summary:{totalChanges:s.length+o.length+c.length+l.length,requiresReplacement:l.length>0,dangerousChanges:S}}}function Ra(n,i,s=""){let o=[],c=new Set([...Object.keys(n),...Object.keys(i)]);for(let l of c){let u=s?`${s}.${l}`:l,h=n[l],y=i[l];if(h===void 0&&y!==void 0)o.push({path:u,oldValue:void 0,newValue:y});else if(h!==void 0&&y===void 0)o.push({path:u,oldValue:h,newValue:void 0});else if(typeof h!==typeof y)o.push({path:u,oldValue:h,newValue:y});else if(typeof h==="object"&&h!==null)if(Array.isArray(h)&&Array.isArray(y)){if(JSON.stringify(h)!==JSON.stringify(y))o.push({path:u,oldValue:h,newValue:y})}else if(!Array.isArray(h)&&!Array.isArray(y)){let f=Ra(h,y,u);o.push(...f)}else o.push({path:u,oldValue:h,newValue:y});else if(h!==y)o.push({path:u,oldValue:h,newValue:y})}return o}function mr(n,i){let s={"AWS::S3::Bucket":new Set(["BucketName"]),"AWS::DynamoDB::Table":new Set(["TableName","KeySchema"]),"AWS::RDS::DBInstance":new Set(["DBInstanceIdentifier","DBName","Engine"]),"AWS::Lambda::Function":new Set(["FunctionName"]),"AWS::EC2::Instance":new Set(["ImageId","InstanceType","KeyName"]),"AWS::ECS::TaskDefinition":new Set(["Family","ContainerDefinitions"]),"AWS::ElastiCache::CacheCluster":new Set(["CacheNodeType","Engine"]),"AWS::CloudFront::Distribution":new Set([]),"AWS::Route53::HostedZone":new Set(["Name"]),"AWS::IAM::Role":new Set(["RoleName","Path"]),"AWS::KMS::Key":new Set(["KeyPolicy"]),"AWS::Cognito::UserPool":new Set(["UserPoolName"]),"AWS::OpenSearchService::Domain":new Set(["DomainName"])}[n];if(!s)return!1;for(let o of i){let c=o.path.split(".")[0];if(s.has(c))return!0}return!1}function pr(n){let i=[];for(let s of n){if(s.action==="remove"&&(s.resourceType==="AWS::RDS::DBInstance"||s.resourceType==="AWS::DynamoDB::Table"||s.resourceType==="AWS::ElastiCache::CacheCluster"))i.push(`Removing ${s.resourceType} ${s.logicalId} - data loss risk!`);if(s.action==="replace"&&(s.resourceType==="AWS::RDS::DBInstance"||s.resourceType==="AWS::DynamoDB::Table"))i.push(`Replacing ${s.resourceType} ${s.logicalId} - data loss risk!`);if((s.action==="remove"||s.action==="replace")&&s.resourceType==="AWS::S3::Bucket")i.push(`${s.action==="remove"?"Removing":"Replacing"} S3 bucket ${s.logicalId} - data loss risk!`);if(s.action==="replace"&&s.resourceType==="AWS::EC2::Instance")i.push(`Replacing EC2 instance ${s.logicalId} - downtime expected`);if(s.action==="update"&&s.resourceType==="AWS::EC2::SecurityGroup")i.push(`Updating security group ${s.logicalId} - may affect connectivity`);if((s.action==="update"||s.action==="replace")&&(s.resourceType==="AWS::IAM::Role"||s.resourceType==="AWS::IAM::Policy"))i.push(`Modifying IAM ${s.resourceType.split("::")[2]} ${s.logicalId} - may affect permissions`)}return i}function _I(n){let i=[];if(i.push(`=== Stack Update Analysis ===
19
19
  `),n.summary.totalChanges===0)return i.push(`No changes detected.
20
20
  `),i.join(`
21
21
  `);if(i.push(`Total changes: ${n.summary.totalChanges}`),i.push(`Requires replacement: ${n.summary.requiresReplacement?"Yes":"No"}
22
22
  `),n.summary.dangerousChanges.length>0){i.push("⚠️ DANGEROUS CHANGES DETECTED:");for(let s of n.summary.dangerousChanges)i.push(` • ${s}`);i.push("")}if(n.added.length>0){i.push(`✅ Resources to Add (${n.added.length}):`);for(let s of n.added)i.push(` + ${s.logicalId} (${s.resourceType})`);i.push("")}if(n.removed.length>0){i.push(`❌ Resources to Remove (${n.removed.length}):`);for(let s of n.removed)i.push(` - ${s.logicalId} (${s.resourceType})`);i.push("")}if(n.replaced.length>0){i.push(`\uD83D\uDD04 Resources to Replace (${n.replaced.length}):`);for(let s of n.replaced){if(i.push(` ~ ${s.logicalId} (${s.resourceType})`),s.reason)i.push(` Reason: ${s.reason}`);if(s.changes){for(let o of s.changes.slice(0,3))i.push(` • ${o.path}: ${JSON.stringify(o.oldValue)} → ${JSON.stringify(o.newValue)}`);if(s.changes.length>3)i.push(` ... and ${s.changes.length-3} more changes`)}}i.push("")}if(n.updated.length>0){i.push(`\uD83D\uDCDD Resources to Update (${n.updated.length}):`);for(let s of n.updated)if(i.push(` ~ ${s.logicalId} (${s.resourceType})`),s.changes){for(let o of s.changes.slice(0,3))i.push(` • ${o.path}: ${JSON.stringify(o.oldValue)} → ${JSON.stringify(o.newValue)}`);if(s.changes.length>3)i.push(` ... and ${s.changes.length-3} more changes`)}i.push("")}if(n.unchanged.length>0)i.push(`⚪ Unchanged Resources (${n.unchanged.length})`);return i.join(`
23
- `)}class Re{static createBucket(n){let{name:i,bucketName:s,slug:o,environment:c,public:l=!1,versioning:u=!1,website:h=!1,encryption:y=!0,intelligentTiering:f=!1,cors:b,lifecycleRules:C}=n,T=s??r({slug:o,environment:c,resourceType:"s3",suffix:i}),w=t(T),E={Type:"AWS::S3::Bucket",Properties:{BucketName:T}};if(y)E.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(u)E.Properties.VersioningConfiguration={Status:"Enabled"};if(h)E.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!l)E.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(b&&b.length>0)E.Properties.CorsConfiguration={CorsRules:b.map((N)=>({AllowedOrigins:N.allowedOrigins,AllowedMethods:N.allowedMethods,AllowedHeaders:N.allowedHeaders,MaxAge:N.maxAge}))};if(C&&C.length>0)E.Properties.LifecycleConfiguration={Rules:C.map((N)=>({Id:N.id,Status:N.enabled?"Enabled":"Disabled",ExpirationInDays:N.expirationDays,Transitions:N.transitions?.map((D)=>({TransitionInDays:D.days,StorageClass:D.storageClass}))}))};if(f&&C){let N={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!E.Properties.LifecycleConfiguration)E.Properties.LifecycleConfiguration={Rules:[]};E.Properties.LifecycleConfiguration.Rules.push({Id:N.id,Status:"Enabled",Transitions:N.transitions?.map((D)=>({TransitionInDays:D.days,StorageClass:D.storageClass}))})}let I;if(l)I={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:k.Ref(w),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[k.Join("",[k.GetAtt(w,"Arn"),"/*"])]}]}}};return{bucket:E,bucketPolicy:I,logicalId:w}}static enableVersioning(n){if(!n.Properties)n.Properties={};return n.Properties.VersioningConfiguration={Status:"Enabled"},n}static enableWebsiteHosting(n,i="index.html",s="error.html"){if(!n.Properties)n.Properties={};return n.Properties.WebsiteConfiguration={IndexDocument:i,ErrorDocument:s},n}static setLifecycleRules(n,i){if(!n.Properties)n.Properties={};return n.Properties.LifecycleConfiguration={Rules:i.map((s)=>({Id:s.id,Status:s.enabled?"Enabled":"Disabled",ExpirationInDays:s.expirationDays,Transitions:s.transitions?.map((o)=>({TransitionInDays:o.days,StorageClass:o.storageClass}))}))},n}static enableIntelligentTiering(n){if(!n.Properties)n.Properties={};if(!n.Properties.LifecycleConfiguration)n.Properties.LifecycleConfiguration={Rules:[]};return n.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),n}static addLambdaNotification(n,i){if(!n.Properties)n.Properties={};if(!n.Properties.NotificationConfiguration)n.Properties.NotificationConfiguration={};if(!n.Properties.NotificationConfiguration.LambdaConfigurations)n.Properties.NotificationConfiguration.LambdaConfigurations=[];let s={Event:i.events[0],Function:i.functionArn};if(i.filter)s.Filter={S3Key:{Rules:[...i.filter.prefix?[{Name:"prefix",Value:i.filter.prefix}]:[],...i.filter.suffix?[{Name:"suffix",Value:i.filter.suffix}]:[]]}};for(let o of i.events){let c={...s,Event:o};n.Properties.NotificationConfiguration.LambdaConfigurations.push(c)}return n}static Notifications={onObjectCreated:(n)=>({functionArn:n,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(n)=>({functionArn:n,events:["s3:ObjectRemoved:*"]}),onImageUpload:(n,i)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:i,suffix:".jpg"}}),onFileType:(n,i,s)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:s,suffix:i}}),onFolderUpload:(n,i)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:i.endsWith("/")?i:`${i}/`}})};static createBackupPlan(n){let{name:i,slug:s,environment:o,bucketLogicalIds:c,retentionDays:l,schedule:u="cron(0 5 * * ? *)",vaultName:h,enableContinuousBackup:y=!1,moveToColdStorageAfterDays:f}=n,b=h||r({slug:s,environment:o,resourceType:"backup-vault",suffix:i}),C=t(b),T={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:b}},w=r({slug:s,environment:o,resourceType:"backup-role",suffix:i}),E=t(w),I={Type:"AWS::IAM::Role",Properties:{RoleName:w,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"backup.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup","arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"]}},N=r({slug:s,environment:o,resourceType:"backup-plan",suffix:i}),D=t(N),x={DeleteAfterDays:l};if(f&&f<l)x.MoveToColdStorageAfterDays=f;let R={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:N,BackupPlanRule:[{RuleName:`${i}-daily-backup`,TargetBackupVault:k.Ref(C),ScheduleExpression:u,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:x,EnableContinuousBackup:y}]}}},_=r({slug:s,environment:o,resourceType:"backup-selection",suffix:i}),B=t(_),W=c.map((K)=>k.GetAtt(K,"Arn")),J={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:k.Ref(D),BackupSelection:{SelectionName:_,IamRoleArn:k.GetAtt(E,"Arn"),Resources:W}}};return{vault:T,plan:R,selection:J,role:I,vaultLogicalId:C,planLogicalId:D,selectionLogicalId:B,roleLogicalId:E}}static BackupSchedules={HOURLY:"cron(0 * * * ? *)",DAILY_5AM:"cron(0 5 * * ? *)",DAILY_MIDNIGHT:"cron(0 0 * * ? *)",WEEKLY_SUNDAY:"cron(0 5 ? * SUN *)",WEEKLY_SATURDAY:"cron(0 5 ? * SAT *)",MONTHLY_FIRST:"cron(0 5 1 * ? *)",EVERY_12_HOURS:"cron(0 */12 * * ? *)",EVERY_6_HOURS:"cron(0 */6 * * ? *)"};static BackupRetention={ONE_DAY:1,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,THREE_MONTHS:90,SIX_MONTHS:180,ONE_YEAR:365,TWO_YEARS:730,FIVE_YEARS:1825,SEVEN_YEARS:2555};static createWwwRedirectBucket(n){let{slug:i,environment:s,sourceDomain:o,targetDomain:c,protocol:l="https"}=n,u=r({slug:i,environment:s,resourceType:"s3",suffix:"www-redirect"}),h=t(u),y={Type:"AWS::S3::Bucket",Properties:{BucketName:o,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:c,Protocol:l}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},f={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:k.Ref(h),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[k.Join("",[k.GetAtt(h,"Arn"),"/*"])]}]}}};return{bucket:y,bucketPolicy:f,logicalId:h}}static createDocsBucket(n){let{slug:i,environment:s,domain:o}=n,c=o||r({slug:i,environment:s,resourceType:"s3",suffix:"docs"}),l=t(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:l}}static createEmailBucket(n){let{slug:i,environment:s}=n,o=r({slug:i,environment:s,resourceType:"s3",suffix:"email"}),c=t(o),l={Type:"AWS::S3::Bucket",Properties:{BucketName:o,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},u={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:k.Ref(c),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:k.Join("",[k.GetAtt(c,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":k.Ref("AWS::AccountId")}}}]}}};return{bucket:l,bucketPolicy:u,logicalId:c}}static docsExist(n={}){let{projectRoot:i=process.cwd(),docsPaths:s=["docs","documentation","doc"]}=n;for(let o of s){let c=ve(i,o);if(He(c)){let l=["dist","build",".bunpress/dist","_site","out","public"];for(let u of l){let h=ve(c,u);if(He(h))try{if(gr(h).length>0)return{exists:!0,path:c,hasDistFolder:!0,distPath:h}}catch{}}return{exists:!0,path:c,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(n){let i=Re.docsExist({projectRoot:n.projectRoot,docsPaths:n.docsPaths});if(!i.exists)return{bucket:null,logicalId:null,docsInfo:i};let s=Re.createDocsBucket({slug:n.slug,environment:n.environment,domain:n.domain});return{bucket:s.bucket,bucketPolicy:s.bucketPolicy,logicalId:s.logicalId,docsInfo:i}}static createPrivateBucket(n){let{slug:i,environment:s,enableVersioning:o=!0,retentionDays:c,encryptionKeyArn:l}=n,u=r({slug:i,environment:s,resourceType:"s3",suffix:"private"}),h=t(u);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:u,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:l?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:l}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:o?{Status:"Enabled"}:void 0,LifecycleConfiguration:c?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:c}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:h}}static checkSourcePaths(n={}){let{projectRoot:i=process.cwd(),paths:s={}}=n,o=s.web||"views/web/dist",c=s.docs||"docs/dist",l=s.private||"private";return{web:{exists:He(ve(i,o)),path:ve(i,o)},docs:{exists:He(ve(i,c)),path:ve(i,c)},private:{exists:He(ve(i,l)),path:ve(i,l)}}}static createDeploymentBuckets(n){let{slug:i,environment:s,domain:o,projectRoot:c,paths:l}=n,u=Re.checkSourcePaths({projectRoot:c,paths:l}),h={},y={web:!1,docs:!1,private:!1},f=Re.createBucket({name:"web",slug:i,environment:s,public:!1,versioning:!1,encryption:!0});if(h[f.logicalId]=f.bucket,y.web=!0,u.docs.exists){let b=Re.createDocsBucket({slug:i,environment:s,domain:o?`docs.${o}`:void 0});if(h[b.logicalId]=b.bucket,b.bucketPolicy)h[`${b.logicalId}Policy`]=b.bucketPolicy;y.docs=!0}if(u.private.exists){let b=Re.createPrivateBucket({slug:i,environment:s,enableVersioning:!0});h[b.logicalId]=b.bucket,y.private=!0}return{resources:h,created:y,sourcePaths:u}}}class je{static createRepository(n){let{name:i,slug:s,environment:o,scanOnPush:c=!0,imageMutability:l="MUTABLE",encryption:u="AES256",kmsKey:h,lifecyclePolicy:y,tags:f}=n,b=r({slug:s,environment:o,resourceType:"ecr",suffix:i}),C=t(b),T={Type:"AWS::ECR::Repository",Properties:{RepositoryName:b,ImageTagMutability:l,ImageScanningConfiguration:{ScanOnPush:c},EncryptionConfiguration:{EncryptionType:u,...h&&u==="KMS"?{KmsKey:h}:{}}}};if(y)T.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(je.generateLifecyclePolicy(y))};if(f)T.Properties.Tags=Object.entries(f).map(([w,E])=>({Key:w,Value:E}));return{repository:T,logicalId:C}}static generateLifecyclePolicy(n){let i=[];if(n.untaggedImageExpireDays!==void 0)i.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:n.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(n.maxImageCount!==void 0)i.push({rulePriority:i.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:n.maxImageCount},action:{type:"expire"}});if(n.maxImageAgeDays!==void 0)i.push({rulePriority:i.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:n.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:i}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(n){if(!n.Properties)n.Properties={};return n.Properties.ImageTagMutability="IMMUTABLE",n}static enableScanOnPush(n){if(!n.Properties)n.Properties={};return n.Properties.ImageScanningConfiguration={ScanOnPush:!0},n}static setLifecyclePolicy(n,i){if(!n.Properties)n.Properties={};return n.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(je.generateLifecyclePolicy(i))},n}static addCrossAccountAccess(n,i){if(!n.Properties)n.Properties={};return n.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:i.map((s)=>`arn:aws:iam::${s}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},n}static addLambdaAccess(n){if(!n.Properties)n.Properties={};return n.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},n}static generateBunDockerfile(n){let{baseImage:i="oven/bun:1-debian",serverPath:s,port:o=3000,additionalDirs:c=[],healthCheckEndpoint:l="/health",nodeCompatible:u=!1,envVars:h={},buildCommands:y=[],runCommand:f}=n,b=["app","config",...c],C=f||`bun run ${s}`,T=`# Multi-stage build for Bun application
23
+ `)}class Re{static createBucket(n){let{name:i,bucketName:s,slug:o,environment:c,public:l=!1,versioning:u=!1,website:h=!1,encryption:y=!0,intelligentTiering:f=!1,cors:S,lifecycleRules:b}=n,v=s??r({slug:o,environment:c,resourceType:"s3",suffix:i}),w=t(v),E={Type:"AWS::S3::Bucket",Properties:{BucketName:v}};if(y)E.Properties.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(u)E.Properties.VersioningConfiguration={Status:"Enabled"};if(h)E.Properties.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"error.html"};if(!l)E.Properties.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(S&&S.length>0)E.Properties.CorsConfiguration={CorsRules:S.map((R)=>({AllowedOrigins:R.allowedOrigins,AllowedMethods:R.allowedMethods,AllowedHeaders:R.allowedHeaders,MaxAge:R.maxAge}))};if(b&&b.length>0)E.Properties.LifecycleConfiguration={Rules:b.map((R)=>({Id:R.id,Status:R.enabled?"Enabled":"Disabled",ExpirationInDays:R.expirationDays,Transitions:R.transitions?.map((D)=>({TransitionInDays:D.days,StorageClass:D.storageClass}))}))};if(f&&b){let R={id:"IntelligentTieringRule",enabled:!0,transitions:[{days:0,storageClass:"INTELLIGENT_TIERING"}]};if(!E.Properties.LifecycleConfiguration)E.Properties.LifecycleConfiguration={Rules:[]};E.Properties.LifecycleConfiguration.Rules.push({Id:R.id,Status:"Enabled",Transitions:R.transitions?.map((D)=>({TransitionInDays:D.days,StorageClass:D.storageClass}))})}let P;if(l)P={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:k.Ref(w),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[k.Join("",[k.GetAtt(w,"Arn"),"/*"])]}]}}};return{bucket:E,bucketPolicy:P,logicalId:w}}static enableVersioning(n){if(!n.Properties)n.Properties={};return n.Properties.VersioningConfiguration={Status:"Enabled"},n}static enableWebsiteHosting(n,i="index.html",s="error.html"){if(!n.Properties)n.Properties={};return n.Properties.WebsiteConfiguration={IndexDocument:i,ErrorDocument:s},n}static setLifecycleRules(n,i){if(!n.Properties)n.Properties={};return n.Properties.LifecycleConfiguration={Rules:i.map((s)=>({Id:s.id,Status:s.enabled?"Enabled":"Disabled",ExpirationInDays:s.expirationDays,Transitions:s.transitions?.map((o)=>({TransitionInDays:o.days,StorageClass:o.storageClass}))}))},n}static enableIntelligentTiering(n){if(!n.Properties)n.Properties={};if(!n.Properties.LifecycleConfiguration)n.Properties.LifecycleConfiguration={Rules:[]};return n.Properties.LifecycleConfiguration.Rules.push({Id:"IntelligentTieringRule",Status:"Enabled",Transitions:[{TransitionInDays:0,StorageClass:"INTELLIGENT_TIERING"}]}),n}static addLambdaNotification(n,i){if(!n.Properties)n.Properties={};if(!n.Properties.NotificationConfiguration)n.Properties.NotificationConfiguration={};if(!n.Properties.NotificationConfiguration.LambdaConfigurations)n.Properties.NotificationConfiguration.LambdaConfigurations=[];let s={Event:i.events[0],Function:i.functionArn};if(i.filter)s.Filter={S3Key:{Rules:[...i.filter.prefix?[{Name:"prefix",Value:i.filter.prefix}]:[],...i.filter.suffix?[{Name:"suffix",Value:i.filter.suffix}]:[]]}};for(let o of i.events){let c={...s,Event:o};n.Properties.NotificationConfiguration.LambdaConfigurations.push(c)}return n}static Notifications={onObjectCreated:(n)=>({functionArn:n,events:["s3:ObjectCreated:*"]}),onObjectRemoved:(n)=>({functionArn:n,events:["s3:ObjectRemoved:*"]}),onImageUpload:(n,i)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:i,suffix:".jpg"}}),onFileType:(n,i,s)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:s,suffix:i}}),onFolderUpload:(n,i)=>({functionArn:n,events:["s3:ObjectCreated:*"],filter:{prefix:i.endsWith("/")?i:`${i}/`}})};static createBackupPlan(n){let{name:i,slug:s,environment:o,bucketLogicalIds:c,retentionDays:l,schedule:u="cron(0 5 * * ? *)",vaultName:h,enableContinuousBackup:y=!1,moveToColdStorageAfterDays:f}=n,S=h||r({slug:s,environment:o,resourceType:"backup-vault",suffix:i}),b=t(S),v={Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:S}},w=r({slug:s,environment:o,resourceType:"backup-role",suffix:i}),E=t(w),P={Type:"AWS::IAM::Role",Properties:{RoleName:w,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"backup.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup","arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores"]}},R=r({slug:s,environment:o,resourceType:"backup-plan",suffix:i}),D=t(R),x={DeleteAfterDays:l};if(f&&f<l)x.MoveToColdStorageAfterDays=f;let I={Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:R,BackupPlanRule:[{RuleName:`${i}-daily-backup`,TargetBackupVault:k.Ref(b),ScheduleExpression:u,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:x,EnableContinuousBackup:y}]}}},_=r({slug:s,environment:o,resourceType:"backup-selection",suffix:i}),B=t(_),W=c.map((K)=>k.GetAtt(K,"Arn")),J={Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:k.Ref(D),BackupSelection:{SelectionName:_,IamRoleArn:k.GetAtt(E,"Arn"),Resources:W}}};return{vault:v,plan:I,selection:J,role:P,vaultLogicalId:b,planLogicalId:D,selectionLogicalId:B,roleLogicalId:E}}static BackupSchedules={HOURLY:"cron(0 * * * ? *)",DAILY_5AM:"cron(0 5 * * ? *)",DAILY_MIDNIGHT:"cron(0 0 * * ? *)",WEEKLY_SUNDAY:"cron(0 5 ? * SUN *)",WEEKLY_SATURDAY:"cron(0 5 ? * SAT *)",MONTHLY_FIRST:"cron(0 5 1 * ? *)",EVERY_12_HOURS:"cron(0 */12 * * ? *)",EVERY_6_HOURS:"cron(0 */6 * * ? *)"};static BackupRetention={ONE_DAY:1,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,THREE_MONTHS:90,SIX_MONTHS:180,ONE_YEAR:365,TWO_YEARS:730,FIVE_YEARS:1825,SEVEN_YEARS:2555};static createWwwRedirectBucket(n){let{slug:i,environment:s,sourceDomain:o,targetDomain:c,protocol:l="https"}=n,u=r({slug:i,environment:s,resourceType:"s3",suffix:"www-redirect"}),h=t(u),y={Type:"AWS::S3::Bucket",Properties:{BucketName:o,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:c,Protocol:l}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1}}},f={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:k.Ref(h),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[k.Join("",[k.GetAtt(h,"Arn"),"/*"])]}]}}};return{bucket:y,bucketPolicy:f,logicalId:h}}static createDocsBucket(n){let{slug:i,environment:s,domain:o}=n,c=o||r({slug:i,environment:s,resourceType:"s3",suffix:"docs"}),l=t(c);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:c,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},Tags:[{Key:"backup",Value:"weekly"}]}},logicalId:l}}static createEmailBucket(n){let{slug:i,environment:s}=n,o=r({slug:i,environment:s,resourceType:"s3",suffix:"email"}),c=t(o),l={Type:"AWS::S3::Bucket",Properties:{BucketName:o,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},LifecycleConfiguration:{Rules:[{Id:"EmailRetention",Status:"Enabled",ExpirationInDays:90,Transitions:[{TransitionInDays:30,StorageClass:"STANDARD_IA"}]}]}}},u={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:k.Ref(c),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"AllowSESPuts",Effect:"Allow",Principal:{Service:"ses.amazonaws.com"},Action:"s3:PutObject",Resource:k.Join("",[k.GetAtt(c,"Arn"),"/*"]),Condition:{StringEquals:{"AWS:SourceAccount":k.Ref("AWS::AccountId")}}}]}}};return{bucket:l,bucketPolicy:u,logicalId:c}}static docsExist(n={}){let{projectRoot:i=process.cwd(),docsPaths:s=["docs","documentation","doc"]}=n;for(let o of s){let c=ve(i,o);if(He(c)){let l=["dist","build",".bunpress/dist","_site","out","public"];for(let u of l){let h=ve(c,u);if(He(h))try{if(gr(h).length>0)return{exists:!0,path:c,hasDistFolder:!0,distPath:h}}catch{}}return{exists:!0,path:c,hasDistFolder:!1,distPath:null}}}return{exists:!1,path:null,hasDistFolder:!1,distPath:null}}static createDocsBucketIfExists(n){let i=Re.docsExist({projectRoot:n.projectRoot,docsPaths:n.docsPaths});if(!i.exists)return{bucket:null,logicalId:null,docsInfo:i};let s=Re.createDocsBucket({slug:n.slug,environment:n.environment,domain:n.domain});return{bucket:s.bucket,bucketPolicy:s.bucketPolicy,logicalId:s.logicalId,docsInfo:i}}static createPrivateBucket(n){let{slug:i,environment:s,enableVersioning:o=!0,retentionDays:c,encryptionKeyArn:l}=n,u=r({slug:i,environment:s,resourceType:"s3",suffix:"private"}),h=t(u);return{bucket:{Type:"AWS::S3::Bucket",Properties:{BucketName:u,BucketEncryption:{ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:l?{SSEAlgorithm:"aws:kms",KMSMasterKeyID:l}:{SSEAlgorithm:"AES256"}}]},PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0},VersioningConfiguration:o?{Status:"Enabled"}:void 0,LifecycleConfiguration:c?{Rules:[{Id:"RetentionPolicy",Status:"Enabled",ExpirationInDays:c}]}:void 0,Tags:[{Key:"backup",Value:"daily"}]}},logicalId:h}}static checkSourcePaths(n={}){let{projectRoot:i=process.cwd(),paths:s={}}=n,o=s.web||"views/web/dist",c=s.docs||"docs/dist",l=s.private||"private";return{web:{exists:He(ve(i,o)),path:ve(i,o)},docs:{exists:He(ve(i,c)),path:ve(i,c)},private:{exists:He(ve(i,l)),path:ve(i,l)}}}static createDeploymentBuckets(n){let{slug:i,environment:s,domain:o,projectRoot:c,paths:l}=n,u=Re.checkSourcePaths({projectRoot:c,paths:l}),h={},y={web:!1,docs:!1,private:!1},f=Re.createBucket({name:"web",slug:i,environment:s,public:!1,versioning:!1,encryption:!0});if(h[f.logicalId]=f.bucket,y.web=!0,u.docs.exists){let S=Re.createDocsBucket({slug:i,environment:s,domain:o?`docs.${o}`:void 0});if(h[S.logicalId]=S.bucket,S.bucketPolicy)h[`${S.logicalId}Policy`]=S.bucketPolicy;y.docs=!0}if(u.private.exists){let S=Re.createPrivateBucket({slug:i,environment:s,enableVersioning:!0});h[S.logicalId]=S.bucket,y.private=!0}return{resources:h,created:y,sourcePaths:u}}}class je{static createRepository(n){let{name:i,slug:s,environment:o,scanOnPush:c=!0,imageMutability:l="MUTABLE",encryption:u="AES256",kmsKey:h,lifecyclePolicy:y,tags:f}=n,S=r({slug:s,environment:o,resourceType:"ecr",suffix:i}),b=t(S),v={Type:"AWS::ECR::Repository",Properties:{RepositoryName:S,ImageTagMutability:l,ImageScanningConfiguration:{ScanOnPush:c},EncryptionConfiguration:{EncryptionType:u,...h&&u==="KMS"?{KmsKey:h}:{}}}};if(y)v.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(je.generateLifecyclePolicy(y))};if(f)v.Properties.Tags=Object.entries(f).map(([w,E])=>({Key:w,Value:E}));return{repository:v,logicalId:b}}static generateLifecyclePolicy(n){let i=[];if(n.untaggedImageExpireDays!==void 0)i.push({rulePriority:1,description:"Delete untagged images",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:n.untaggedImageExpireDays,countUnit:"days"},action:{type:"expire"}});if(n.maxImageCount!==void 0)i.push({rulePriority:i.length+1,description:"Keep only most recent images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:n.maxImageCount},action:{type:"expire"}});if(n.maxImageAgeDays!==void 0)i.push({rulePriority:i.length+1,description:"Delete images older than specified days",selection:{tagStatus:"any",countType:"sinceImagePushed",countNumber:n.maxImageAgeDays,countUnit:"days"},action:{type:"expire"}});return{rules:i}}static LifecyclePolicies={production:{maxImageCount:10,untaggedImageExpireDays:7},development:{maxImageCount:5,untaggedImageExpireDays:3},minimal:{maxImageCount:3,untaggedImageExpireDays:1},archive:{maxImageCount:50,untaggedImageExpireDays:30}};static enableImmutableTags(n){if(!n.Properties)n.Properties={};return n.Properties.ImageTagMutability="IMMUTABLE",n}static enableScanOnPush(n){if(!n.Properties)n.Properties={};return n.Properties.ImageScanningConfiguration={ScanOnPush:!0},n}static setLifecyclePolicy(n,i){if(!n.Properties)n.Properties={};return n.Properties.LifecyclePolicy={LifecyclePolicyText:JSON.stringify(je.generateLifecyclePolicy(i))},n}static addCrossAccountAccess(n,i){if(!n.Properties)n.Properties={};return n.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"CrossAccountPull",Effect:"Allow",Principal:{AWS:i.map((s)=>`arn:aws:iam::${s}:root`)},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:BatchCheckLayerAvailability"]}]},n}static addLambdaAccess(n){if(!n.Properties)n.Properties={};return n.Properties.RepositoryPolicyText={Version:"2012-10-17",Statement:[{Sid:"LambdaECRImageRetrievalPolicy",Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:["ecr:GetDownloadUrlForLayer","ecr:BatchGetImage"]}]},n}static generateBunDockerfile(n){let{baseImage:i="oven/bun:1-debian",serverPath:s,port:o=3000,additionalDirs:c=[],healthCheckEndpoint:l="/health",nodeCompatible:u=!1,envVars:h={},buildCommands:y=[],runCommand:f}=n,S=["app","config",...c],b=f||`bun run ${s}`,v=`# Multi-stage build for Bun application
24
24
  # Generated by ts-cloud
25
25
 
26
26
  # Builder stage
@@ -47,18 +47,18 @@ COPY --from=builder /app/node_modules ./node_modules
47
47
 
48
48
  # Copy application code
49
49
  COPY package.json ./
50
- `;for(let w of b)T+=`COPY ${w} ./${w}
51
- `;if(T+=`COPY ${s} ./${s}
52
- `,y.length>0){T+=`
50
+ `;for(let w of S)v+=`COPY ${w} ./${w}
51
+ `;if(v+=`COPY ${s} ./${s}
52
+ `,y.length>0){v+=`
53
53
  # Build commands
54
- `;for(let w of y)T+=`RUN ${w}
55
- `}T+=`
54
+ `;for(let w of y)v+=`RUN ${w}
55
+ `}v+=`
56
56
  # Environment variables
57
- `,T+=`ENV NODE_ENV=production
58
- `,T+=`ENV PORT=${o}
59
- `;for(let[w,E]of Object.entries(h))T+=`ENV ${w}=${E}
60
- `;if(u)T+=`ENV BUN_INSTALL_FORCE_NODE_API=1
61
- `;return T+=`
57
+ `,v+=`ENV NODE_ENV=production
58
+ `,v+=`ENV PORT=${o}
59
+ `;for(let[w,E]of Object.entries(h))v+=`ENV ${w}=${E}
60
+ `;if(u)v+=`ENV BUN_INSTALL_FORCE_NODE_API=1
61
+ `;return v+=`
62
62
  # Create storage directory
63
63
  RUN mkdir -p /app/storage && chown -R app:app /app/storage
64
64
 
@@ -74,7 +74,7 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \\
74
74
 
75
75
  # Start application
76
76
  CMD ["bun", "run", "${s}"]
77
- `,T}static generateDockerBuildCommands(n){let{repositoryUri:i,tag:s="latest",dockerfilePath:o="Dockerfile",context:c=".",additionalTags:l=[],buildArgs:u={},platform:h="linux/amd64",noCache:y=!1}=n,f=`${i}:${s}`,b=[s,...l],C=`docker build -f ${o} -t ${f}`;if(h)C+=` --platform ${h}`;if(y)C+=" --no-cache";for(let[E,I]of Object.entries(u))C+=` --build-arg ${E}=${I}`;C+=` ${c}`;let T=b.slice(1).map((E)=>`docker tag ${f} ${i}:${E}`),w=b.map((E)=>`docker push ${i}:${E}`);return{build:C,tag:T,push:w,all:[C,...T,...w]}}static generateEcrLoginCommand(n,i){return`aws ecr get-login-password --region ${n} | docker login --username AWS --password-stdin ${i}.dkr.ecr.${n}.amazonaws.com`}static buildRepositoryUri(n){return`${n.accountId}.dkr.ecr.${n.region}.amazonaws.com/${n.repositoryName}`}static generateImageTags(n){let i=["latest"];if(n.version){i.push(n.version);let s=n.version.split(".");if(s.length>=2)i.push(`${s[0]}.${s[1]}`);if(s.length>=1)i.push(s[0])}if(n.gitSha)i.push(n.gitSha.substring(0,7)),i.push(n.gitSha);if(n.gitBranch){let s=n.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");i.push(s)}if(n.environment)i.push(n.environment);if(n.timestamp){let s=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);i.push(s)}return[...new Set(i)]}static DeploymentWorkflow={generateDeployScript:(n)=>{let i=je.buildRepositoryUri({accountId:n.accountId,region:n.region,repositoryName:n.repositoryName}),s=n.tags||["latest"],o=s[0];return`#!/bin/bash
77
+ `,v}static generateDockerBuildCommands(n){let{repositoryUri:i,tag:s="latest",dockerfilePath:o="Dockerfile",context:c=".",additionalTags:l=[],buildArgs:u={},platform:h="linux/amd64",noCache:y=!1}=n,f=`${i}:${s}`,S=[s,...l],b=`docker build -f ${o} -t ${f}`;if(h)b+=` --platform ${h}`;if(y)b+=" --no-cache";for(let[E,P]of Object.entries(u))b+=` --build-arg ${E}=${P}`;b+=` ${c}`;let v=S.slice(1).map((E)=>`docker tag ${f} ${i}:${E}`),w=S.map((E)=>`docker push ${i}:${E}`);return{build:b,tag:v,push:w,all:[b,...v,...w]}}static generateEcrLoginCommand(n,i){return`aws ecr get-login-password --region ${n} | docker login --username AWS --password-stdin ${i}.dkr.ecr.${n}.amazonaws.com`}static buildRepositoryUri(n){return`${n.accountId}.dkr.ecr.${n.region}.amazonaws.com/${n.repositoryName}`}static generateImageTags(n){let i=["latest"];if(n.version){i.push(n.version);let s=n.version.split(".");if(s.length>=2)i.push(`${s[0]}.${s[1]}`);if(s.length>=1)i.push(s[0])}if(n.gitSha)i.push(n.gitSha.substring(0,7)),i.push(n.gitSha);if(n.gitBranch){let s=n.gitBranch.replace(/[^a-zA-Z0-9.-]/g,"-").replace(/^-+|-+$/g,"");i.push(s)}if(n.environment)i.push(n.environment);if(n.timestamp){let s=new Date().toISOString().replace(/[:.]/g,"-").substring(0,19);i.push(s)}return[...new Set(i)]}static DeploymentWorkflow={generateDeployScript:(n)=>{let i=je.buildRepositoryUri({accountId:n.accountId,region:n.region,repositoryName:n.repositoryName}),s=n.tags||["latest"],o=s[0];return`#!/bin/bash
78
78
  set -e
79
79
 
80
80
  # Configuration
@@ -103,7 +103,7 @@ echo "Image: $IMAGE_URI:${o}"
103
103
  docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
104
104
  docker push $ECR_REGISTRY/$ECR_REPOSITORY:latest`},...n.ecsCluster&&n.ecsService?[{name:"Deploy to ECS",run:`aws ecs update-service --cluster ${n.ecsCluster} --service ${n.ecsService} --force-new-deployment`}]:[]]}}};return`# Generated by ts-cloud
105
105
  ${JSON.stringify(i,null,2).replace(/"/g,"").replace(/,\n/g,`
106
- `)}`}};static DockerfileTemplates={bunServer:(n,i=3000)=>je.generateBunDockerfile({serverPath:n,port:i}),bunWithBuild:(n,i,s=3000)=>je.generateBunDockerfile({serverPath:n,port:s,buildCommands:[i]}),bunFullStack:(n,i=3000)=>je.generateBunDockerfile({serverPath:n,port:i,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(n,i=3000)=>je.generateBunDockerfile({serverPath:n,port:i,healthCheckEndpoint:"/api/health"})}}var Pd=[400,403,404,416,429,500,502,503,504],gg=[500,502,503,504],mg=["GET","HEAD","OPTIONS"],xI="-failover-group",hg=["default","media-quality-based"],fg={min:1,max:3},Ag={min:1,max:10};function Nd(n){if(n===void 0)return[...gg];if(n.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${Pd.join(", ")}). Omit it to use the default ${gg.join(", ")}.`);let i=n.filter((s)=>!Pd.includes(s));if(i.length>0)throw Error(`CloudFront origin failover: ${i.join(", ")} ${i.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${Pd.join(", ")}.`);return[...new Set(n)].sort((s,o)=>s-o)}function yg(n){let{primaryOriginId:i,secondaryOriginId:s}=n;if(!i||!s)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(i===s)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${i}")`);let o=Nd(n.statusCodes);return Na(n.selectionCriteria),{Id:n.groupId??`${i}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:o.length,Items:o}},Members:{Quantity:2,Items:[{OriginId:i},{OriginId:s}]},...n.selectionCriteria?{SelectionCriteria:n.selectionCriteria}:{}}}function Na(n,i="the origin group"){if(n===void 0)return;if(!hg.includes(n))throw Error(`CloudFront origin failover: ${i} has selection criteria ${JSON.stringify(n)}. Allowed: ${hg.join(", ")}.`)}function yt(n,i,s){if(typeof n!=="number"||!Number.isInteger(n)||n<i.min||n>i.max)throw Error(`CloudFront origin: ${s} must be a whole number from ${i.min} to ${i.max}, got ${JSON.stringify(n)}.`)}function De(n,i="the origin"){let s={};if(n?.connectionAttempts!==void 0)yt(n.connectionAttempts,fg,`${i} connectionAttempts`),s.ConnectionAttempts=n.connectionAttempts;if(n?.connectionTimeout!==void 0)yt(n.connectionTimeout,Ag,`${i} connectionTimeout (seconds)`),s.ConnectionTimeout=n.connectionTimeout;return s}function Gr(n){return{Quantity:1,Items:[yg(n)]}}function qt(n,i="the cache behavior"){let s=(Array.isArray(n)?n:n?.Items??[]).filter((o)=>!mg.includes(o.toUpperCase()));if(s.length>0)throw Error(`CloudFront origin failover: ${i} allows ${s.join(", ")}, but a cache behavior that targets an origin group may only allow ${mg.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function kd(n){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(n)&&!/s3-website/i.test(n)}function Qe(n){if(!n)return[];if(Array.isArray(n))return n;return n.Items??[]}function Se(n){return typeof n==="string"?n:void 0}var hr=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function Vt(n,i="the distribution"){let s=Qe(n.Origins),o=new Set(s.map((b)=>Se(b.Id)).filter((b)=>!!b)),c=new Map(s.map((b)=>[Se(b.Id)??"",b.DomainName])),l=s.some((b)=>Se(b.Id)===void 0);for(let b of s){let C=Se(b.Id)??"(unnamed origin)";if(b.ConnectionAttempts!==void 0)yt(b.ConnectionAttempts,fg,`${i} origin "${C}" ConnectionAttempts`);if(b.ConnectionTimeout!==void 0)yt(b.ConnectionTimeout,Ag,`${i} origin "${C}" ConnectionTimeout (seconds)`)}let u=n.OriginGroups,h=Qe(u);if(u&&!Array.isArray(u)&&u.Quantity!==void 0&&u.Quantity!==h.length)throw Error(`CloudFront origin failover: ${i} OriginGroups.Quantity is ${u.Quantity} but it lists ${h.length} group(s).`);let y=new Set;for(let b of h){let C=Se(b.Id);if(b.Id===void 0||b.Id==="")throw Error(`CloudFront origin failover: ${i} has an origin group without an Id.`);let T=`${i} origin group "${C??"(intrinsic id)"}"`;if(C){if(y.has(C))throw Error(`CloudFront origin failover: ${i} declares origin group "${C}" twice.`);if(o.has(C))throw Error(`CloudFront origin failover: ${T} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);y.add(C)}let w=b.Members,E=Qe(w);if(E.length!==2||w?.Quantity!==void 0&&w.Quantity!==E.length)throw Error(`CloudFront origin failover: ${T} must have exactly 2 members (a primary and a secondary), it has ${E.length}${w?.Quantity!==void 0&&w.Quantity!==E.length?` with Quantity ${w.Quantity}`:""}.`);let I=E.map((x)=>Se(x.OriginId));for(let x of I)if(x&&!o.has(x)&&!l)throw Error(`CloudFront origin failover: ${T} lists member "${x}", which is not an origin of this distribution. Origins: ${[...o].join(", ")||"(none)"}.`);if(I[0]&&I[0]===I[1])throw Error(`CloudFront origin failover: ${T} lists "${I[0]}" as both primary and secondary.`);let N=b.FailoverCriteria?.StatusCodes,D=Qe(N);if(Nd(D),N?.Quantity!==void 0&&N.Quantity!==D.length)throw Error(`CloudFront origin failover: ${T} FailoverCriteria.StatusCodes.Quantity is ${N.Quantity} but it lists ${D.length} code(s).`);if(Na(b.SelectionCriteria,T),b.SelectionCriteria==="media-quality-based")for(let x of I){let R=x?Se(c.get(x)):void 0;if(R&&!hr.test(R))throw Error(`CloudFront origin failover: ${T} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${x}" is ${R}. Use 'default'.`)}}let f=[];if(n.DefaultCacheBehavior)f.push({behavior:n.DefaultCacheBehavior,name:"the default cache behavior"});for(let b of Qe(n.CacheBehaviors))f.push({behavior:b,name:`the cache behavior for ${JSON.stringify(b.PathPattern)}`});for(let{behavior:b,name:C}of f){let T=Se(b.TargetOriginId);if(!T)continue;if(y.has(T))qt(b.AllowedMethods??["GET","HEAD"],`${C} of ${i} (origin group "${T}")`);else if(!o.has(T)&&!l&&h.every((w)=>Se(w.Id)!==void 0))throw Error(`CloudFront: ${C} of ${i} targets "${T}", which is neither an origin nor an origin group of this distribution.`)}}class me{static createDistribution(n){let{slug:i,environment:s,origin:o,customDomain:c,certificateArn:l,errorPages:u,cachePolicy:h,edgeFunctions:y,http3:f=!1,comment:b,failoverOrigin:C}=n,T=r({slug:i,environment:s,resourceType:"cdn"}),w=t(T),E={Id:"DefaultOrigin",DomainName:o.domainName,OriginPath:o.originPath||"",...De(o,"the CDN origin")},I;if(o.type==="s3"){let D=`${w}OAC`;I={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${T}-oac`,Description:`Origin Access Control for ${T}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},E.OriginAccessControlId=k.Ref(D)}else if(o.type==="alb"||o.type==="custom")E.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let N={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:b||`CDN for ${T}`,DefaultRootObject:"index.html",Origins:[E],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:f?"http2and3":"http2"}}};if(c&&l)N.Properties.DistributionConfig.Aliases=[c],N.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:l,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(u&&u.length>0)N.Properties.DistributionConfig.CustomErrorResponses=u.map((D)=>({ErrorCode:D.errorCode,ResponseCode:D.responseCode,ResponsePagePath:D.responsePagePath}));if(y&&y.length>0)N.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=y.map((D)=>({EventType:D.event,LambdaFunctionARN:D.functionArn}));if(C)me.addOriginFailover(N,C);return{distribution:N,originAccessControl:I,logicalId:w}}static addOriginFailover(n,i){let s=n.Properties.DistributionConfig,o=s.DefaultCacheBehavior,c=o.TargetOriginId,l=i.id??"FailoverOrigin";if(s.OriginGroups&&s.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(qt(o.AllowedMethods??["GET","HEAD"],"the default cache behavior"),s.Origins.some((b)=>b.Id===l))throw Error(`CloudFront origin failover: an origin with id "${l}" already exists`);let u=yg({primaryOriginId:c,secondaryOriginId:l,statusCodes:i.statusCodes,selectionCriteria:i.selectionCriteria}),h=i.type??(kd(i.domainName)?"s3":"custom"),y={Id:l,DomainName:i.domainName,OriginPath:i.originPath||"",...De(i,"the failover origin")},f=De(i.primary,"the primary origin");if(Object.keys(f).length>0){let b=s.Origins.find((C)=>C.Id===c);if(b)Object.assign(b,f)}if(h==="s3"){let b=s.Origins.find((C)=>C.Id===c);if(y.S3OriginConfig={OriginAccessIdentity:""},b?.OriginAccessControlId)y.OriginAccessControlId=b.OriginAccessControlId}else y.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return s.Origins.push(y),s.OriginGroups={Quantity:1,Items:[u]},o.TargetOriginId=u.Id,Vt(s),n}static setCustomDomain(n,i,s){return n.Properties.DistributionConfig.Aliases=[i],n.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},n}static setErrorPages(n,i){return n.Properties.DistributionConfig.CustomErrorResponses=i.map((s)=>({ErrorCode:s.errorCode,ResponseCode:s.responseCode,ResponsePagePath:s.responsePagePath})),n}static enableHttp3(n){return n.Properties.DistributionConfig.HttpVersion="http2and3",n}static addEdgeFunction(n,i,s){if(!n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:i,LambdaFunctionARN:s}),n}static setCachePolicy(n,i){return n.Properties.DistributionConfig.Comment=`${n.Properties.DistributionConfig.Comment||""} (TTL: ${i.default||86400}s)`,n}static createSpaDistribution(n){return me.createDistribution({...n,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(n){let{slug:i,environment:s}=n,o=r({slug:i,environment:s,resourceType:"edge-docs"}),c=t(o),l=t(`${o}-role`),u=t(`${o}-version`),h={Type:"AWS::IAM::Role",Properties:{RoleName:`${o}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},y=`
106
+ `)}`}};static DockerfileTemplates={bunServer:(n,i=3000)=>je.generateBunDockerfile({serverPath:n,port:i}),bunWithBuild:(n,i,s=3000)=>je.generateBunDockerfile({serverPath:n,port:s,buildCommands:[i]}),bunFullStack:(n,i=3000)=>je.generateBunDockerfile({serverPath:n,port:i,additionalDirs:["public","views","dist"],buildCommands:["bun run build"]}),bunApi:(n,i=3000)=>je.generateBunDockerfile({serverPath:n,port:i,healthCheckEndpoint:"/api/health"})}}var Pd=[400,403,404,416,429,500,502,503,504],gg=[500,502,503,504],mg=["GET","HEAD","OPTIONS"],xI="-failover-group",hg=["default","media-quality-based"],fg={min:1,max:3},Ag={min:1,max:10};function Nd(n){if(n===void 0)return[...gg];if(n.length===0)throw Error(`CloudFront origin failover: statusCodes must list at least one code (allowed: ${Pd.join(", ")}). Omit it to use the default ${gg.join(", ")}.`);let i=n.filter((s)=>!Pd.includes(s));if(i.length>0)throw Error(`CloudFront origin failover: ${i.join(", ")} ${i.length===1?"is not a status code":"are not status codes"} CloudFront can fail over on. Allowed: ${Pd.join(", ")}.`);return[...new Set(n)].sort((s,o)=>s-o)}function yg(n){let{primaryOriginId:i,secondaryOriginId:s}=n;if(!i||!s)throw Error("CloudFront origin failover: both a primary and a secondary origin id are required");if(i===s)throw Error(`CloudFront origin failover: the secondary origin must differ from the primary (both are "${i}")`);let o=Nd(n.statusCodes);return Na(n.selectionCriteria),{Id:n.groupId??`${i}-failover-group`,FailoverCriteria:{StatusCodes:{Quantity:o.length,Items:o}},Members:{Quantity:2,Items:[{OriginId:i},{OriginId:s}]},...n.selectionCriteria?{SelectionCriteria:n.selectionCriteria}:{}}}function Na(n,i="the origin group"){if(n===void 0)return;if(!hg.includes(n))throw Error(`CloudFront origin failover: ${i} has selection criteria ${JSON.stringify(n)}. Allowed: ${hg.join(", ")}.`)}function yt(n,i,s){if(typeof n!=="number"||!Number.isInteger(n)||n<i.min||n>i.max)throw Error(`CloudFront origin: ${s} must be a whole number from ${i.min} to ${i.max}, got ${JSON.stringify(n)}.`)}function De(n,i="the origin"){let s={};if(n?.connectionAttempts!==void 0)yt(n.connectionAttempts,fg,`${i} connectionAttempts`),s.ConnectionAttempts=n.connectionAttempts;if(n?.connectionTimeout!==void 0)yt(n.connectionTimeout,Ag,`${i} connectionTimeout (seconds)`),s.ConnectionTimeout=n.connectionTimeout;return s}function Gr(n){return{Quantity:1,Items:[yg(n)]}}function qt(n,i="the cache behavior"){let s=(Array.isArray(n)?n:n?.Items??[]).filter((o)=>!mg.includes(o.toUpperCase()));if(s.length>0)throw Error(`CloudFront origin failover: ${i} allows ${s.join(", ")}, but a cache behavior that targets an origin group may only allow ${mg.join(", ")}. CloudFront never fails over a write, so point the write paths at a single origin in their own cache behavior.`)}function kd(n){return/\.s3[.-](?:[a-z0-9-]+\.)?amazonaws\.com(?:\.cn)?$/i.test(n)&&!/s3-website/i.test(n)}function Qe(n){if(!n)return[];if(Array.isArray(n))return n;return n.Items??[]}function Se(n){return typeof n==="string"?n:void 0}var hr=/\.mediapackagev2\.[a-z0-9-]+\.amazonaws\.com$/i;function Vt(n,i="the distribution"){let s=Qe(n.Origins),o=new Set(s.map((S)=>Se(S.Id)).filter((S)=>!!S)),c=new Map(s.map((S)=>[Se(S.Id)??"",S.DomainName])),l=s.some((S)=>Se(S.Id)===void 0);for(let S of s){let b=Se(S.Id)??"(unnamed origin)";if(S.ConnectionAttempts!==void 0)yt(S.ConnectionAttempts,fg,`${i} origin "${b}" ConnectionAttempts`);if(S.ConnectionTimeout!==void 0)yt(S.ConnectionTimeout,Ag,`${i} origin "${b}" ConnectionTimeout (seconds)`)}let u=n.OriginGroups,h=Qe(u);if(u&&!Array.isArray(u)&&u.Quantity!==void 0&&u.Quantity!==h.length)throw Error(`CloudFront origin failover: ${i} OriginGroups.Quantity is ${u.Quantity} but it lists ${h.length} group(s).`);let y=new Set;for(let S of h){let b=Se(S.Id);if(S.Id===void 0||S.Id==="")throw Error(`CloudFront origin failover: ${i} has an origin group without an Id.`);let v=`${i} origin group "${b??"(intrinsic id)"}"`;if(b){if(y.has(b))throw Error(`CloudFront origin failover: ${i} declares origin group "${b}" twice.`);if(o.has(b))throw Error(`CloudFront origin failover: ${v} has the same id as an origin. Cache behaviors target groups and origins by id, so the two must differ.`);y.add(b)}let w=S.Members,E=Qe(w);if(E.length!==2||w?.Quantity!==void 0&&w.Quantity!==E.length)throw Error(`CloudFront origin failover: ${v} must have exactly 2 members (a primary and a secondary), it has ${E.length}${w?.Quantity!==void 0&&w.Quantity!==E.length?` with Quantity ${w.Quantity}`:""}.`);let P=E.map((x)=>Se(x.OriginId));for(let x of P)if(x&&!o.has(x)&&!l)throw Error(`CloudFront origin failover: ${v} lists member "${x}", which is not an origin of this distribution. Origins: ${[...o].join(", ")||"(none)"}.`);if(P[0]&&P[0]===P[1])throw Error(`CloudFront origin failover: ${v} lists "${P[0]}" as both primary and secondary.`);let R=S.FailoverCriteria?.StatusCodes,D=Qe(R);if(Nd(D),R?.Quantity!==void 0&&R.Quantity!==D.length)throw Error(`CloudFront origin failover: ${v} FailoverCriteria.StatusCodes.Quantity is ${R.Quantity} but it lists ${D.length} code(s).`);if(Na(S.SelectionCriteria,v),S.SelectionCriteria==="media-quality-based")for(let x of P){let I=x?Se(c.get(x)):void 0;if(I&&!hr.test(I))throw Error(`CloudFront origin failover: ${v} uses media-quality-based selection, which only works between AWS Elemental MediaPackage v2 origins, but member "${x}" is ${I}. Use 'default'.`)}}let f=[];if(n.DefaultCacheBehavior)f.push({behavior:n.DefaultCacheBehavior,name:"the default cache behavior"});for(let S of Qe(n.CacheBehaviors))f.push({behavior:S,name:`the cache behavior for ${JSON.stringify(S.PathPattern)}`});for(let{behavior:S,name:b}of f){let v=Se(S.TargetOriginId);if(!v)continue;if(y.has(v))qt(S.AllowedMethods??["GET","HEAD"],`${b} of ${i} (origin group "${v}")`);else if(!o.has(v)&&!l&&h.every((w)=>Se(w.Id)!==void 0))throw Error(`CloudFront: ${b} of ${i} targets "${v}", which is neither an origin nor an origin group of this distribution.`)}}class me{static createDistribution(n){let{slug:i,environment:s,origin:o,customDomain:c,certificateArn:l,errorPages:u,cachePolicy:h,edgeFunctions:y,http3:f=!1,comment:S,failoverOrigin:b}=n,v=r({slug:i,environment:s,resourceType:"cdn"}),w=t(v),E={Id:"DefaultOrigin",DomainName:o.domainName,OriginPath:o.originPath||"",...De(o,"the CDN origin")},P;if(o.type==="s3"){let D=`${w}OAC`;P={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${v}-oac`,Description:`Origin Access Control for ${v}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},E.OriginAccessControlId=k.Ref(D)}else if(o.type==="alb"||o.type==="custom")E.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};let R={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:S||`CDN for ${v}`,DefaultRootObject:"index.html",Origins:[E],DefaultCacheBehavior:{TargetOriginId:"DefaultOrigin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},PriceClass:"PriceClass_100",HttpVersion:f?"http2and3":"http2"}}};if(c&&l)R.Properties.DistributionConfig.Aliases=[c],R.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:l,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};if(u&&u.length>0)R.Properties.DistributionConfig.CustomErrorResponses=u.map((D)=>({ErrorCode:D.errorCode,ResponseCode:D.responseCode,ResponsePagePath:D.responsePagePath}));if(y&&y.length>0)R.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=y.map((D)=>({EventType:D.event,LambdaFunctionARN:D.functionArn}));if(b)me.addOriginFailover(R,b);return{distribution:R,originAccessControl:P,logicalId:w}}static addOriginFailover(n,i){let s=n.Properties.DistributionConfig,o=s.DefaultCacheBehavior,c=o.TargetOriginId,l=i.id??"FailoverOrigin";if(s.OriginGroups&&s.OriginGroups.Quantity>0)throw Error("CloudFront origin failover: this distribution already has an origin group");if(qt(o.AllowedMethods??["GET","HEAD"],"the default cache behavior"),s.Origins.some((S)=>S.Id===l))throw Error(`CloudFront origin failover: an origin with id "${l}" already exists`);let u=yg({primaryOriginId:c,secondaryOriginId:l,statusCodes:i.statusCodes,selectionCriteria:i.selectionCriteria}),h=i.type??(kd(i.domainName)?"s3":"custom"),y={Id:l,DomainName:i.domainName,OriginPath:i.originPath||"",...De(i,"the failover origin")},f=De(i.primary,"the primary origin");if(Object.keys(f).length>0){let S=s.Origins.find((b)=>b.Id===c);if(S)Object.assign(S,f)}if(h==="s3"){let S=s.Origins.find((b)=>b.Id===c);if(y.S3OriginConfig={OriginAccessIdentity:""},S?.OriginAccessControlId)y.OriginAccessControlId=S.OriginAccessControlId}else y.CustomOriginConfig={HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only"};return s.Origins.push(y),s.OriginGroups={Quantity:1,Items:[u]},o.TargetOriginId=u.Id,Vt(s),n}static setCustomDomain(n,i,s){return n.Properties.DistributionConfig.Aliases=[i],n.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:s,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"},n}static setErrorPages(n,i){return n.Properties.DistributionConfig.CustomErrorResponses=i.map((s)=>({ErrorCode:s.errorCode,ResponseCode:s.responseCode,ResponsePagePath:s.responsePagePath})),n}static enableHttp3(n){return n.Properties.DistributionConfig.HttpVersion="http2and3",n}static addEdgeFunction(n,i,s){if(!n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations)n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations=[];return n.Properties.DistributionConfig.DefaultCacheBehavior.LambdaFunctionAssociations.push({EventType:i,LambdaFunctionARN:s}),n}static setCachePolicy(n,i){return n.Properties.DistributionConfig.Comment=`${n.Properties.DistributionConfig.Comment||""} (TTL: ${i.default||86400}s)`,n}static createSpaDistribution(n){return me.createDistribution({...n,errorPages:[{errorCode:404,responseCode:200,responsePagePath:"/index.html"},{errorCode:403,responseCode:200,responsePagePath:"/index.html"}]})}static createDocsOriginRequestFunction(n){let{slug:i,environment:s}=n,o=r({slug:i,environment:s,resourceType:"edge-docs"}),c=t(o),l=t(`${o}-role`),u=t(`${o}-version`),h={Type:"AWS::IAM::Role",Properties:{RoleName:`${o}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","edgelambda.amazonaws.com"]},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"]}},y=`
107
107
  'use strict';
108
108
 
109
109
  exports.handler = async (event) => {
@@ -136,7 +136,7 @@ exports.handler = async (event) => {
136
136
 
137
137
  return request;
138
138
  };
139
- `.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:o,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:k.GetAtt(l,"Arn"),Code:{ZipFile:y},MemorySize:128,Timeout:5}},role:h,functionLogicalId:c,roleLogicalId:l,versionLogicalId:u}}static createDocsDistribution(n){let{slug:i,environment:s,origin:o,customDomain:c,certificateArn:l,lambdaEdgeFunctionArn:u}=n,h=me.createDistribution({slug:i,environment:s,origin:o,customDomain:c,certificateArn:l,comment:`Docs CDN for ${i}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(u)me.addEdgeFunction(h.distribution,"origin-request",u);return h.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,h.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,h.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,h}static createApiDistribution(n){let{slug:i,environment:s,albDomainName:o,customDomain:c,certificateArn:l,pathPattern:u="/api/*",forwardHeaders:h=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:y="all",whitelistedCookies:f,customOriginHeaders:b={}}=n,C=r({slug:i,environment:s,resourceType:"cdn-api"}),T=t(C),w=Object.entries(b).map(([D,x])=>({HeaderName:D,HeaderValue:x})),E={Id:"ALBOrigin",DomainName:o,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(w.length>0)E.OriginCustomHeaders=w;let I={Forward:y};if(y==="whitelist"&&f)I.WhitelistedNames=f;let N={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${C}`,Origins:[E],DefaultCacheBehavior:{TargetOriginId:"ALBOrigin",ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:0,MaxTTL:0,MinTTL:0,ForwardedValues:{QueryString:!0,Headers:h,Cookies:I}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(c&&l)N.Properties.DistributionConfig.Aliases=[c],N.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:l,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:N,logicalId:T}}static createMultiOriginDistribution(n){let{slug:i,environment:s,s3BucketDomainName:o,albDomainName:c,apiPathPattern:l="/api/*",customDomain:u,certificateArn:h,customOriginHeaders:y={}}=n,f=r({slug:i,environment:s,resourceType:"cdn"}),b=t(f),C=`${b}OAC`,T={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${f}-oac`,Description:`Origin Access Control for ${f}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},w=Object.entries(y).map(([D,x])=>({HeaderName:D,HeaderValue:x})),E={Id:"S3Origin",DomainName:o,OriginAccessControlId:k.Ref(C)},I={Id:"ALBOrigin",DomainName:c,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(w.length>0)I.OriginCustomHeaders=w;let N={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${f}`,DefaultRootObject:"index.html",Origins:[E,I],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:l,TargetOriginId:"ALBOrigin",ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:0,MaxTTL:0,MinTTL:0,ForwardedValues:{QueryString:!0,Headers:["Host","Origin","Authorization","Content-Type","Accept"],Cookies:{Forward:"all"}}}],PriceClass:"PriceClass_100",HttpVersion:"http2",CustomErrorResponses:[{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html"},{ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html"}]}}};if(u&&h)N.Properties.DistributionConfig.Aliases=[u],N.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:h,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:N,originAccessControl:T,logicalId:b,oacLogicalId:C}}static addAlbOrigin(n,i){let{originId:s,domainName:o,pathPattern:c,customHeaders:l={},forwardHeaders:u=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:h={default:0,max:0,min:0}}=i,y=Object.entries(l).map(([b,C])=>({HeaderName:b,HeaderValue:C})),f={Id:s,DomainName:o,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(y.length>0)f.OriginCustomHeaders=y;if(!n.Properties.DistributionConfig.Origins)n.Properties.DistributionConfig.Origins=[];if(n.Properties.DistributionConfig.Origins.push(f),!n.Properties.DistributionConfig.CacheBehaviors)n.Properties.DistributionConfig.CacheBehaviors=[];return n.Properties.DistributionConfig.CacheBehaviors.push({PathPattern:c,TargetOriginId:s,ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:h.default,MaxTTL:h.max,MinTTL:h.min,ForwardedValues:{QueryString:!0,Headers:u,Cookies:{Forward:"all"}}}),n}static addOriginHeader(n,i,s,o){let c=n.Properties.DistributionConfig.Origins?.find((l)=>l.Id===i);if(c){if(!c.OriginCustomHeaders)c.OriginCustomHeaders=[];c.OriginCustomHeaders.push({HeaderName:s,HeaderValue:o})}return n}static EdgeFunctionTemplates={docsOriginRequest:`
139
+ `.trim();return{lambdaFunction:{Type:"AWS::Lambda::Function",Properties:{FunctionName:o,Description:"Lambda@Edge origin request handler for docs routing",Runtime:"nodejs20.x",Handler:"index.handler",Role:k.GetAtt(l,"Arn"),Code:{ZipFile:y},MemorySize:128,Timeout:5}},role:h,functionLogicalId:c,roleLogicalId:l,versionLogicalId:u}}static createDocsDistribution(n){let{slug:i,environment:s,origin:o,customDomain:c,certificateArn:l,lambdaEdgeFunctionArn:u}=n,h=me.createDistribution({slug:i,environment:s,origin:o,customDomain:c,certificateArn:l,comment:`Docs CDN for ${i}`,errorPages:[{errorCode:404,responseCode:404,responsePagePath:"/404.html"},{errorCode:403,responseCode:403,responsePagePath:"/404.html"}]});if(u)me.addEdgeFunction(h.distribution,"origin-request",u);return h.distribution.Properties.DistributionConfig.DefaultCacheBehavior.DefaultTTL=86400,h.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MaxTTL=604800,h.distribution.Properties.DistributionConfig.DefaultCacheBehavior.MinTTL=0,h}static createApiDistribution(n){let{slug:i,environment:s,albDomainName:o,customDomain:c,certificateArn:l,pathPattern:u="/api/*",forwardHeaders:h=["Host","Origin","Authorization","Content-Type","Accept"],forwardCookies:y="all",whitelistedCookies:f,customOriginHeaders:S={}}=n,b=r({slug:i,environment:s,resourceType:"cdn-api"}),v=t(b),w=Object.entries(S).map(([D,x])=>({HeaderName:D,HeaderValue:x})),E={Id:"ALBOrigin",DomainName:o,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(w.length>0)E.OriginCustomHeaders=w;let P={Forward:y};if(y==="whitelist"&&f)P.WhitelistedNames=f;let R={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`API CDN for ${b}`,Origins:[E],DefaultCacheBehavior:{TargetOriginId:"ALBOrigin",ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:0,MaxTTL:0,MinTTL:0,ForwardedValues:{QueryString:!0,Headers:h,Cookies:P}},PriceClass:"PriceClass_100",HttpVersion:"http2"}}};if(c&&l)R.Properties.DistributionConfig.Aliases=[c],R.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:l,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:R,logicalId:v}}static createMultiOriginDistribution(n){let{slug:i,environment:s,s3BucketDomainName:o,albDomainName:c,apiPathPattern:l="/api/*",customDomain:u,certificateArn:h,customOriginHeaders:y={}}=n,f=r({slug:i,environment:s,resourceType:"cdn"}),S=t(f),b=`${S}OAC`,v={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${f}-oac`,Description:`Origin Access Control for ${f}`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},w=Object.entries(y).map(([D,x])=>({HeaderName:D,HeaderValue:x})),E={Id:"S3Origin",DomainName:o,OriginAccessControlId:k.Ref(b)},P={Id:"ALBOrigin",DomainName:c,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(w.length>0)P.OriginCustomHeaders=w;let R={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,Comment:`Multi-origin CDN for ${f}`,DefaultRootObject:"index.html",Origins:[E,P],DefaultCacheBehavior:{TargetOriginId:"S3Origin",ViewerProtocolPolicy:"redirect-to-https",AllowedMethods:["GET","HEAD","OPTIONS"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0},CacheBehaviors:[{PathPattern:l,TargetOriginId:"ALBOrigin",ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:0,MaxTTL:0,MinTTL:0,ForwardedValues:{QueryString:!0,Headers:["Host","Origin","Authorization","Content-Type","Accept"],Cookies:{Forward:"all"}}}],PriceClass:"PriceClass_100",HttpVersion:"http2",CustomErrorResponses:[{ErrorCode:404,ResponseCode:200,ResponsePagePath:"/index.html"},{ErrorCode:403,ResponseCode:200,ResponsePagePath:"/index.html"}]}}};if(u&&h)R.Properties.DistributionConfig.Aliases=[u],R.Properties.DistributionConfig.ViewerCertificate={AcmCertificateArn:h,SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"};return{distribution:R,originAccessControl:v,logicalId:S,oacLogicalId:b}}static addAlbOrigin(n,i){let{originId:s,domainName:o,pathPattern:c,customHeaders:l={},forwardHeaders:u=["Host","Origin","Authorization","Content-Type","Accept"],cacheTtl:h={default:0,max:0,min:0}}=i,y=Object.entries(l).map(([S,b])=>({HeaderName:S,HeaderValue:b})),f={Id:s,DomainName:o,CustomOriginConfig:{HTTPPort:80,HTTPSPort:443,OriginProtocolPolicy:"https-only",OriginSSLProtocols:["TLSv1.2"],OriginReadTimeout:60,OriginKeepaliveTimeout:60}};if(y.length>0)f.OriginCustomHeaders=y;if(!n.Properties.DistributionConfig.Origins)n.Properties.DistributionConfig.Origins=[];if(n.Properties.DistributionConfig.Origins.push(f),!n.Properties.DistributionConfig.CacheBehaviors)n.Properties.DistributionConfig.CacheBehaviors=[];return n.Properties.DistributionConfig.CacheBehaviors.push({PathPattern:c,TargetOriginId:s,ViewerProtocolPolicy:"https-only",AllowedMethods:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],CachedMethods:["GET","HEAD","OPTIONS"],Compress:!0,DefaultTTL:h.default,MaxTTL:h.max,MinTTL:h.min,ForwardedValues:{QueryString:!0,Headers:u,Cookies:{Forward:"all"}}}),n}static addOriginHeader(n,i,s,o){let c=n.Properties.DistributionConfig.Origins?.find((l)=>l.Id===i);if(c){if(!c.OriginCustomHeaders)c.OriginCustomHeaders=[];c.OriginCustomHeaders.push({HeaderName:s,HeaderValue:o})}return n}static EdgeFunctionTemplates={docsOriginRequest:`
140
140
  'use strict';
141
141
  exports.handler = async (event) => {
142
142
  const request = event.Records[0].cf.request;
@@ -209,7 +209,7 @@ exports.handler = async (event) => {
209
209
 
210
210
  return request;
211
211
  };
212
- `.trim()};static Config={ttl:(n)=>{let{min:i=0,max:s=86400,default:o=86400}=n;return{MinTTL:i,MaxTTL:s,DefaultTTL:o}},cookies:(n,i)=>{let s={Forward:n==="allowList"?"whitelist":n};if(n==="allowList"&&i)s.WhitelistedNames=i;return s},allowedMethods:(n)=>{let i={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return i[n]||i.GET_HEAD},cachedMethods:(n)=>{let i={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return i[n]||i.GET_HEAD},ttlPresets:{static:{min:0,max:31536000,default:31536000},dynamic:{min:0,max:0,default:0},api:{min:0,max:3600,default:60},html:{min:0,max:86400,default:86400},images:{min:0,max:604800,default:604800}},cacheBehavior:(n)=>{let{ttl:i={min:0,max:86400,default:86400},cookies:s="none",allowedCookies:o,allowedMethods:c="GET_HEAD",cachedMethods:l="GET_HEAD",compress:u=!0,forwardQueryString:h=!0,forwardHeaders:y=[]}=n;return{MinTTL:i.min,MaxTTL:i.max,DefaultTTL:i.default,Compress:u,AllowedMethods:me.Config.allowedMethods(c),CachedMethods:me.Config.cachedMethods(l),ForwardedValues:{QueryString:h,Headers:y,Cookies:me.Config.cookies(s,o)}}}};static applyConfig(n,i){let s=n.Properties.DistributionConfig.DefaultCacheBehavior;if(i.ttl)s.MinTTL=i.ttl.min,s.MaxTTL=i.ttl.max,s.DefaultTTL=i.ttl.default;if(i.compress!==void 0)s.Compress=i.compress;if(i.allowedMethods)s.AllowedMethods=me.Config.allowedMethods(i.allowedMethods);if(i.cachedMethods)s.CachedMethods=me.Config.cachedMethods(i.cachedMethods);if(i.cookies){if(!s.ForwardedValues)s.ForwardedValues={QueryString:!0};s.ForwardedValues.Cookies=me.Config.cookies(i.cookies,i.allowedCookies)}return n}}var aA=[403,404,500,502,503,504],Bd="TsCloud::StorageFailover",po="AllowCloudFrontFailoverRead",yr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,fr=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function Ig(n){let{failover:i,primaryBucket:s,primaryRegion:o}=n,c=n.where??"storage failover";if(!i||typeof i!=="object")throw Error(`${c}.failover must be an object such as { region: 'us-west-2' }.`);if(!i.region||!yr.test(i.region))throw Error(`${c}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(i.region)}.`);if(i.region===o)throw Error(`${c}.failover.region is ${i.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let l=i.bucket??`${s}-${i.region}`;if(!fr.test(l)||l.includes("..")){let u=i.bucket===void 0&&l.length>63?` The default name (<primary bucket>-<region>) is ${l.length} characters; S3 allows 63. Set ${c}.failover.bucket.`:"";throw Error(`${c}.failover: "${l}" is not a valid S3 bucket name.${u}`)}if(l===s)throw Error(`${c}.failover.bucket must differ from the primary bucket "${s}".`);return{replicaBucket:l,replicaRegion:i.region,replicate:i.replicate!==!1,statusCodes:Nd(i.statusCodes??aA),primaryConnection:De(i,`${c}.failover`)}}function Sg(n,i){return`${n}.s3.${i}.amazonaws.com`}function Cg(n){let i=`arn:aws:s3:::${n.primaryBucket}`,s=`arn:aws:s3:::${n.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...n.roleName?{RoleName:n.roleName}:{},AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"s3.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"failover-replication",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetReplicationConfiguration","s3:ListBucket"],Resource:i},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${i}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${s}/*`}]}}]}}}function Eg(n){return{Role:n.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${n.replicaBucket}`}}]}}function _d(n){return{Sid:po,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${n.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":n.distributionArn}}}}function OI(n){let i=(typeof n==="string"?JSON.parse(n):n)?.Metadata?.[Bd];return Array.isArray(i)?i:[]}class F{static createHostedZone(n){let{domain:i,slug:s,environment:o,comment:c}=n,l=r({slug:s,environment:o,resourceType:"hostedzone"}),u=t(`${l}-${i.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:i,HostedZoneConfig:{Comment:c||`Hosted zone for ${i}`}}},logicalId:u}}static createRecord(n){let{hostedZoneId:i,hostedZoneName:s,name:o,type:c,ttl:l,values:u,aliasTarget:h}=n,y=t(`record-${o.replace(/\./g,"")}-${c}`),f={Type:"AWS::Route53::RecordSet",Properties:{Name:o,Type:c}};if(i)f.Properties.HostedZoneId=i;else if(s)f.Properties.HostedZoneName=s;if(h)f.Properties.AliasTarget={DNSName:h.dnsName,HostedZoneId:h.hostedZoneId,EvaluateTargetHealth:h.evaluateTargetHealth??!1};else f.Properties.TTL=l||300,f.Properties.ResourceRecords=u||[];return{record:f,logicalId:y}}static createCloudFrontAlias(n,i,s){return F.createRecord({hostedZoneId:s,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(n,i,s,o){return F.createRecord({hostedZoneId:o,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:s,evaluateTargetHealth:!0}})}static createCname(n,i,s,o=300){return F.createRecord({hostedZoneId:s,name:n,type:"CNAME",ttl:o,values:[i]})}static createWwwRedirect(n,i){return F.createRecord({hostedZoneId:i,name:`www.${n}`,type:"CNAME",ttl:300,values:[n]})}static createMxRecords(n,i,s,o=300){return F.createRecord({hostedZoneId:s,name:n,type:"MX",ttl:o,values:i.map((c)=>`${c.priority} ${c.server}`)})}static createTxtRecord(n,i,s,o=300){return F.createRecord({hostedZoneId:s,name:n,type:"TXT",ttl:o,values:[`"${i}"`]})}static createSpfRecord(n,i,s){return F.createTxtRecord(n,i,s)}static createDmarcRecord(n,i,s,o){let c=`v=DMARC1; p=${i}; rua=mailto:${s}`;return F.createTxtRecord(`_dmarc.${n}`,c,o)}static createS3WebsiteAlias(n,i,s,o){return F.createRecord({hostedZoneId:o,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:s,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(n,i){return`${n}.s3-website-${i}.amazonaws.com`}static createStoreRecord(n,i,s){return F.createCname(`store.${n}`,i,s)}static createApiRecord(n,i,s){return F.createCname(`api.${n}`,i,s)}static createDocsRecord(n,i,s){return F.createCname(`docs.${n}`,i,s)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class S{static createCertificate(n){let{domain:i,subdomains:s=[],slug:o,environment:c,validationMethod:l="DNS",hostedZoneId:u}=n,h=r({slug:o,environment:c,resourceType:"acm"}),y=t(`${h}-${i.replace(/\./g,"")}`),f=[i];for(let C of s)if(C==="*")f.push(`*.${i}`);else f.push(`${C}.${i}`);let b={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:i,SubjectAlternativeNames:f,ValidationMethod:l}};if(l==="DNS"&&u)b.Properties.DomainValidationOptions=f.map((C)=>({DomainName:C,HostedZoneId:u}));return{certificate:b,logicalId:y}}static createKmsKey(n){let{description:i,slug:s,environment:o,enableRotation:c=!0,multiRegion:l=!1}=n,u=r({slug:s,environment:o,resourceType:"kms"}),h=t(u),y={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:k.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},f={Type:"AWS::KMS::Key",Properties:{Description:i,Enabled:!0,EnableKeyRotation:c,KeyPolicy:y,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:l}},b=t(`${u}-alias`),C={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${s}-${o}`,TargetKeyId:k.Ref(h)}};return{key:f,alias:C,logicalId:h,aliasId:b}}static createFirewall(n){let{slug:i,environment:s,scope:o="CLOUDFRONT",defaultAction:c="allow"}=n,l=r({slug:i,environment:s,resourceType:"waf"}),u=t(l);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:l,Scope:o,DefaultAction:c==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${i} ${s}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${l}-metric`}}},logicalId:u}}static setRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:i.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static blockCountries(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{GeoMatchStatement:{CountryCodes:i.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static blockIpAddresses(n,i,s,o){let c=r({slug:s,environment:o,resourceType:"ipset"}),l=t(`${c}-${i.name}`),u={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${c}-${i.name}`,Scope:n.Properties.Scope,IPAddressVersion:i.ipVersion||"IPV4",Addresses:i.ipAddresses,Description:`Blocked IPs for ${i.name}`}};if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{IPSetReferenceStatement:{Arn:k.GetAtt(l,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),{webAcl:n,ipSet:u,ipSetLogicalId:l}}static addManagedRules(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s={ManagedRuleGroupStatement:{VendorName:i.vendorName,Name:i.ruleName}};if(i.excludedRules&&i.excludedRules.length>0)s.ManagedRuleGroupStatement.ExcludedRules=i.excludedRules.map((o)=>({Name:o}));return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:s,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static ManagedRuleGroups={CoreRuleSet:{vendorName:"AWS",ruleName:"AWSManagedRulesCommonRuleSet"},KnownBadInputs:{vendorName:"AWS",ruleName:"AWSManagedRulesKnownBadInputsRuleSet"},SqlDatabase:{vendorName:"AWS",ruleName:"AWSManagedRulesSQLiRuleSet"},LinuxOS:{vendorName:"AWS",ruleName:"AWSManagedRulesLinuxRuleSet"},PosixOS:{vendorName:"AWS",ruleName:"AWSManagedRulesUnixRuleSet"},AmazonIpReputation:{vendorName:"AWS",ruleName:"AWSManagedRulesAmazonIpReputationList"},AnonymousIpList:{vendorName:"AWS",ruleName:"AWSManagedRulesAnonymousIpList"},BotControl:{vendorName:"AWS",ruleName:"AWSManagedRulesBotControlRuleSet"}};static setPathRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s=i.paths.map((o)=>({SearchString:o,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:i.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:s.map((o)=>({ByteMatchStatement:o}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static setHeaderRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s={RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:i.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(i.headerValue)s.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:i.headerValue,FieldToMatch:{SingleHeader:{Name:i.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:s,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static protectLoginEndpoint(n,i){let{loginPaths:s,priority:o,requestsPerMinute:c=10}=i;return S.setPathRateLimit(n,{name:"LoginRateLimit",priority:o,requestsPerWindow:c*5,paths:s}),n}static protectApiEndpoints(n,i){let{apiPaths:s,priority:o,requestsPerMinute:c=100}=i;return S.setPathRateLimit(n,{name:"ApiRateLimit",priority:o,requestsPerWindow:c*5,paths:s}),n}static createProtectedFirewall(n){let{slug:i,environment:s,scope:o="CLOUDFRONT",enableBotControl:c=!1,enableRateLimiting:l=!0,rateLimitPerMinute:u=2000}=n,{webAcl:h,logicalId:y}=S.createFirewall({slug:i,environment:s,scope:o,defaultAction:"allow"}),f=0;if(h=S.addManagedRules(h,{name:"AWSIPReputationList",priority:f++,...S.ManagedRuleGroups.AmazonIpReputation}),h=S.addManagedRules(h,{name:"AWSAnonymousIPList",priority:f++,...S.ManagedRuleGroups.AnonymousIpList}),h=S.addManagedRules(h,{name:"AWSCoreRuleSet",priority:f++,...S.ManagedRuleGroups.CoreRuleSet}),h=S.addManagedRules(h,{name:"AWSKnownBadInputs",priority:f++,...S.ManagedRuleGroups.KnownBadInputs}),h=S.addManagedRules(h,{name:"AWSSQLi",priority:f++,...S.ManagedRuleGroups.SqlDatabase}),c)h=S.addManagedRules(h,{name:"AWSBotControl",priority:f++,...S.ManagedRuleGroups.BotControl});if(l)h=S.setRateLimit(h,{name:"GlobalRateLimit",priority:f++,requestsPerWindow:u*5});return{webAcl:h,logicalId:y}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}class a{static createServer(n){let{slug:i,environment:s,instanceType:o="t3.micro",imageId:c="ami-0f3caa1cf4417e51b",keyName:l,securityGroupIds:u,subnetId:h,userData:y,volumeSize:f=20,volumeType:b="gp3",encrypted:C=!0}=n,T=r({slug:i,environment:s,resourceType:"ec2"}),w=t(T),E={Type:"AWS::EC2::Instance",Properties:{ImageId:c,InstanceType:o,Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:s}]}};if(l)E.Properties.KeyName=l;if(u)E.Properties.SecurityGroupIds=u;if(h)E.Properties.SubnetId=h;if(y)E.Properties.UserData=k.Base64(y);return E.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:f,VolumeType:b,Encrypted:C,DeleteOnTermination:!0}}],{instance:E,logicalId:w}}static createSecurityGroup(n){let{slug:i,environment:s,vpcId:o,description:c,ingress:l=[],egress:u=[]}=n,h=r({slug:i,environment:s,resourceType:"sg"}),y=t(h),f={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:c||`Security group for ${i} ${s}`,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(o)f.Properties.VpcId=o;if(l.length>0)f.Properties.SecurityGroupIngress=l.map((b)=>({IpProtocol:b.protocol,FromPort:b.fromPort,ToPort:b.toPort,CidrIp:b.cidr,SourceSecurityGroupId:b.sourceSecurityGroupId}));if(u.length>0)f.Properties.SecurityGroupEgress=u.map((b)=>({IpProtocol:b.protocol,FromPort:b.fromPort,ToPort:b.toPort,CidrIp:b.cidr,DestinationSecurityGroupId:b.sourceSecurityGroupId}));return{securityGroup:f,logicalId:y}}static createWebServerSecurityGroup(n,i,s){return a.createSecurityGroup({slug:n,environment:i,vpcId:s,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(n){let{slug:i,environment:s,scheme:o="internet-facing",subnets:c,securityGroups:l,type:u="application"}=n,h=r({slug:i,environment:s,resourceType:"alb"}),y=t(h),f={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:h,Scheme:o,Type:u,Subnets:c,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(l)f.Properties.SecurityGroups=l;return{loadBalancer:f,logicalId:y}}static createTargetGroup(n){let{slug:i,environment:s,port:o,protocol:c="HTTP",vpcId:l,targetType:u="ip",healthCheckPath:h="/",healthCheckInterval:y=30,healthCheckTimeout:f=5,healthyThreshold:b=2,unhealthyThreshold:C=3}=n,T=r({slug:i,environment:s,resourceType:"tg"}),w=t(T);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:T,Port:o,Protocol:c,VpcId:l,TargetType:u,HealthCheckEnabled:!0,HealthCheckProtocol:c,HealthCheckPath:h,HealthCheckIntervalSeconds:y,HealthCheckTimeoutSeconds:f,HealthyThresholdCount:b,UnhealthyThresholdCount:C,Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:s}]}},logicalId:w}}static createListener(n,i){let{port:s,protocol:o="HTTP",certificateArn:c,defaultTargetGroupArn:l}=i,u=t(`listener-${n}-${s}`),h={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:k.Ref(n),Port:s,Protocol:o,DefaultActions:[{Type:"forward",TargetGroupArn:l}]}};if(o==="HTTPS"&&c)h.Properties.Certificates=[{CertificateArn:c}],h.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:h,logicalId:u}}static createEcsCluster(n,i){let s=r({slug:n,environment:i,resourceType:"ecs-cluster"}),o=t(s);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:s,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static createFargateService(n){let{slug:i,environment:s,image:o,cpu:c="256",memory:l="512",desiredCount:u=1,containerPort:h=8080,environmentVariables:y={},secrets:f=[],healthCheck:b,logGroup:C,subnets:T,securityGroups:w,targetGroupArn:E}=n,{cluster:I,logicalId:N}=a.createEcsCluster(i,s),D=r({slug:i,environment:s,resourceType:"fargate"}),x=t(`${D}-execution-role`),R={Type:"AWS::IAM::Role",Properties:{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"]}},_=t(`${D}-task-role`),B={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},W=t(`${D}-task`),J={Type:"AWS::ECS::TaskDefinition",Properties:{Family:D,TaskRoleArn:k.GetAtt(_,"Arn"),ExecutionRoleArn:k.GetAtt(x,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:c,Memory:l,ContainerDefinitions:[{Name:i,Image:o,Essential:!0,PortMappings:[{ContainerPort:h,Protocol:"tcp"}],Environment:Object.entries(y).map(([Z,ne])=>({Name:Z,Value:ne})),Secrets:f.map((Z)=>({Name:Z.name,ValueFrom:Z.valueFrom}))}],Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:s}]}};if(b)J.Properties.ContainerDefinitions[0].HealthCheck={Command:b.command,Interval:b.interval||30,Timeout:b.timeout||5,Retries:b.retries||3,StartPeriod:60};if(C)J.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":C,"awslogs-region":k.Ref("AWS::Region"),"awslogs-stream-prefix":i}};let K=t(`${D}-service`),Y={Type:"AWS::ECS::Service",Properties:{ServiceName:D,Cluster:k.Ref(N),TaskDefinition:k.Ref(W),DesiredCount:u,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:T,SecurityGroups:w,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:s}]}};if(E)Y.Properties.LoadBalancers=[{TargetGroupArn:E,ContainerName:i,ContainerPort:h}];return{cluster:I,taskDefinition:J,service:Y,taskRole:B,executionRole:R,clusterLogicalId:N,taskDefinitionLogicalId:W,serviceLogicalId:K,taskRoleLogicalId:_,executionRoleLogicalId:x}}static createLambdaFunction(n){let{slug:i,environment:s,runtime:o,handler:c,code:l,timeout:u=30,memorySize:h=128,environmentVariables:y={},vpcConfig:f}=n,b=r({slug:i,environment:s,resourceType:"lambda"}),C=t(b),T=t(`${b}-role`),w={Type:"AWS::IAM::Role",Properties:{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"]}};if(f)w.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let E={Type:"AWS::Lambda::Function",Properties:{FunctionName:b,Runtime:o,Role:k.GetAtt(T,"Arn"),Handler:c,Code:{...l.s3Bucket&&{S3Bucket:l.s3Bucket},...l.s3Key&&{S3Key:l.s3Key},...l.zipFile&&{ZipFile:l.zipFile}},Timeout:u,MemorySize:h,Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s}]}};if(Object.keys(y).length>0)E.Properties.Environment={Variables:y};if(f)E.Properties.VpcConfig={SecurityGroupIds:f.securityGroupIds,SubnetIds:f.subnetIds};return{lambdaFunction:E,role:w,logicalId:C,roleLogicalId:T}}static generateNodeServerUserData(n={}){let{nodeVersion:i="20",appRepo:s,environment:o={}}=n,c=Object.entries(o).map(([l,u])=>`echo "export ${l}='${u}'" >> /etc/environment`).join(`
212
+ `.trim()};static Config={ttl:(n)=>{let{min:i=0,max:s=86400,default:o=86400}=n;return{MinTTL:i,MaxTTL:s,DefaultTTL:o}},cookies:(n,i)=>{let s={Forward:n==="allowList"?"whitelist":n};if(n==="allowList"&&i)s.WhitelistedNames=i;return s},allowedMethods:(n)=>{let i={ALL:["GET","HEAD","OPTIONS","PUT","POST","PATCH","DELETE"],GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return i[n]||i.GET_HEAD},cachedMethods:(n)=>{let i={GET_HEAD:["GET","HEAD"],GET_HEAD_OPTIONS:["GET","HEAD","OPTIONS"]};return i[n]||i.GET_HEAD},ttlPresets:{static:{min:0,max:31536000,default:31536000},dynamic:{min:0,max:0,default:0},api:{min:0,max:3600,default:60},html:{min:0,max:86400,default:86400},images:{min:0,max:604800,default:604800}},cacheBehavior:(n)=>{let{ttl:i={min:0,max:86400,default:86400},cookies:s="none",allowedCookies:o,allowedMethods:c="GET_HEAD",cachedMethods:l="GET_HEAD",compress:u=!0,forwardQueryString:h=!0,forwardHeaders:y=[]}=n;return{MinTTL:i.min,MaxTTL:i.max,DefaultTTL:i.default,Compress:u,AllowedMethods:me.Config.allowedMethods(c),CachedMethods:me.Config.cachedMethods(l),ForwardedValues:{QueryString:h,Headers:y,Cookies:me.Config.cookies(s,o)}}}};static applyConfig(n,i){let s=n.Properties.DistributionConfig.DefaultCacheBehavior;if(i.ttl)s.MinTTL=i.ttl.min,s.MaxTTL=i.ttl.max,s.DefaultTTL=i.ttl.default;if(i.compress!==void 0)s.Compress=i.compress;if(i.allowedMethods)s.AllowedMethods=me.Config.allowedMethods(i.allowedMethods);if(i.cachedMethods)s.CachedMethods=me.Config.cachedMethods(i.cachedMethods);if(i.cookies){if(!s.ForwardedValues)s.ForwardedValues={QueryString:!0};s.ForwardedValues.Cookies=me.Config.cookies(i.cookies,i.allowedCookies)}return n}}var aA=[403,404,500,502,503,504],Bd="TsCloud::StorageFailover",po="AllowCloudFrontFailoverRead",yr=/^[a-z]{2}(?:-gov)?-[a-z]+-\d$/,fr=/^[a-z0-9][a-z0-9.-]{1,61}[a-z0-9]$/;function Ig(n){let{failover:i,primaryBucket:s,primaryRegion:o}=n,c=n.where??"storage failover";if(!i||typeof i!=="object")throw Error(`${c}.failover must be an object such as { region: 'us-west-2' }.`);if(!i.region||!yr.test(i.region))throw Error(`${c}.failover.region must be an AWS region such as 'us-west-2', got ${JSON.stringify(i.region)}.`);if(i.region===o)throw Error(`${c}.failover.region is ${i.region}, the same region as the primary bucket. Failover only helps when the replica is in another region.`);let l=i.bucket??`${s}-${i.region}`;if(!fr.test(l)||l.includes("..")){let u=i.bucket===void 0&&l.length>63?` The default name (<primary bucket>-<region>) is ${l.length} characters; S3 allows 63. Set ${c}.failover.bucket.`:"";throw Error(`${c}.failover: "${l}" is not a valid S3 bucket name.${u}`)}if(l===s)throw Error(`${c}.failover.bucket must differ from the primary bucket "${s}".`);return{replicaBucket:l,replicaRegion:i.region,replicate:i.replicate!==!1,statusCodes:Nd(i.statusCodes??aA),primaryConnection:De(i,`${c}.failover`)}}function Sg(n,i){return`${n}.s3.${i}.amazonaws.com`}function Cg(n){let i=`arn:aws:s3:::${n.primaryBucket}`,s=`arn:aws:s3:::${n.replicaBucket}`;return{Type:"AWS::IAM::Role",Properties:{...n.roleName?{RoleName:n.roleName}:{},AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"s3.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"failover-replication",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetReplicationConfiguration","s3:ListBucket"],Resource:i},{Effect:"Allow",Action:["s3:GetObjectVersionForReplication","s3:GetObjectVersionAcl","s3:GetObjectVersionTagging"],Resource:`${i}/*`},{Effect:"Allow",Action:["s3:ReplicateObject","s3:ReplicateDelete","s3:ReplicateTags"],Resource:`${s}/*`}]}}]}}}function Eg(n){return{Role:n.roleArn,Rules:[{Id:"cloudfront-failover-replica",Status:"Enabled",Priority:1,Filter:{Prefix:""},DeleteMarkerReplication:{Status:"Enabled"},Destination:{Bucket:`arn:aws:s3:::${n.replicaBucket}`}}]}}function _d(n){return{Sid:po,Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:`arn:aws:s3:::${n.replicaBucket}/*`,Condition:{StringEquals:{"AWS:SourceArn":n.distributionArn}}}}function OI(n){let i=(typeof n==="string"?JSON.parse(n):n)?.Metadata?.[Bd];return Array.isArray(i)?i:[]}class F{static createHostedZone(n){let{domain:i,slug:s,environment:o,comment:c}=n,l=r({slug:s,environment:o,resourceType:"hostedzone"}),u=t(`${l}-${i.replace(/\./g,"")}`);return{zone:{Type:"AWS::Route53::HostedZone",Properties:{Name:i,HostedZoneConfig:{Comment:c||`Hosted zone for ${i}`}}},logicalId:u}}static createRecord(n){let{hostedZoneId:i,hostedZoneName:s,name:o,type:c,ttl:l,values:u,aliasTarget:h}=n,y=t(`record-${o.replace(/\./g,"")}-${c}`),f={Type:"AWS::Route53::RecordSet",Properties:{Name:o,Type:c}};if(i)f.Properties.HostedZoneId=i;else if(s)f.Properties.HostedZoneName=s;if(h)f.Properties.AliasTarget={DNSName:h.dnsName,HostedZoneId:h.hostedZoneId,EvaluateTargetHealth:h.evaluateTargetHealth??!1};else f.Properties.TTL=l||300,f.Properties.ResourceRecords=u||[];return{record:f,logicalId:y}}static createCloudFrontAlias(n,i,s){return F.createRecord({hostedZoneId:s,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:"Z2FDTNDATAQYW2",evaluateTargetHealth:!1}})}static createAlbAlias(n,i,s,o){return F.createRecord({hostedZoneId:o,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:s,evaluateTargetHealth:!0}})}static createCname(n,i,s,o=300){return F.createRecord({hostedZoneId:s,name:n,type:"CNAME",ttl:o,values:[i]})}static createWwwRedirect(n,i){return F.createRecord({hostedZoneId:i,name:`www.${n}`,type:"CNAME",ttl:300,values:[n]})}static createMxRecords(n,i,s,o=300){return F.createRecord({hostedZoneId:s,name:n,type:"MX",ttl:o,values:i.map((c)=>`${c.priority} ${c.server}`)})}static createTxtRecord(n,i,s,o=300){return F.createRecord({hostedZoneId:s,name:n,type:"TXT",ttl:o,values:[`"${i}"`]})}static createSpfRecord(n,i,s){return F.createTxtRecord(n,i,s)}static createDmarcRecord(n,i,s,o){let c=`v=DMARC1; p=${i}; rua=mailto:${s}`;return F.createTxtRecord(`_dmarc.${n}`,c,o)}static createS3WebsiteAlias(n,i,s,o){return F.createRecord({hostedZoneId:o,name:n,type:"A",aliasTarget:{dnsName:i,hostedZoneId:s,evaluateTargetHealth:!1}})}static S3WebsiteHostedZoneIds={"us-east-1":"Z3AQBSTGFYJSTF","us-east-2":"Z2O1EMRO9K5GLX","us-west-1":"Z2F56UZL2M1ACD","us-west-2":"Z3BJ6K6RIION7M","af-south-1":"Z83WF9RJE8B12","ap-east-1":"ZNB98KWMFR0R6","ap-south-1":"Z11RGJOFQNVJUP","ap-south-2":"Z02976202B4EZMXIPMXF7","ap-northeast-1":"Z2M4EHUR26P7ZW","ap-northeast-2":"Z3W03O7B5YMIYP","ap-northeast-3":"Z2YQB5RD63NC85","ap-southeast-1":"Z3O0J2DXBE1FTB","ap-southeast-2":"Z1WCIBER6CPFUU","ap-southeast-3":"Z01613992JD795ZI93075","ca-central-1":"Z1QDHH18159H29","eu-central-1":"Z21DNDUVLTQW6Q","eu-central-2":"Z030506016YDQGETNASS","eu-west-1":"Z1BKCTXD74EZPE","eu-west-2":"Z3GKZC51ZF0DB4","eu-west-3":"Z3R1K369G5AVDG","eu-north-1":"Z3BAZG2TWCNX0D","eu-south-1":"Z30OZKI7KPW7MI","eu-south-2":"Z0081959F7139GRJC19J","me-south-1":"Z1MPMWCPA7YB62","me-central-1":"Z06143092I8HRBER9VXCO","sa-east-1":"Z7KQH4QJS55SO"};static getS3WebsiteEndpoint(n,i){return`${n}.s3-website-${i}.amazonaws.com`}static createStoreRecord(n,i,s){return F.createCname(`store.${n}`,i,s)}static createApiRecord(n,i,s){return F.createCname(`api.${n}`,i,s)}static createDocsRecord(n,i,s){return F.createCname(`docs.${n}`,i,s)}static CloudFrontHostedZoneId="Z2FDTNDATAQYW2"}class C{static createCertificate(n){let{domain:i,subdomains:s=[],slug:o,environment:c,validationMethod:l="DNS",hostedZoneId:u}=n,h=r({slug:o,environment:c,resourceType:"acm"}),y=t(`${h}-${i.replace(/\./g,"")}`),f=[i];for(let b of s)if(b==="*")f.push(`*.${i}`);else f.push(`${b}.${i}`);let S={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:i,SubjectAlternativeNames:f,ValidationMethod:l}};if(l==="DNS"&&u)S.Properties.DomainValidationOptions=f.map((b)=>({DomainName:b,HostedZoneId:u}));return{certificate:S,logicalId:y}}static createKmsKey(n){let{description:i,slug:s,environment:o,enableRotation:c=!0,multiRegion:l=!1}=n,u=r({slug:s,environment:o,resourceType:"kms"}),h=t(u),y={Version:"2012-10-17",Statement:[{Sid:"Enable IAM User Permissions",Effect:"Allow",Principal:{AWS:k.Sub("arn:aws:iam::${AWS::AccountId}:root")},Action:"kms:*",Resource:"*"},{Sid:"Allow services to use the key",Effect:"Allow",Principal:{Service:["s3.amazonaws.com","cloudfront.amazonaws.com","logs.amazonaws.com","secretsmanager.amazonaws.com"]},Action:["kms:Decrypt","kms:GenerateDataKey"],Resource:"*"}]},f={Type:"AWS::KMS::Key",Properties:{Description:i,Enabled:!0,EnableKeyRotation:c,KeyPolicy:y,KeySpec:"SYMMETRIC_DEFAULT",KeyUsage:"ENCRYPT_DECRYPT",MultiRegion:l}},S=t(`${u}-alias`),b={Type:"AWS::KMS::Alias",Properties:{AliasName:`alias/${s}-${o}`,TargetKeyId:k.Ref(h)}};return{key:f,alias:b,logicalId:h,aliasId:S}}static createFirewall(n){let{slug:i,environment:s,scope:o="CLOUDFRONT",defaultAction:c="allow"}=n,l=r({slug:i,environment:s,resourceType:"waf"}),u=t(l);return{webAcl:{Type:"AWS::WAFv2::WebACL",Properties:{Name:l,Scope:o,DefaultAction:c==="allow"?{Allow:{}}:{Block:{}},Description:`WAF for ${i} ${s}`,Rules:[],VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${l}-metric`}}},logicalId:u}}static setRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:i.aggregateKeyType||"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static blockCountries(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{GeoMatchStatement:{CountryCodes:i.countryCodes}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static blockIpAddresses(n,i,s,o){let c=r({slug:s,environment:o,resourceType:"ipset"}),l=t(`${c}-${i.name}`),u={Type:"AWS::WAFv2::IPSet",Properties:{Name:`${c}-${i.name}`,Scope:n.Properties.Scope,IPAddressVersion:i.ipVersion||"IPV4",Addresses:i.ipAddresses,Description:`Blocked IPs for ${i.name}`}};if(!n.Properties.Rules)n.Properties.Rules=[];return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{IPSetReferenceStatement:{Arn:k.GetAtt(l,"Arn")}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),{webAcl:n,ipSet:u,ipSetLogicalId:l}}static addManagedRules(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s={ManagedRuleGroupStatement:{VendorName:i.vendorName,Name:i.ruleName}};if(i.excludedRules&&i.excludedRules.length>0)s.ManagedRuleGroupStatement.ExcludedRules=i.excludedRules.map((o)=>({Name:o}));return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:s,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static ManagedRuleGroups={CoreRuleSet:{vendorName:"AWS",ruleName:"AWSManagedRulesCommonRuleSet"},KnownBadInputs:{vendorName:"AWS",ruleName:"AWSManagedRulesKnownBadInputsRuleSet"},SqlDatabase:{vendorName:"AWS",ruleName:"AWSManagedRulesSQLiRuleSet"},LinuxOS:{vendorName:"AWS",ruleName:"AWSManagedRulesLinuxRuleSet"},PosixOS:{vendorName:"AWS",ruleName:"AWSManagedRulesUnixRuleSet"},AmazonIpReputation:{vendorName:"AWS",ruleName:"AWSManagedRulesAmazonIpReputationList"},AnonymousIpList:{vendorName:"AWS",ruleName:"AWSManagedRulesAnonymousIpList"},BotControl:{vendorName:"AWS",ruleName:"AWSManagedRulesBotControlRuleSet"}};static setPathRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s=i.paths.map((o)=>({SearchString:o,FieldToMatch:{UriPath:{}},TextTransformation:[{Priority:0,Type:"LOWERCASE"}],PositionalConstraint:"STARTS_WITH"}));return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:{RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:i.aggregateKeyType||"IP",ScopeDownStatement:{OrStatement:{Statements:s.map((o)=>({ByteMatchStatement:o}))}}}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static setHeaderRateLimit(n,i){if(!n.Properties.Rules)n.Properties.Rules=[];let s={RateBasedStatement:{Limit:i.requestsPerWindow,AggregateKeyType:"CUSTOM_KEYS",CustomKeys:[{Header:{Name:i.headerName,TextTransformations:[{Priority:0,Type:"NONE"}]}}]}};if(i.headerValue)s.RateBasedStatement.ScopeDownStatement={ByteMatchStatement:{SearchString:i.headerValue,FieldToMatch:{SingleHeader:{Name:i.headerName}},TextTransformation:[{Priority:0,Type:"NONE"}],PositionalConstraint:"EXACTLY"}};return n.Properties.Rules.push({Name:i.name,Priority:i.priority,Statement:s,Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${i.name}-metric`}}),n}static protectLoginEndpoint(n,i){let{loginPaths:s,priority:o,requestsPerMinute:c=10}=i;return C.setPathRateLimit(n,{name:"LoginRateLimit",priority:o,requestsPerWindow:c*5,paths:s}),n}static protectApiEndpoints(n,i){let{apiPaths:s,priority:o,requestsPerMinute:c=100}=i;return C.setPathRateLimit(n,{name:"ApiRateLimit",priority:o,requestsPerWindow:c*5,paths:s}),n}static createProtectedFirewall(n){let{slug:i,environment:s,scope:o="CLOUDFRONT",enableBotControl:c=!1,enableRateLimiting:l=!0,rateLimitPerMinute:u=2000}=n,{webAcl:h,logicalId:y}=C.createFirewall({slug:i,environment:s,scope:o,defaultAction:"allow"}),f=0;if(h=C.addManagedRules(h,{name:"AWSIPReputationList",priority:f++,...C.ManagedRuleGroups.AmazonIpReputation}),h=C.addManagedRules(h,{name:"AWSAnonymousIPList",priority:f++,...C.ManagedRuleGroups.AnonymousIpList}),h=C.addManagedRules(h,{name:"AWSCoreRuleSet",priority:f++,...C.ManagedRuleGroups.CoreRuleSet}),h=C.addManagedRules(h,{name:"AWSKnownBadInputs",priority:f++,...C.ManagedRuleGroups.KnownBadInputs}),h=C.addManagedRules(h,{name:"AWSSQLi",priority:f++,...C.ManagedRuleGroups.SqlDatabase}),c)h=C.addManagedRules(h,{name:"AWSBotControl",priority:f++,...C.ManagedRuleGroups.BotControl});if(l)h=C.setRateLimit(h,{name:"GlobalRateLimit",priority:f++,requestsPerWindow:u*5});return{webAcl:h,logicalId:y}}static RateLimitPresets={STANDARD:2000,HIGH_TRAFFIC:1e4,STRICT:100,LOGIN:10,API:100}}class a{static createServer(n){let{slug:i,environment:s,instanceType:o="t3.micro",imageId:c="ami-0f3caa1cf4417e51b",keyName:l,securityGroupIds:u,subnetId:h,userData:y,volumeSize:f=20,volumeType:S="gp3",encrypted:b=!0}=n,v=r({slug:i,environment:s,resourceType:"ec2"}),w=t(v),E={Type:"AWS::EC2::Instance",Properties:{ImageId:c,InstanceType:o,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:s}]}};if(l)E.Properties.KeyName=l;if(u)E.Properties.SecurityGroupIds=u;if(h)E.Properties.SubnetId=h;if(y)E.Properties.UserData=k.Base64(y);return E.Properties.BlockDeviceMappings=[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:f,VolumeType:S,Encrypted:b,DeleteOnTermination:!0}}],{instance:E,logicalId:w}}static createSecurityGroup(n){let{slug:i,environment:s,vpcId:o,description:c,ingress:l=[],egress:u=[]}=n,h=r({slug:i,environment:s,resourceType:"sg"}),y=t(h),f={Type:"AWS::EC2::SecurityGroup",Properties:{GroupDescription:c||`Security group for ${i} ${s}`,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(o)f.Properties.VpcId=o;if(l.length>0)f.Properties.SecurityGroupIngress=l.map((S)=>({IpProtocol:S.protocol,FromPort:S.fromPort,ToPort:S.toPort,CidrIp:S.cidr,SourceSecurityGroupId:S.sourceSecurityGroupId}));if(u.length>0)f.Properties.SecurityGroupEgress=u.map((S)=>({IpProtocol:S.protocol,FromPort:S.fromPort,ToPort:S.toPort,CidrIp:S.cidr,DestinationSecurityGroupId:S.sourceSecurityGroupId}));return{securityGroup:f,logicalId:y}}static createWebServerSecurityGroup(n,i,s){return a.createSecurityGroup({slug:n,environment:i,vpcId:s,description:"Security group for web servers - HTTP, HTTPS, SSH",ingress:[{protocol:"tcp",fromPort:80,toPort:80,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:443,toPort:443,cidr:"0.0.0.0/0"},{protocol:"tcp",fromPort:22,toPort:22,cidr:"0.0.0.0/0"}],egress:[{protocol:"-1",fromPort:0,toPort:0,cidr:"0.0.0.0/0"}]})}static createLoadBalancer(n){let{slug:i,environment:s,scheme:o="internet-facing",subnets:c,securityGroups:l,type:u="application"}=n,h=r({slug:i,environment:s,resourceType:"alb"}),y=t(h),f={Type:"AWS::ElasticLoadBalancingV2::LoadBalancer",Properties:{Name:h,Scheme:o,Type:u,Subnets:c,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(l)f.Properties.SecurityGroups=l;return{loadBalancer:f,logicalId:y}}static createTargetGroup(n){let{slug:i,environment:s,port:o,protocol:c="HTTP",vpcId:l,targetType:u="ip",healthCheckPath:h="/",healthCheckInterval:y=30,healthCheckTimeout:f=5,healthyThreshold:S=2,unhealthyThreshold:b=3}=n,v=r({slug:i,environment:s,resourceType:"tg"}),w=t(v);return{targetGroup:{Type:"AWS::ElasticLoadBalancingV2::TargetGroup",Properties:{Name:v,Port:o,Protocol:c,VpcId:l,TargetType:u,HealthCheckEnabled:!0,HealthCheckProtocol:c,HealthCheckPath:h,HealthCheckIntervalSeconds:y,HealthCheckTimeoutSeconds:f,HealthyThresholdCount:S,UnhealthyThresholdCount:b,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:s}]}},logicalId:w}}static createListener(n,i){let{port:s,protocol:o="HTTP",certificateArn:c,defaultTargetGroupArn:l}=i,u=t(`listener-${n}-${s}`),h={Type:"AWS::ElasticLoadBalancingV2::Listener",Properties:{LoadBalancerArn:k.Ref(n),Port:s,Protocol:o,DefaultActions:[{Type:"forward",TargetGroupArn:l}]}};if(o==="HTTPS"&&c)h.Properties.Certificates=[{CertificateArn:c}],h.Properties.SslPolicy="ELBSecurityPolicy-TLS13-1-2-2021-06";return{listener:h,logicalId:u}}static createEcsCluster(n,i){let s=r({slug:n,environment:i,resourceType:"ecs-cluster"}),o=t(s);return{cluster:{Type:"AWS::ECS::Cluster",Properties:{ClusterName:s,Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static createFargateService(n){let{slug:i,environment:s,image:o,cpu:c="256",memory:l="512",desiredCount:u=1,containerPort:h=8080,environmentVariables:y={},secrets:f=[],healthCheck:S,logGroup:b,subnets:v,securityGroups:w,targetGroupArn:E}=n,{cluster:P,logicalId:R}=a.createEcsCluster(i,s),D=r({slug:i,environment:s,resourceType:"fargate"}),x=t(`${D}-execution-role`),I={Type:"AWS::IAM::Role",Properties:{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"]}},_=t(`${D}-task-role`),B={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]}}},W=t(`${D}-task`),J={Type:"AWS::ECS::TaskDefinition",Properties:{Family:D,TaskRoleArn:k.GetAtt(_,"Arn"),ExecutionRoleArn:k.GetAtt(x,"Arn"),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:c,Memory:l,ContainerDefinitions:[{Name:i,Image:o,Essential:!0,PortMappings:[{ContainerPort:h,Protocol:"tcp"}],Environment:Object.entries(y).map(([Z,ne])=>({Name:Z,Value:ne})),Secrets:f.map((Z)=>({Name:Z.name,ValueFrom:Z.valueFrom}))}],Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:s}]}};if(S)J.Properties.ContainerDefinitions[0].HealthCheck={Command:S.command,Interval:S.interval||30,Timeout:S.timeout||5,Retries:S.retries||3,StartPeriod:60};if(b)J.Properties.ContainerDefinitions[0].LogConfiguration={LogDriver:"awslogs",Options:{"awslogs-group":b,"awslogs-region":k.Ref("AWS::Region"),"awslogs-stream-prefix":i}};let K=t(`${D}-service`),Y={Type:"AWS::ECS::Service",Properties:{ServiceName:D,Cluster:k.Ref(R),TaskDefinition:k.Ref(W),DesiredCount:u,LaunchType:"FARGATE",NetworkConfiguration:{AwsvpcConfiguration:{Subnets:v,SecurityGroups:w,AssignPublicIp:"ENABLED"}},Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:s}]}};if(E)Y.Properties.LoadBalancers=[{TargetGroupArn:E,ContainerName:i,ContainerPort:h}];return{cluster:P,taskDefinition:J,service:Y,taskRole:B,executionRole:I,clusterLogicalId:R,taskDefinitionLogicalId:W,serviceLogicalId:K,taskRoleLogicalId:_,executionRoleLogicalId:x}}static createLambdaFunction(n){let{slug:i,environment:s,runtime:o,handler:c,code:l,timeout:u=30,memorySize:h=128,environmentVariables:y={},vpcConfig:f}=n,S=r({slug:i,environment:s,resourceType:"lambda"}),b=t(S),v=t(`${S}-role`),w={Type:"AWS::IAM::Role",Properties:{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"]}};if(f)w.Properties.ManagedPolicyArns.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");let E={Type:"AWS::Lambda::Function",Properties:{FunctionName:S,Runtime:o,Role:k.GetAtt(v,"Arn"),Handler:c,Code:{...l.s3Bucket&&{S3Bucket:l.s3Bucket},...l.s3Key&&{S3Key:l.s3Key},...l.zipFile&&{ZipFile:l.zipFile}},Timeout:u,MemorySize:h,Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:s}]}};if(Object.keys(y).length>0)E.Properties.Environment={Variables:y};if(f)E.Properties.VpcConfig={SecurityGroupIds:f.securityGroupIds,SubnetIds:f.subnetIds};return{lambdaFunction:E,role:w,logicalId:b,roleLogicalId:v}}static generateNodeServerUserData(n={}){let{nodeVersion:i="20",appRepo:s,environment:o={}}=n,c=Object.entries(o).map(([l,u])=>`echo "export ${l}='${u}'" >> /etc/environment`).join(`
213
213
  `);return`#!/bin/bash
214
214
  # Update system
215
215
  yum update -y
@@ -310,7 +310,7 @@ systemctl enable caddy
310
310
  systemctl start caddy
311
311
 
312
312
  echo "Bun server setup complete!"
313
- `}static createLaunchConfiguration(n){let{slug:i,environment:s,imageId:o,instanceType:c,keyName:l,securityGroups:u,userData:h,volumeSize:y=20,volumeType:f="gp3",encrypted:b=!0,iamInstanceProfile:C}=n,T=r({slug:i,environment:s,resourceType:"launch-config"}),w=t(T),E={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:o,InstanceType:c,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:y,VolumeType:f,Encrypted:b,DeleteOnTermination:!0}}]}};if(l)E.Properties.KeyName=l;if(u)E.Properties.SecurityGroups=u;if(h)E.Properties.UserData=k.Base64(h);if(C)E.Properties.IamInstanceProfile=C;return{launchConfiguration:E,logicalId:w}}static createAutoScalingGroup(n){let{slug:i,environment:s,launchConfigurationName:o,minSize:c,maxSize:l,desiredCapacity:u,vpcZoneIdentifier:h,targetGroupArns:y,healthCheckType:f="EC2",healthCheckGracePeriod:b=300,cooldown:C=300,tags:T={}}=n,w=r({slug:i,environment:s,resourceType:"asg"}),E=t(w),I={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:w,LaunchConfigurationName:o,MinSize:c,MaxSize:l,HealthCheckType:f,HealthCheckGracePeriod:b,Cooldown:C,Tags:[{Key:"Name",Value:w,PropagateAtLaunch:!0},{Key:"Environment",Value:s,PropagateAtLaunch:!0},...Object.entries(T).map(([N,D])=>({Key:N,Value:D,PropagateAtLaunch:!0}))]}};if(u!==void 0)I.Properties.DesiredCapacity=u;if(h)I.Properties.VPCZoneIdentifier=h;if(y)I.Properties.TargetGroupARNs=y;return I.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,c-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:I,logicalId:E}}static createScalingPolicy(n){let{slug:i,environment:s,autoScalingGroupName:o,policyType:c="TargetTrackingScaling",targetValue:l=70,predefinedMetricType:u="ASGAverageCPUUtilization"}=n,h=r({slug:i,environment:s,resourceType:"scaling-policy"}),y=t(h),f={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:o,PolicyType:c}};if(c==="TargetTrackingScaling")f.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:u},TargetValue:l};return{scalingPolicy:f,logicalId:y}}static AutoScaling={smallWebServer:(n,i,s,o,c)=>a.createAutoScalingGroup({slug:n,environment:i,launchConfigurationName:s,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:c?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(n,i,s,o,c)=>a.createAutoScalingGroup({slug:n,environment:i,launchConfigurationName:s,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:c?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(n,i,s,o,c)=>a.createAutoScalingGroup({slug:n,environment:i,launchConfigurationName:s,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:c?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(n,i,s,o=70)=>a.createScalingPolicy({slug:n,environment:i,autoScalingGroupName:s,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:o}),requestCountScaling:(n,i,s,o=1000)=>a.createScalingPolicy({slug:n,environment:i,autoScalingGroupName:s,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:o})};static Secrets={fromSecretsManager:(n)=>Object.entries(n).map(([i,s])=>({name:i,valueFrom:s})),fromJsonSecret:(n,i)=>`${n}:${i}::`,fromSecretVersion:(n,i)=>`${n}::${i}:`,fromSecretVersionStage:(n,i)=>`${n}:::${i}`,createAccessPolicy:(n)=>({PolicyName:"SecretsManagerAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:n}]}}),createKmsPolicy:(n)=>({PolicyName:"KMSDecryptAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["kms:Decrypt"],Resource:n}]}}),buildSecretArn:(n)=>`arn:aws:secretsmanager:${n.region}:${n.accountId}:secret:${n.secretName}`,buildSecretArnPattern:(n)=>{let i=n.region||"*",s=n.accountId||"*";return`arn:aws:secretsmanager:${i}:${s}:secret:${n.secretNamePrefix}*`},commonAppSecrets:(n)=>({DATABASE_URL:`${n}/database-url`,DATABASE_PASSWORD:`${n}/database-password`,REDIS_URL:`${n}/redis-url`,REDIS_PASSWORD:`${n}/redis-password`,API_KEY:`${n}/api-key`,JWT_SECRET:`${n}/jwt-secret`,ENCRYPTION_KEY:`${n}/encryption-key`,AWS_ACCESS_KEY_ID:`${n}/aws-access-key-id`,AWS_SECRET_ACCESS_KEY:`${n}/aws-secret-access-key`,MAIL_PASSWORD:`${n}/mail-password`,STRIPE_SECRET_KEY:`${n}/stripe-secret-key`,STRIPE_WEBHOOK_SECRET:`${n}/stripe-webhook-secret`})};static createFargateServiceWithSecrets(n){let{secretArns:i=[],kmsKeyArns:s=[],...o}=n,c=a.createFargateService(o);if(i.length>0){if(!c.executionRole.Properties.Policies)c.executionRole.Properties.Policies=[];if(c.executionRole.Properties.Policies.push(a.Secrets.createAccessPolicy(i)),s.length>0)c.executionRole.Properties.Policies.push(a.Secrets.createKmsPolicy(s))}return c}static generateSecretReferences(n){return n.secrets.map((i)=>{let s=`arn:aws:secretsmanager:${n.region}:${n.accountId}:secret:${n.secretPrefix}/${i}`;return{name:i.toUpperCase().replace(/-/g,"_"),valueFrom:s}})}static EnvSecrets={database:(n)=>[{name:"DB_HOST",valueFrom:`${n}:host::`},{name:"DB_PORT",valueFrom:`${n}:port::`},{name:"DB_USERNAME",valueFrom:`${n}:username::`},{name:"DB_PASSWORD",valueFrom:`${n}:password::`},{name:"DB_NAME",valueFrom:`${n}:dbname::`}],redis:(n)=>[{name:"REDIS_HOST",valueFrom:`${n}:host::`},{name:"REDIS_PORT",valueFrom:`${n}:port::`},{name:"REDIS_PASSWORD",valueFrom:`${n}:password::`}],apiCredentials:(n)=>[{name:"API_KEY",valueFrom:`${n}:apiKey::`},{name:"API_SECRET",valueFrom:`${n}:apiSecret::`}],mail:(n)=>[{name:"MAIL_HOST",valueFrom:`${n}:host::`},{name:"MAIL_PORT",valueFrom:`${n}:port::`},{name:"MAIL_USERNAME",valueFrom:`${n}:username::`},{name:"MAIL_PASSWORD",valueFrom:`${n}:password::`}],awsCredentials:(n)=>[{name:"AWS_ACCESS_KEY_ID",valueFrom:`${n}:accessKeyId::`},{name:"AWS_SECRET_ACCESS_KEY",valueFrom:`${n}:secretAccessKey::`}]};static createJumpBox(n){let{slug:i,environment:s,vpcId:o,subnetId:c,keyName:l,instanceType:u="t3.micro",imageId:h="ami-0f3caa1cf4417e51b",allowedCidrs:y=["0.0.0.0/0"],mountEfs:f}=n,b=r({slug:i,environment:s,resourceType:"jumpbox"}),C=t(`${b}-sg`),T={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${b}-sg`,GroupDescription:`Security group for ${b} JumpBox SSH access`,VpcId:o,SecurityGroupIngress:y.map((B)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:B,Description:`SSH access from ${B}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound traffic"}],Tags:[{Key:"Name",Value:`${b}-sg`},{Key:"Environment",Value:s}]}},w=t(`${b}-role`),E={Type:"AWS::IAM::Role",Properties:{RoleName:`${b}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"],Policies:f?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},I=t(`${b}-profile`),N={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${b}-profile`,Roles:[k.Ref(w)]}},D=`#!/bin/bash
313
+ `}static createLaunchConfiguration(n){let{slug:i,environment:s,imageId:o,instanceType:c,keyName:l,securityGroups:u,userData:h,volumeSize:y=20,volumeType:f="gp3",encrypted:S=!0,iamInstanceProfile:b}=n,v=r({slug:i,environment:s,resourceType:"launch-config"}),w=t(v),E={Type:"AWS::AutoScaling::LaunchConfiguration",Properties:{ImageId:o,InstanceType:c,BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:y,VolumeType:f,Encrypted:S,DeleteOnTermination:!0}}]}};if(l)E.Properties.KeyName=l;if(u)E.Properties.SecurityGroups=u;if(h)E.Properties.UserData=k.Base64(h);if(b)E.Properties.IamInstanceProfile=b;return{launchConfiguration:E,logicalId:w}}static createAutoScalingGroup(n){let{slug:i,environment:s,launchConfigurationName:o,minSize:c,maxSize:l,desiredCapacity:u,vpcZoneIdentifier:h,targetGroupArns:y,healthCheckType:f="EC2",healthCheckGracePeriod:S=300,cooldown:b=300,tags:v={}}=n,w=r({slug:i,environment:s,resourceType:"asg"}),E=t(w),P={Type:"AWS::AutoScaling::AutoScalingGroup",Properties:{AutoScalingGroupName:w,LaunchConfigurationName:o,MinSize:c,MaxSize:l,HealthCheckType:f,HealthCheckGracePeriod:S,Cooldown:b,Tags:[{Key:"Name",Value:w,PropagateAtLaunch:!0},{Key:"Environment",Value:s,PropagateAtLaunch:!0},...Object.entries(v).map(([R,D])=>({Key:R,Value:D,PropagateAtLaunch:!0}))]}};if(u!==void 0)P.Properties.DesiredCapacity=u;if(h)P.Properties.VPCZoneIdentifier=h;if(y)P.Properties.TargetGroupARNs=y;return P.UpdatePolicy={AutoScalingRollingUpdate:{MaxBatchSize:1,MinInstancesInService:Math.max(0,c-1),PauseTime:"PT5M",WaitOnResourceSignals:!1}},{autoScalingGroup:P,logicalId:E}}static createScalingPolicy(n){let{slug:i,environment:s,autoScalingGroupName:o,policyType:c="TargetTrackingScaling",targetValue:l=70,predefinedMetricType:u="ASGAverageCPUUtilization"}=n,h=r({slug:i,environment:s,resourceType:"scaling-policy"}),y=t(h),f={Type:"AWS::AutoScaling::ScalingPolicy",Properties:{AutoScalingGroupName:o,PolicyType:c}};if(c==="TargetTrackingScaling")f.Properties.TargetTrackingConfiguration={PredefinedMetricSpecification:{PredefinedMetricType:u},TargetValue:l};return{scalingPolicy:f,logicalId:y}}static AutoScaling={smallWebServer:(n,i,s,o,c)=>a.createAutoScalingGroup({slug:n,environment:i,launchConfigurationName:s,minSize:2,maxSize:4,desiredCapacity:2,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:c?"ELB":"EC2",healthCheckGracePeriod:300}),mediumWebServer:(n,i,s,o,c)=>a.createAutoScalingGroup({slug:n,environment:i,launchConfigurationName:s,minSize:3,maxSize:10,desiredCapacity:3,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:c?"ELB":"EC2",healthCheckGracePeriod:300}),largeWebServer:(n,i,s,o,c)=>a.createAutoScalingGroup({slug:n,environment:i,launchConfigurationName:s,minSize:5,maxSize:20,desiredCapacity:5,vpcZoneIdentifier:o,targetGroupArns:c,healthCheckType:c?"ELB":"EC2",healthCheckGracePeriod:300}),cpuScaling:(n,i,s,o=70)=>a.createScalingPolicy({slug:n,environment:i,autoScalingGroupName:s,policyType:"TargetTrackingScaling",predefinedMetricType:"ASGAverageCPUUtilization",targetValue:o}),requestCountScaling:(n,i,s,o=1000)=>a.createScalingPolicy({slug:n,environment:i,autoScalingGroupName:s,policyType:"TargetTrackingScaling",predefinedMetricType:"ALBRequestCountPerTarget",targetValue:o})};static Secrets={fromSecretsManager:(n)=>Object.entries(n).map(([i,s])=>({name:i,valueFrom:s})),fromJsonSecret:(n,i)=>`${n}:${i}::`,fromSecretVersion:(n,i)=>`${n}::${i}:`,fromSecretVersionStage:(n,i)=>`${n}:::${i}`,createAccessPolicy:(n)=>({PolicyName:"SecretsManagerAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],Resource:n}]}}),createKmsPolicy:(n)=>({PolicyName:"KMSDecryptAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["kms:Decrypt"],Resource:n}]}}),buildSecretArn:(n)=>`arn:aws:secretsmanager:${n.region}:${n.accountId}:secret:${n.secretName}`,buildSecretArnPattern:(n)=>{let i=n.region||"*",s=n.accountId||"*";return`arn:aws:secretsmanager:${i}:${s}:secret:${n.secretNamePrefix}*`},commonAppSecrets:(n)=>({DATABASE_URL:`${n}/database-url`,DATABASE_PASSWORD:`${n}/database-password`,REDIS_URL:`${n}/redis-url`,REDIS_PASSWORD:`${n}/redis-password`,API_KEY:`${n}/api-key`,JWT_SECRET:`${n}/jwt-secret`,ENCRYPTION_KEY:`${n}/encryption-key`,AWS_ACCESS_KEY_ID:`${n}/aws-access-key-id`,AWS_SECRET_ACCESS_KEY:`${n}/aws-secret-access-key`,MAIL_PASSWORD:`${n}/mail-password`,STRIPE_SECRET_KEY:`${n}/stripe-secret-key`,STRIPE_WEBHOOK_SECRET:`${n}/stripe-webhook-secret`})};static createFargateServiceWithSecrets(n){let{secretArns:i=[],kmsKeyArns:s=[],...o}=n,c=a.createFargateService(o);if(i.length>0){if(!c.executionRole.Properties.Policies)c.executionRole.Properties.Policies=[];if(c.executionRole.Properties.Policies.push(a.Secrets.createAccessPolicy(i)),s.length>0)c.executionRole.Properties.Policies.push(a.Secrets.createKmsPolicy(s))}return c}static generateSecretReferences(n){return n.secrets.map((i)=>{let s=`arn:aws:secretsmanager:${n.region}:${n.accountId}:secret:${n.secretPrefix}/${i}`;return{name:i.toUpperCase().replace(/-/g,"_"),valueFrom:s}})}static EnvSecrets={database:(n)=>[{name:"DB_HOST",valueFrom:`${n}:host::`},{name:"DB_PORT",valueFrom:`${n}:port::`},{name:"DB_USERNAME",valueFrom:`${n}:username::`},{name:"DB_PASSWORD",valueFrom:`${n}:password::`},{name:"DB_NAME",valueFrom:`${n}:dbname::`}],redis:(n)=>[{name:"REDIS_HOST",valueFrom:`${n}:host::`},{name:"REDIS_PORT",valueFrom:`${n}:port::`},{name:"REDIS_PASSWORD",valueFrom:`${n}:password::`}],apiCredentials:(n)=>[{name:"API_KEY",valueFrom:`${n}:apiKey::`},{name:"API_SECRET",valueFrom:`${n}:apiSecret::`}],mail:(n)=>[{name:"MAIL_HOST",valueFrom:`${n}:host::`},{name:"MAIL_PORT",valueFrom:`${n}:port::`},{name:"MAIL_USERNAME",valueFrom:`${n}:username::`},{name:"MAIL_PASSWORD",valueFrom:`${n}:password::`}],awsCredentials:(n)=>[{name:"AWS_ACCESS_KEY_ID",valueFrom:`${n}:accessKeyId::`},{name:"AWS_SECRET_ACCESS_KEY",valueFrom:`${n}:secretAccessKey::`}]};static createJumpBox(n){let{slug:i,environment:s,vpcId:o,subnetId:c,keyName:l,instanceType:u="t3.micro",imageId:h="ami-0f3caa1cf4417e51b",allowedCidrs:y=["0.0.0.0/0"],mountEfs:f}=n,S=r({slug:i,environment:s,resourceType:"jumpbox"}),b=t(`${S}-sg`),v={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:`${S}-sg`,GroupDescription:`Security group for ${S} JumpBox SSH access`,VpcId:o,SecurityGroupIngress:y.map((B)=>({IpProtocol:"tcp",FromPort:22,ToPort:22,CidrIp:B,Description:`SSH access from ${B}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound traffic"}],Tags:[{Key:"Name",Value:`${S}-sg`},{Key:"Environment",Value:s}]}},w=t(`${S}-role`),E={Type:"AWS::IAM::Role",Properties:{RoleName:`${S}-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"],Policies:f?[{PolicyName:"EFSAccess",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess"],Resource:"*"}]}}]:void 0}},P=t(`${S}-profile`),R={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:`${S}-profile`,Roles:[k.Ref(w)]}},D=`#!/bin/bash
314
314
  yum update -y
315
315
  yum install -y amazon-efs-utils nfs-utils jq curl wget htop
316
316
  `;if(f){let B=f.mountPath||"/mnt/efs";D+=`
@@ -318,7 +318,7 @@ yum install -y amazon-efs-utils nfs-utils jq curl wget htop
318
318
  mkdir -p ${B}
319
319
  mount -t efs ${f.fileSystemId}:/ ${B}
320
320
  echo "${f.fileSystemId}:/ ${B} efs defaults,_netdev 0 0" >> /etc/fstab
321
- `}let x=t(b),R={Type:"AWS::EC2::Instance",DependsOn:[I],Properties:{ImageId:h,InstanceType:u,KeyName:l,SubnetId:c,SecurityGroupIds:[k.Ref(C)],IamInstanceProfile:k.Ref(I),UserData:k.Base64(D),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s},{Key:"Purpose",Value:"JumpBox/Bastion"}]}},_={[C]:T,[w]:E,[I]:N,[x]:R};return{instance:R,securityGroup:T,instanceProfile:N,instanceRole:E,instanceLogicalId:x,securityGroupLogicalId:C,instanceProfileLogicalId:I,instanceRoleLogicalId:w,resources:_}}static JumpBox={withEfsMount:(n)=>a.createJumpBox({slug:n.slug,environment:n.environment,vpcId:n.vpcId,subnetId:n.subnetId,keyName:n.keyName,allowedCidrs:n.allowedCidrs,mountEfs:{fileSystemId:n.fileSystemId,mountPath:n.mountPath||"/mnt/efs"}}),minimal:(n)=>a.createJumpBox({slug:n.slug,environment:n.environment,vpcId:n.vpcId,subnetId:n.subnetId,keyName:n.keyName,instanceType:"t3.nano",allowedCidrs:n.allowedCidrs}),withDatabaseTools:(n)=>{let i=a.createJumpBox({slug:n.slug,environment:n.environment,vpcId:n.vpcId,subnetId:n.subnetId,keyName:n.keyName,allowedCidrs:n.allowedCidrs}),s=`#!/bin/bash
321
+ `}let x=t(S),I={Type:"AWS::EC2::Instance",DependsOn:[P],Properties:{ImageId:h,InstanceType:u,KeyName:l,SubnetId:c,SecurityGroupIds:[k.Ref(b)],IamInstanceProfile:k.Ref(P),UserData:k.Base64(D),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:s},{Key:"Purpose",Value:"JumpBox/Bastion"}]}},_={[b]:v,[w]:E,[P]:R,[x]:I};return{instance:I,securityGroup:v,instanceProfile:R,instanceRole:E,instanceLogicalId:x,securityGroupLogicalId:b,instanceProfileLogicalId:P,instanceRoleLogicalId:w,resources:_}}static JumpBox={withEfsMount:(n)=>a.createJumpBox({slug:n.slug,environment:n.environment,vpcId:n.vpcId,subnetId:n.subnetId,keyName:n.keyName,allowedCidrs:n.allowedCidrs,mountEfs:{fileSystemId:n.fileSystemId,mountPath:n.mountPath||"/mnt/efs"}}),minimal:(n)=>a.createJumpBox({slug:n.slug,environment:n.environment,vpcId:n.vpcId,subnetId:n.subnetId,keyName:n.keyName,instanceType:"t3.nano",allowedCidrs:n.allowedCidrs}),withDatabaseTools:(n)=>{let i=a.createJumpBox({slug:n.slug,environment:n.environment,vpcId:n.vpcId,subnetId:n.subnetId,keyName:n.keyName,allowedCidrs:n.allowedCidrs}),s=`#!/bin/bash
322
322
  yum update -y
323
323
  yum install -y amazon-efs-utils nfs-utils jq curl wget htop
324
324
 
@@ -346,7 +346,7 @@ yum install -y mysql
346
346
  yum install -y redis
347
347
 
348
348
  echo "Database tools installed!"
349
- `),i},commonCidrs:{any:["0.0.0.0/0"],privateOnly:["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16"]}};static InstanceSize={toInstanceType:(n,i="t3")=>`${i}.${n}`,specs:{nano:{vcpu:2,memory:0.5,instanceType:"t3.nano"},micro:{vcpu:2,memory:1,instanceType:"t3.micro"},small:{vcpu:2,memory:2,instanceType:"t3.small"},medium:{vcpu:2,memory:4,instanceType:"t3.medium"},large:{vcpu:2,memory:8,instanceType:"t3.large"},xlarge:{vcpu:4,memory:16,instanceType:"t3.xlarge"},"2xlarge":{vcpu:8,memory:32,instanceType:"t3.2xlarge"}},toFargateSpecs:(n)=>{let i={nano:{cpu:"256",memory:"512"},micro:{cpu:"256",memory:"1024"},small:{cpu:"512",memory:"1024"},medium:{cpu:"1024",memory:"2048"},large:{cpu:"2048",memory:"4096"},xlarge:{cpu:"4096",memory:"8192"},"2xlarge":{cpu:"4096",memory:"16384"}};return i[n]||i.medium},toLambdaMemory:(n)=>({nano:128,micro:256,small:512,medium:1024,large:2048,xlarge:4096,"2xlarge":8192})[n]||1024,presets:{webServer:"t3.small",apiServer:"t3.medium",worker:"t3.medium",database:"r6i.large",cache:"r6i.medium",compute:"c6i.large",general:"m6i.medium"}};static DiskConfig={create:(n)=>{let{size:i,type:s="ssd",encrypted:o=!0,iops:c,throughput:l,deleteOnTermination:u=!0}=n,h={standard:"gp2",ssd:"gp3",premium:"io2",gp2:"gp2",gp3:"gp3",io1:"io1",io2:"io2"}[s]||"gp3",y={VolumeSize:i,VolumeType:h,Encrypted:o,DeleteOnTermination:u};if((h==="io1"||h==="io2"||h==="gp3")&&c)y.Iops=c;if(h==="gp3"&&l)y.Throughput=l;return y},presets:{standard:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0},large:{VolumeSize:100,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0},highPerformance:{VolumeSize:50,VolumeType:"io2",Iops:3000,Encrypted:!0,DeleteOnTermination:!0},database:{VolumeSize:100,VolumeType:"io2",Iops:1e4,Encrypted:!0,DeleteOnTermination:!1}}};static SpotConfig={create:(n)=>{let{maxPrice:i,spotInstanceType:s="one-time",interruptionBehavior:o="terminate",blockDurationMinutes:c}=n,l={SpotInstanceType:s,InstanceInterruptionBehavior:o};if(i)l.MaxPrice=i;if(c)l.BlockDurationMinutes=c;return{SpotOptions:l}},presets:{standard:{spotInstanceType:"one-time",interruptionBehavior:"terminate"},persistent:{spotInstanceType:"persistent",interruptionBehavior:"stop"},costOptimized:{maxPrice:"0.05",spotInstanceType:"one-time",interruptionBehavior:"terminate"}}};static MixedInstances={create:(n)=>{let{instanceTypes:i,baseCapacity:s=0,onDemandPercentage:o=20,spotAllocationStrategy:c="capacity-optimized",spotMaxPrice:l}=n,u={OnDemandBaseCapacity:s,OnDemandPercentageAboveBaseCapacity:o,SpotAllocationStrategy:c};if(l)u.SpotMaxPrice=l;let h=i.map(({size:y,weight:f})=>{let b={InstanceType:a.InstanceSize.toInstanceType(y)};if(f)b.WeightedCapacity=String(f);return b});return{MixedInstancesPolicy:{InstancesDistribution:u,LaunchTemplate:{Overrides:h}}}},presets:{costOptimized:{baseCapacity:0,onDemandPercentage:20,spotAllocationStrategy:"lowest-price",instanceTypes:[{size:"small",weight:1},{size:"medium",weight:2}]},balanced:{baseCapacity:1,onDemandPercentage:50,spotAllocationStrategy:"capacity-optimized",instanceTypes:[{size:"medium",weight:1},{size:"large",weight:2}]},highAvailability:{baseCapacity:2,onDemandPercentage:80,spotAllocationStrategy:"capacity-optimized-prioritized",instanceTypes:[{size:"medium",weight:1}]}}};static AutoScalingConfig={create:(n)=>{let{min:i,max:s,desired:o=i,scaleUpThreshold:c=70,scaleDownThreshold:l=30,cooldownSeconds:u=300,targetMetric:h="cpu"}=n,y={cpu:"ASGAverageCPUUtilization",memory:"ASGAverageMemoryUtilization",requests:"ALBRequestCountPerTarget"};return{minSize:i,maxSize:s,desiredCapacity:o,scalingPolicies:[{policyType:"TargetTrackingScaling",targetValue:c,predefinedMetricType:y[h]||y.cpu,scaleInCooldown:u,scaleOutCooldown:u}]}},forEcs:(n)=>{let{min:i,max:s,cpuTarget:o=70,memoryTarget:c}=n,l=[{predefinedMetricType:"ECSServiceAverageCPUUtilization",targetValue:o}];if(c)l.push({predefinedMetricType:"ECSServiceAverageMemoryUtilization",targetValue:c});return{minCapacity:i,maxCapacity:s,targetTrackingPolicies:l}},presets:{small:{min:1,max:3,scaleUpThreshold:70,scaleDownThreshold:30},medium:{min:2,max:10,scaleUpThreshold:70,scaleDownThreshold:30},large:{min:3,max:50,scaleUpThreshold:60,scaleDownThreshold:40},highAvailability:{min:2,max:20,scaleUpThreshold:60,scaleDownThreshold:30}}};static LoadBalancerConfig={healthCheck:(n)=>{let{path:i="/",interval:s=30,timeout:o=5,healthyThreshold:c=2,unhealthyThreshold:l=5,protocol:u="HTTP"}=n,h={HealthCheckIntervalSeconds:s,HealthCheckTimeoutSeconds:o,HealthyThresholdCount:c,UnhealthyThresholdCount:l};if(u!=="TCP")h.HealthCheckPath=i,h.HealthCheckProtocol=u;return h},presets:{standard:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:5},fast:{path:"/health",interval:10,timeout:3,healthyThreshold:2,unhealthyThreshold:2},relaxed:{path:"/health",interval:60,timeout:30,healthyThreshold:2,unhealthyThreshold:10}}};static SslConfig={httpsListener:(n)=>{let{certificateArn:i,targetGroupArn:s,port:o=443,sslPolicy:c="ELBSecurityPolicy-TLS13-1-2-2021-06"}=n;return{Port:o,Protocol:"HTTPS",Certificates:[{CertificateArn:i}],SslPolicy:c,DefaultActions:[{Type:"forward",TargetGroupArn:s}]}},httpRedirectListener:(n=80)=>({Port:n,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}),policies:{tls13:"ELBSecurityPolicy-TLS13-1-2-2021-06",tls12:"ELBSecurityPolicy-TLS-1-2-Ext-2018-06",tls11:"ELBSecurityPolicy-TLS-1-1-2017-01",fips:"ELBSecurityPolicy-TLS-1-2-Ext-FIPS-2022-05"}};static FunctionConfig={create:(n)=>{let{handler:i,runtime:s="nodejs20.x",timeout:o=30,memorySize:c=256,environmentVariables:l,reservedConcurrency:u}=n,h={Handler:i,Runtime:s,Timeout:o,MemorySize:c};if(l)h.Environment={Variables:l};if(u)h.ReservedConcurrentExecutions=u;return h},runtimes:{nodejs20:"nodejs20.x",nodejs18:"nodejs18.x",python312:"python3.12",python311:"python3.11",java21:"java21",java17:"java17",go:"provided.al2023",rust:"provided.al2023",bun:"provided.al2023"},presets:{api:{runtime:"nodejs20.x",timeout:30,memorySize:256},worker:{runtime:"nodejs20.x",timeout:300,memorySize:512},cron:{runtime:"nodejs20.x",timeout:900,memorySize:1024},dataProcessing:{runtime:"nodejs20.x",timeout:900,memorySize:3008}}};static UserData={generateAppServerScript:(n)=>{let{runtime:i="bun",runtimeVersion:s="latest",webServer:o="nginx",processManager:c="systemd",enableSsl:l=!0,sslEmail:u="admin@example.com",domain:h,appPort:y=3000,installDatabaseClients:f=!1,installRedis:b=!1,extraPackages:C=[]}=n,T=`#!/bin/bash
349
+ `),i},commonCidrs:{any:["0.0.0.0/0"],privateOnly:["10.0.0.0/8","172.16.0.0/12","192.168.0.0/16"]}};static InstanceSize={toInstanceType:(n,i="t3")=>`${i}.${n}`,specs:{nano:{vcpu:2,memory:0.5,instanceType:"t3.nano"},micro:{vcpu:2,memory:1,instanceType:"t3.micro"},small:{vcpu:2,memory:2,instanceType:"t3.small"},medium:{vcpu:2,memory:4,instanceType:"t3.medium"},large:{vcpu:2,memory:8,instanceType:"t3.large"},xlarge:{vcpu:4,memory:16,instanceType:"t3.xlarge"},"2xlarge":{vcpu:8,memory:32,instanceType:"t3.2xlarge"}},toFargateSpecs:(n)=>{let i={nano:{cpu:"256",memory:"512"},micro:{cpu:"256",memory:"1024"},small:{cpu:"512",memory:"1024"},medium:{cpu:"1024",memory:"2048"},large:{cpu:"2048",memory:"4096"},xlarge:{cpu:"4096",memory:"8192"},"2xlarge":{cpu:"4096",memory:"16384"}};return i[n]||i.medium},toLambdaMemory:(n)=>({nano:128,micro:256,small:512,medium:1024,large:2048,xlarge:4096,"2xlarge":8192})[n]||1024,presets:{webServer:"t3.small",apiServer:"t3.medium",worker:"t3.medium",database:"r6i.large",cache:"r6i.medium",compute:"c6i.large",general:"m6i.medium"}};static DiskConfig={create:(n)=>{let{size:i,type:s="ssd",encrypted:o=!0,iops:c,throughput:l,deleteOnTermination:u=!0}=n,h={standard:"gp2",ssd:"gp3",premium:"io2",gp2:"gp2",gp3:"gp3",io1:"io1",io2:"io2"}[s]||"gp3",y={VolumeSize:i,VolumeType:h,Encrypted:o,DeleteOnTermination:u};if((h==="io1"||h==="io2"||h==="gp3")&&c)y.Iops=c;if(h==="gp3"&&l)y.Throughput=l;return y},presets:{standard:{VolumeSize:20,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0},large:{VolumeSize:100,VolumeType:"gp3",Encrypted:!0,DeleteOnTermination:!0},highPerformance:{VolumeSize:50,VolumeType:"io2",Iops:3000,Encrypted:!0,DeleteOnTermination:!0},database:{VolumeSize:100,VolumeType:"io2",Iops:1e4,Encrypted:!0,DeleteOnTermination:!1}}};static SpotConfig={create:(n)=>{let{maxPrice:i,spotInstanceType:s="one-time",interruptionBehavior:o="terminate",blockDurationMinutes:c}=n,l={SpotInstanceType:s,InstanceInterruptionBehavior:o};if(i)l.MaxPrice=i;if(c)l.BlockDurationMinutes=c;return{SpotOptions:l}},presets:{standard:{spotInstanceType:"one-time",interruptionBehavior:"terminate"},persistent:{spotInstanceType:"persistent",interruptionBehavior:"stop"},costOptimized:{maxPrice:"0.05",spotInstanceType:"one-time",interruptionBehavior:"terminate"}}};static MixedInstances={create:(n)=>{let{instanceTypes:i,baseCapacity:s=0,onDemandPercentage:o=20,spotAllocationStrategy:c="capacity-optimized",spotMaxPrice:l}=n,u={OnDemandBaseCapacity:s,OnDemandPercentageAboveBaseCapacity:o,SpotAllocationStrategy:c};if(l)u.SpotMaxPrice=l;let h=i.map(({size:y,weight:f})=>{let S={InstanceType:a.InstanceSize.toInstanceType(y)};if(f)S.WeightedCapacity=String(f);return S});return{MixedInstancesPolicy:{InstancesDistribution:u,LaunchTemplate:{Overrides:h}}}},presets:{costOptimized:{baseCapacity:0,onDemandPercentage:20,spotAllocationStrategy:"lowest-price",instanceTypes:[{size:"small",weight:1},{size:"medium",weight:2}]},balanced:{baseCapacity:1,onDemandPercentage:50,spotAllocationStrategy:"capacity-optimized",instanceTypes:[{size:"medium",weight:1},{size:"large",weight:2}]},highAvailability:{baseCapacity:2,onDemandPercentage:80,spotAllocationStrategy:"capacity-optimized-prioritized",instanceTypes:[{size:"medium",weight:1}]}}};static AutoScalingConfig={create:(n)=>{let{min:i,max:s,desired:o=i,scaleUpThreshold:c=70,scaleDownThreshold:l=30,cooldownSeconds:u=300,targetMetric:h="cpu"}=n,y={cpu:"ASGAverageCPUUtilization",memory:"ASGAverageMemoryUtilization",requests:"ALBRequestCountPerTarget"};return{minSize:i,maxSize:s,desiredCapacity:o,scalingPolicies:[{policyType:"TargetTrackingScaling",targetValue:c,predefinedMetricType:y[h]||y.cpu,scaleInCooldown:u,scaleOutCooldown:u}]}},forEcs:(n)=>{let{min:i,max:s,cpuTarget:o=70,memoryTarget:c}=n,l=[{predefinedMetricType:"ECSServiceAverageCPUUtilization",targetValue:o}];if(c)l.push({predefinedMetricType:"ECSServiceAverageMemoryUtilization",targetValue:c});return{minCapacity:i,maxCapacity:s,targetTrackingPolicies:l}},presets:{small:{min:1,max:3,scaleUpThreshold:70,scaleDownThreshold:30},medium:{min:2,max:10,scaleUpThreshold:70,scaleDownThreshold:30},large:{min:3,max:50,scaleUpThreshold:60,scaleDownThreshold:40},highAvailability:{min:2,max:20,scaleUpThreshold:60,scaleDownThreshold:30}}};static LoadBalancerConfig={healthCheck:(n)=>{let{path:i="/",interval:s=30,timeout:o=5,healthyThreshold:c=2,unhealthyThreshold:l=5,protocol:u="HTTP"}=n,h={HealthCheckIntervalSeconds:s,HealthCheckTimeoutSeconds:o,HealthyThresholdCount:c,UnhealthyThresholdCount:l};if(u!=="TCP")h.HealthCheckPath=i,h.HealthCheckProtocol=u;return h},presets:{standard:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:5},fast:{path:"/health",interval:10,timeout:3,healthyThreshold:2,unhealthyThreshold:2},relaxed:{path:"/health",interval:60,timeout:30,healthyThreshold:2,unhealthyThreshold:10}}};static SslConfig={httpsListener:(n)=>{let{certificateArn:i,targetGroupArn:s,port:o=443,sslPolicy:c="ELBSecurityPolicy-TLS13-1-2-2021-06"}=n;return{Port:o,Protocol:"HTTPS",Certificates:[{CertificateArn:i}],SslPolicy:c,DefaultActions:[{Type:"forward",TargetGroupArn:s}]}},httpRedirectListener:(n=80)=>({Port:n,Protocol:"HTTP",DefaultActions:[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]}),policies:{tls13:"ELBSecurityPolicy-TLS13-1-2-2021-06",tls12:"ELBSecurityPolicy-TLS-1-2-Ext-2018-06",tls11:"ELBSecurityPolicy-TLS-1-1-2017-01",fips:"ELBSecurityPolicy-TLS-1-2-Ext-FIPS-2022-05"}};static FunctionConfig={create:(n)=>{let{handler:i,runtime:s="nodejs20.x",timeout:o=30,memorySize:c=256,environmentVariables:l,reservedConcurrency:u}=n,h={Handler:i,Runtime:s,Timeout:o,MemorySize:c};if(l)h.Environment={Variables:l};if(u)h.ReservedConcurrentExecutions=u;return h},runtimes:{nodejs20:"nodejs20.x",nodejs18:"nodejs18.x",python312:"python3.12",python311:"python3.11",java21:"java21",java17:"java17",go:"provided.al2023",rust:"provided.al2023",bun:"provided.al2023"},presets:{api:{runtime:"nodejs20.x",timeout:30,memorySize:256},worker:{runtime:"nodejs20.x",timeout:300,memorySize:512},cron:{runtime:"nodejs20.x",timeout:900,memorySize:1024},dataProcessing:{runtime:"nodejs20.x",timeout:900,memorySize:3008}}};static UserData={generateAppServerScript:(n)=>{let{runtime:i="bun",runtimeVersion:s="latest",webServer:o="nginx",processManager:c="systemd",enableSsl:l=!0,sslEmail:u="admin@example.com",domain:h,appPort:y=3000,installDatabaseClients:f=!1,installRedis:S=!1,extraPackages:b=[]}=n,v=`#!/bin/bash
350
350
  set -e
351
351
 
352
352
  # Update system
@@ -356,7 +356,7 @@ apt-get update && apt-get upgrade -y
356
356
  # Install basic tools
357
357
  apt-get install -y curl wget git jq htop unzip
358
358
 
359
- `;if(i==="bun")T+=a.UserData.Scripts.bun(s);else T+=a.UserData.Scripts.nodeJs(s);if(o==="nginx"){if(T+=a.UserData.Scripts.nginx(),h&&l)T+=a.UserData.Scripts.nginxProxy(h,y)}else if(o==="caddy"){if(T+=a.UserData.Scripts.caddy(),h)T+=a.UserData.Scripts.caddyProxy(h,y)}if(c==="pm2"&&i==="node")T+=a.UserData.Scripts.pm2();if(l&&o==="nginx"&&h)T+=a.UserData.Scripts.letsEncrypt(h,u);if(f)T+=a.UserData.Scripts.databaseClients();if(b)T+=a.UserData.Scripts.redis();if(T+=`
359
+ `;if(i==="bun")v+=a.UserData.Scripts.bun(s);else v+=a.UserData.Scripts.nodeJs(s);if(o==="nginx"){if(v+=a.UserData.Scripts.nginx(),h&&l)v+=a.UserData.Scripts.nginxProxy(h,y)}else if(o==="caddy"){if(v+=a.UserData.Scripts.caddy(),h)v+=a.UserData.Scripts.caddyProxy(h,y)}if(c==="pm2"&&i==="node")v+=a.UserData.Scripts.pm2();if(l&&o==="nginx"&&h)v+=a.UserData.Scripts.letsEncrypt(h,u);if(f)v+=a.UserData.Scripts.databaseClients();if(S)v+=a.UserData.Scripts.redis();if(v+=`
360
360
  # Install AWS CLI
361
361
  if ! command -v aws &> /dev/null; then
362
362
  curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-$(uname -m).zip" -o /tmp/awscliv2.zip
@@ -364,10 +364,10 @@ if ! command -v aws &> /dev/null; then
364
364
  /tmp/aws/install
365
365
  rm -rf /tmp/aws /tmp/awscliv2.zip
366
366
  fi
367
- `,C.length>0)T+=`
367
+ `,b.length>0)v+=`
368
368
  # Install extra packages
369
- apt-get install -y ${C.join(" ")}
370
- `;return T+=`
369
+ apt-get install -y ${b.join(" ")}
370
+ `;return v+=`
371
371
  # Create API server directory
372
372
  mkdir -p /var/www/api
373
373
 
@@ -391,9 +391,9 @@ SERVICEFILE
391
391
 
392
392
  systemctl daemon-reload
393
393
  systemctl enable stacks-api
394
- `,T+=`
394
+ `,v+=`
395
395
  echo "Server setup complete!"
396
- `,T},generateBunAppScript:(n)=>{let{runtime:i="bun",runtimeVersion:s="latest",systemPackages:o=[],database:c,caddyfile:l}=n,u=new Set(o);if(c==="sqlite")u.add("sqlite");else if(c==="mysql")u.add("mysql");else if(c==="postgres")u.add("postgresql15");let h=`#!/bin/bash
396
+ `,v},generateBunAppScript:(n)=>{let{runtime:i="bun",runtimeVersion:s="latest",systemPackages:o=[],database:c,caddyfile:l}=n,u=new Set(o);if(c==="sqlite")u.add("sqlite");else if(c==="mysql")u.add("mysql");else if(c==="postgres")u.add("postgresql15");let h=`#!/bin/bash
397
397
  set -euo pipefail
398
398
 
399
399
  # Amazon Linux 2023 base setup
@@ -604,7 +604,7 @@ ufw default allow outgoing
604
604
  ${n.map((i)=>`ufw allow ${i}`).join(`
605
605
  `)}
606
606
  ufw --force enable
607
- `},Presets:{bunWithNginx:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:n,appPort:i,enableSsl:!0}),bunWithCaddy:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:n,appPort:i,enableSsl:!1}),nodeWithPm2:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:n,appPort:i,enableSsl:!0}),worker:(n="bun")=>a.UserData.generateAppServerScript({runtime:n,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(n){let{slug:i,environment:s,domain:o,instanceLogicalId:c}=n,l=r({slug:i,environment:s,resourceType:"eip"}),u=t(l),h={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:s},...o?[{Key:"Domain",Value:o}]:[]]}},y={[u]:h},f,b;if(c)b=t(`${l}-assoc`),f={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:k.GetAtt(u,"AllocationId"),InstanceId:k.Ref(c)}},y[b]=f;return{eip:h,eipAssociation:f,eipLogicalId:u,associationLogicalId:b,resources:y}}static createServerModeStack(n){let{slug:i,environment:s,vpcId:o,subnetId:c,instanceType:l="t3.small",imageId:u="ami-0f3caa1cf4417e51b",keyName:h,domain:y,userData:f,allowedPorts:b=[22,80,443],volumeSize:C=20,volumeType:T="gp3"}=n,w={},E=r({slug:i,environment:s,resourceType:"server-sg"}),I=t(E),N={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:E,GroupDescription:`Security group for ${i} server`,VpcId:o,SecurityGroupIngress:b.map((ie)=>({IpProtocol:"tcp",FromPort:ie,ToPort:ie,CidrIp:"0.0.0.0/0",Description:`Port ${ie}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:s}]}};w[I]=N;let D=r({slug:i,environment:s,resourceType:"server-role"}),x=t(D),R={Type:"AWS::IAM::Role",Properties:{RoleName:D,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore","arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"],Policies:[{PolicyName:"StacksServerPermissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:SendBulkEmail","ses:VerifyDomainIdentity","ses:VerifyDomainDkim","ses:GetIdentityDkimAttributes","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["route53:ChangeResourceRecordSets","route53:ListResourceRecordSets","route53:GetHostedZone"],Resource:"*"},{Effect:"Allow",Action:["ssm:GetParameter","ssm:GetParameters"],Resource:"*"}]}}]}};w[x]=R;let _=r({slug:i,environment:s,resourceType:"server-profile"}),B=t(_),W={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:_,Roles:[k.Ref(x)]}};w[B]=W;let J=r({slug:i,environment:s,resourceType:"server"}),K=t(J),Y={Type:"AWS::EC2::Instance",DependsOn:[B],Properties:{ImageId:u,InstanceType:l,KeyName:h,SubnetId:c,SecurityGroupIds:[k.Ref(I)],IamInstanceProfile:k.Ref(B),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:C,VolumeType:T,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:J},{Key:"Environment",Value:s},...y?[{Key:"Domain",Value:y}]:[]]}};if(f)Y.Properties.UserData=k.Base64(f);w[K]=Y;let{eip:Z,eipAssociation:ne,eipLogicalId:de,associationLogicalId:oe,resources:le}=a.createElasticIp({slug:i,environment:s,domain:y,instanceLogicalId:K});return Object.assign(w,le),{instance:Y,securityGroup:N,eip:Z,eipAssociation:ne,instanceRole:R,instanceProfile:W,resources:w,outputs:{instanceLogicalId:K,securityGroupLogicalId:I,eipLogicalId:de,associationLogicalId:oe,roleLogicalId:x,profileLogicalId:B}}}static ServerMode={webServer:(n)=>{let i=a.UserData.generateAppServerScript({runtime:n.runtime||"bun",webServer:n.webServer||"nginx",domain:n.domain,enableSsl:!0});return a.createServerModeStack({...n,userData:i,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(n)=>{let i=a.UserData.generateAppServerScript({runtime:n.runtime||"bun",webServer:"none",installRedis:n.installRedis});return a.createServerModeStack({...n,userData:i,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(n)=>a.createServerModeStack({...n,userData:`#!/bin/bash
607
+ `},Presets:{bunWithNginx:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"bun",webServer:"nginx",processManager:"systemd",domain:n,appPort:i,enableSsl:!0}),bunWithCaddy:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"bun",webServer:"caddy",processManager:"systemd",domain:n,appPort:i,enableSsl:!1}),nodeWithPm2:(n,i=3000)=>a.UserData.generateAppServerScript({runtime:"node",webServer:"nginx",processManager:"pm2",domain:n,appPort:i,enableSsl:!0}),worker:(n="bun")=>a.UserData.generateAppServerScript({runtime:n,webServer:"none",processManager:"systemd",enableSsl:!1})}};static createElasticIp(n){let{slug:i,environment:s,domain:o,instanceLogicalId:c}=n,l=r({slug:i,environment:s,resourceType:"eip"}),u=t(l),h={Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:s},...o?[{Key:"Domain",Value:o}]:[]]}},y={[u]:h},f,S;if(c)S=t(`${l}-assoc`),f={Type:"AWS::EC2::EIPAssociation",Properties:{AllocationId:k.GetAtt(u,"AllocationId"),InstanceId:k.Ref(c)}},y[S]=f;return{eip:h,eipAssociation:f,eipLogicalId:u,associationLogicalId:S,resources:y}}static createServerModeStack(n){let{slug:i,environment:s,vpcId:o,subnetId:c,instanceType:l="t3.small",imageId:u="ami-0f3caa1cf4417e51b",keyName:h,domain:y,userData:f,allowedPorts:S=[22,80,443],volumeSize:b=20,volumeType:v="gp3"}=n,w={},E=r({slug:i,environment:s,resourceType:"server-sg"}),P=t(E),R={Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:E,GroupDescription:`Security group for ${i} server`,VpcId:o,SecurityGroupIngress:S.map((ie)=>({IpProtocol:"tcp",FromPort:ie,ToPort:ie,CidrIp:"0.0.0.0/0",Description:`Port ${ie}`})),SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0",Description:"Allow all outbound"}],Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:s}]}};w[P]=R;let D=r({slug:i,environment:s,resourceType:"server-role"}),x=t(D),I={Type:"AWS::IAM::Role",Properties:{RoleName:D,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ec2.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore","arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy"],Policies:[{PolicyName:"StacksServerPermissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:SendBulkEmail","ses:VerifyDomainIdentity","ses:VerifyDomainDkim","ses:GetIdentityDkimAttributes","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["route53:ChangeResourceRecordSets","route53:ListResourceRecordSets","route53:GetHostedZone"],Resource:"*"},{Effect:"Allow",Action:["ssm:GetParameter","ssm:GetParameters"],Resource:"*"}]}}]}};w[x]=I;let _=r({slug:i,environment:s,resourceType:"server-profile"}),B=t(_),W={Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:_,Roles:[k.Ref(x)]}};w[B]=W;let J=r({slug:i,environment:s,resourceType:"server"}),K=t(J),Y={Type:"AWS::EC2::Instance",DependsOn:[B],Properties:{ImageId:u,InstanceType:l,KeyName:h,SubnetId:c,SecurityGroupIds:[k.Ref(P)],IamInstanceProfile:k.Ref(B),BlockDeviceMappings:[{DeviceName:"/dev/xvda",Ebs:{VolumeSize:b,VolumeType:v,Encrypted:!0,DeleteOnTermination:!0}}],Tags:[{Key:"Name",Value:J},{Key:"Environment",Value:s},...y?[{Key:"Domain",Value:y}]:[]]}};if(f)Y.Properties.UserData=k.Base64(f);w[K]=Y;let{eip:Z,eipAssociation:ne,eipLogicalId:de,associationLogicalId:oe,resources:le}=a.createElasticIp({slug:i,environment:s,domain:y,instanceLogicalId:K});return Object.assign(w,le),{instance:Y,securityGroup:R,eip:Z,eipAssociation:ne,instanceRole:I,instanceProfile:W,resources:w,outputs:{instanceLogicalId:K,securityGroupLogicalId:P,eipLogicalId:de,associationLogicalId:oe,roleLogicalId:x,profileLogicalId:B}}}static ServerMode={webServer:(n)=>{let i=a.UserData.generateAppServerScript({runtime:n.runtime||"bun",webServer:n.webServer||"nginx",domain:n.domain,enableSsl:!0});return a.createServerModeStack({...n,userData:i,instanceType:"t3.small",allowedPorts:[22,80,443]})},workerServer:(n)=>{let i=a.UserData.generateAppServerScript({runtime:n.runtime||"bun",webServer:"none",installRedis:n.installRedis});return a.createServerModeStack({...n,userData:i,instanceType:"t3.medium",allowedPorts:[22]})},cacheServer:(n)=>a.createServerModeStack({...n,userData:`#!/bin/bash
608
608
  set -e
609
609
  apt-get update && apt-get upgrade -y
610
610
  apt-get install -y redis-server
@@ -612,7 +612,7 @@ sed -i 's/bind 127.0.0.1/bind 0.0.0.0/' /etc/redis/redis.conf
612
612
  systemctl enable redis-server
613
613
  systemctl restart redis-server
614
614
  echo "Redis server setup complete!"
615
- `,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class A{static createVpc(n){let{slug:i,environment:s,cidr:o="10.0.0.0/16",enableDnsHostnames:c=!0,enableDnsSupport:l=!0}=n,u=r({slug:i,environment:s,resourceType:"vpc"}),h=t(u);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:o,EnableDnsHostnames:c,EnableDnsSupport:l,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s}]}},logicalId:h}}static createSubnet(n){let{slug:i,environment:s,vpcId:o,type:c,cidr:l,availabilityZone:u,mapPublicIp:h=c==="public"}=n,y=r({slug:i,environment:s,resourceType:`subnet-${c}`}),f=t(`${y}-${u}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:o,CidrBlock:l,AvailabilityZone:u,MapPublicIpOnLaunch:h,Tags:[{Key:"Name",Value:`${y}-${u}`},{Key:"Environment",Value:s},{Key:"Type",Value:c}]}},logicalId:f}}static createInternetGateway(n,i){let s=r({slug:n,environment:i,resourceType:"igw"}),o=t(s);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static attachInternetGateway(n,i){let s=t(`${n}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:k.Ref(n),InternetGatewayId:k.Ref(i)}},logicalId:s}}static createEip(n,i){let s=r({slug:n,environment:i,resourceType:"eip"}),o=t(s);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static createNatGateway(n,i){let{slug:s,environment:o,subnetId:c}=n,l=r({slug:s,environment:o,resourceType:"nat"}),u=t(l);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:k.GetAtt(i,"AllocationId"),SubnetId:c,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:o},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:u}}static createRouteTable(n,i,s,o){let c=r({slug:n,environment:i,resourceType:`rt-${o}`}),l=t(c);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:k.Ref(s),Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:i},{Key:"Type",Value:o}]}},logicalId:l}}static createRoute(n,i,s){let o=t(`${n}-route-${s.type}`),c={Type:"AWS::EC2::Route",Properties:{RouteTableId:k.Ref(n),DestinationCidrBlock:i}};if(s.type==="igw")c.Properties.GatewayId=k.Ref(s.logicalId);else if(s.type==="nat")c.Properties.NatGatewayId=k.Ref(s.logicalId);else if(s.type==="instance")c.Properties.InstanceId=k.Ref(s.logicalId);return{route:c,logicalId:o}}static associateSubnetWithRouteTable(n,i){let s=t(`${n}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:k.Ref(n),RouteTableId:k.Ref(i)}},logicalId:s}}static enableFlowLogs(n){let{slug:i,environment:s,resourceId:o,resourceType:c,trafficType:l="ALL",logGroupName:u}=n,h=r({slug:i,environment:s,resourceType:"flowlog"}),y=t(h);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:c,ResourceIds:[o],TrafficType:l,LogDestinationType:"cloud-watch-logs",LogGroupName:u||`/aws/vpc/${i}-${s}`,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}},logicalId:y}}static calculateSubnetCidrs(n,i,s=3){let[o,c]=n.split("/"),l=Number.parseInt(c,10),u=Math.ceil(Math.log2(i*s)),h=l+u;if(h>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[y,f,b,C]=o.split(".").map(Number),T=(y<<24)+(f<<16)+(b<<8)+C,w=2**(32-h),E=[];for(let I=0;I<i*s;I++){let N=T+I*w,D=[N>>>24&255,N>>>16&255,N>>>8&255,N&255].join(".");E.push(`${D}/${h}`)}return E}static getAvailabilityZones(n,i){return["a","b","c","d","e","f"].slice(0,i).map((s)=>`${n}${s}`)}static createMultiAzNetwork(n){let{slug:i,environment:s,region:o,cidr:c="10.0.0.0/16",zones:l=3,enableNatGateway:u=!1,singleNatGateway:h=!1,enableFlowLogs:y=!1}=n,f={},b=[],C=[],T=[],{vpc:w,logicalId:E}=A.createVpc({slug:i,environment:s,cidr:c});f[E]=w;let{internetGateway:I,logicalId:N}=A.createInternetGateway(i,s);f[N]=I;let{attachment:D,logicalId:x}=A.attachInternetGateway(E,N);f[x]=D;let{routeTable:R,logicalId:_}=A.createRouteTable(i,s,E,"public");f[_]=R;let{route:B,logicalId:W}=A.createRoute(_,"0.0.0.0/0",{type:"igw",logicalId:N});B.DependsOn=x,f[W]=B;let J=A.calculateSubnetCidrs(c,l,2),K=A.getAvailabilityZones(o,l),Y=[];for(let Z=0;Z<l;Z++){let ne=K[Z],de=J[Z*2],oe=J[Z*2+1],{subnet:le,logicalId:ie}=A.createSubnet({slug:i,environment:s,vpcId:k.Ref(E),type:"public",cidr:de,availabilityZone:ne});f[ie]=le,b.push(ie);let{association:Ee,logicalId:Fe}=A.associateSubnetWithRouteTable(ie,_);f[Fe]=Ee;let{subnet:Et,logicalId:pe}=A.createSubnet({slug:i,environment:s,vpcId:k.Ref(E),type:"private",cidr:oe,availabilityZone:ne});if(f[pe]=Et,C.push(pe),u&&(!h||Z===0)){let{eip:ue,logicalId:he}=A.createEip(`${i}-${ne}`,s);f[he]=ue;let{natGateway:Ie,logicalId:ye}=A.createNatGateway({slug:`${i}-${ne}`,environment:s,subnetId:k.Ref(ie)},he);Ie.DependsOn=x,f[ye]=Ie,T.push(ye);let{routeTable:Ae,logicalId:Me}=A.createRouteTable(`${i}-${ne}`,s,E,"private");f[Me]=Ae,Y.push(Me);let{route:Ue,logicalId:z}=A.createRoute(Me,"0.0.0.0/0",{type:"nat",logicalId:ye});f[z]=Ue;let{association:ae,logicalId:X}=A.associateSubnetWithRouteTable(pe,Me);f[X]=ae}else if(u&&h&&Z>0){let{association:ue,logicalId:he}=A.associateSubnetWithRouteTable(pe,Y[0]);f[he]=ue}else{let{routeTable:ue,logicalId:he}=A.createRouteTable(`${i}-${ne}-isolated`,s,E,"private");f[he]=ue;let{association:Ie,logicalId:ye}=A.associateSubnetWithRouteTable(pe,he);f[ye]=Ie}}if(y){let{flowLog:Z,logicalId:ne}=A.enableFlowLogs({slug:i,environment:s,resourceId:k.Ref(E),resourceType:"VPC"});f[ne]=Z}return{resources:f,outputs:{vpcId:E,publicSubnetIds:b,privateSubnetIds:C,natGatewayIds:T.length>0?T:void 0}}}static NatGatewayCostWarning=`
615
+ `,instanceType:"t3.medium",allowedPorts:[22,6379]})}}class A{static createVpc(n){let{slug:i,environment:s,cidr:o="10.0.0.0/16",enableDnsHostnames:c=!0,enableDnsSupport:l=!0}=n,u=r({slug:i,environment:s,resourceType:"vpc"}),h=t(u);return{vpc:{Type:"AWS::EC2::VPC",Properties:{CidrBlock:o,EnableDnsHostnames:c,EnableDnsSupport:l,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s}]}},logicalId:h}}static createSubnet(n){let{slug:i,environment:s,vpcId:o,type:c,cidr:l,availabilityZone:u,mapPublicIp:h=c==="public"}=n,y=r({slug:i,environment:s,resourceType:`subnet-${c}`}),f=t(`${y}-${u}`);return{subnet:{Type:"AWS::EC2::Subnet",Properties:{VpcId:o,CidrBlock:l,AvailabilityZone:u,MapPublicIpOnLaunch:h,Tags:[{Key:"Name",Value:`${y}-${u}`},{Key:"Environment",Value:s},{Key:"Type",Value:c}]}},logicalId:f}}static createInternetGateway(n,i){let s=r({slug:n,environment:i,resourceType:"igw"}),o=t(s);return{internetGateway:{Type:"AWS::EC2::InternetGateway",Properties:{Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static attachInternetGateway(n,i){let s=t(`${n}-igw-attachment`);return{attachment:{Type:"AWS::EC2::VPCGatewayAttachment",Properties:{VpcId:k.Ref(n),InternetGatewayId:k.Ref(i)}},logicalId:s}}static createEip(n,i){let s=r({slug:n,environment:i,resourceType:"eip"}),o=t(s);return{eip:{Type:"AWS::EC2::EIP",Properties:{Domain:"vpc",Tags:[{Key:"Name",Value:s},{Key:"Environment",Value:i}]}},logicalId:o}}static createNatGateway(n,i){let{slug:s,environment:o,subnetId:c}=n,l=r({slug:s,environment:o,resourceType:"nat"}),u=t(l);return{natGateway:{Type:"AWS::EC2::NatGateway",Properties:{AllocationId:k.GetAtt(i,"AllocationId"),SubnetId:c,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:o},{Key:"Warning",Value:"NAT Gateway incurs hourly charges"}]}},logicalId:u}}static createRouteTable(n,i,s,o){let c=r({slug:n,environment:i,resourceType:`rt-${o}`}),l=t(c);return{routeTable:{Type:"AWS::EC2::RouteTable",Properties:{VpcId:k.Ref(s),Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:i},{Key:"Type",Value:o}]}},logicalId:l}}static createRoute(n,i,s){let o=t(`${n}-route-${s.type}`),c={Type:"AWS::EC2::Route",Properties:{RouteTableId:k.Ref(n),DestinationCidrBlock:i}};if(s.type==="igw")c.Properties.GatewayId=k.Ref(s.logicalId);else if(s.type==="nat")c.Properties.NatGatewayId=k.Ref(s.logicalId);else if(s.type==="instance")c.Properties.InstanceId=k.Ref(s.logicalId);return{route:c,logicalId:o}}static associateSubnetWithRouteTable(n,i){let s=t(`${n}-rt-assoc`);return{association:{Type:"AWS::EC2::SubnetRouteTableAssociation",Properties:{SubnetId:k.Ref(n),RouteTableId:k.Ref(i)}},logicalId:s}}static enableFlowLogs(n){let{slug:i,environment:s,resourceId:o,resourceType:c,trafficType:l="ALL",logGroupName:u}=n,h=r({slug:i,environment:s,resourceType:"flowlog"}),y=t(h);return{flowLog:{Type:"AWS::EC2::FlowLog",Properties:{ResourceType:c,ResourceIds:[o],TrafficType:l,LogDestinationType:"cloud-watch-logs",LogGroupName:u||`/aws/vpc/${i}-${s}`,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}},logicalId:y}}static calculateSubnetCidrs(n,i,s=3){let[o,c]=n.split("/"),l=Number.parseInt(c,10),u=Math.ceil(Math.log2(i*s)),h=l+u;if(h>28)throw Error("VPC CIDR is too small to accommodate requested subnets");let[y,f,S,b]=o.split(".").map(Number),v=(y<<24)+(f<<16)+(S<<8)+b,w=2**(32-h),E=[];for(let P=0;P<i*s;P++){let R=v+P*w,D=[R>>>24&255,R>>>16&255,R>>>8&255,R&255].join(".");E.push(`${D}/${h}`)}return E}static getAvailabilityZones(n,i){return["a","b","c","d","e","f"].slice(0,i).map((s)=>`${n}${s}`)}static createMultiAzNetwork(n){let{slug:i,environment:s,region:o,cidr:c="10.0.0.0/16",zones:l=3,enableNatGateway:u=!1,singleNatGateway:h=!1,enableFlowLogs:y=!1}=n,f={},S=[],b=[],v=[],{vpc:w,logicalId:E}=A.createVpc({slug:i,environment:s,cidr:c});f[E]=w;let{internetGateway:P,logicalId:R}=A.createInternetGateway(i,s);f[R]=P;let{attachment:D,logicalId:x}=A.attachInternetGateway(E,R);f[x]=D;let{routeTable:I,logicalId:_}=A.createRouteTable(i,s,E,"public");f[_]=I;let{route:B,logicalId:W}=A.createRoute(_,"0.0.0.0/0",{type:"igw",logicalId:R});B.DependsOn=x,f[W]=B;let J=A.calculateSubnetCidrs(c,l,2),K=A.getAvailabilityZones(o,l),Y=[];for(let Z=0;Z<l;Z++){let ne=K[Z],de=J[Z*2],oe=J[Z*2+1],{subnet:le,logicalId:ie}=A.createSubnet({slug:i,environment:s,vpcId:k.Ref(E),type:"public",cidr:de,availabilityZone:ne});f[ie]=le,S.push(ie);let{association:Ee,logicalId:Fe}=A.associateSubnetWithRouteTable(ie,_);f[Fe]=Ee;let{subnet:Et,logicalId:pe}=A.createSubnet({slug:i,environment:s,vpcId:k.Ref(E),type:"private",cidr:oe,availabilityZone:ne});if(f[pe]=Et,b.push(pe),u&&(!h||Z===0)){let{eip:ue,logicalId:he}=A.createEip(`${i}-${ne}`,s);f[he]=ue;let{natGateway:Ie,logicalId:ye}=A.createNatGateway({slug:`${i}-${ne}`,environment:s,subnetId:k.Ref(ie)},he);Ie.DependsOn=x,f[ye]=Ie,v.push(ye);let{routeTable:Ae,logicalId:Me}=A.createRouteTable(`${i}-${ne}`,s,E,"private");f[Me]=Ae,Y.push(Me);let{route:Ue,logicalId:z}=A.createRoute(Me,"0.0.0.0/0",{type:"nat",logicalId:ye});f[z]=Ue;let{association:ae,logicalId:X}=A.associateSubnetWithRouteTable(pe,Me);f[X]=ae}else if(u&&h&&Z>0){let{association:ue,logicalId:he}=A.associateSubnetWithRouteTable(pe,Y[0]);f[he]=ue}else{let{routeTable:ue,logicalId:he}=A.createRouteTable(`${i}-${ne}-isolated`,s,E,"private");f[he]=ue;let{association:Ie,logicalId:ye}=A.associateSubnetWithRouteTable(pe,he);f[ye]=Ie}}if(y){let{flowLog:Z,logicalId:ne}=A.enableFlowLogs({slug:i,environment:s,resourceId:k.Ref(E),resourceType:"VPC"});f[ne]=Z}return{resources:f,outputs:{vpcId:E,publicSubnetIds:S,privateSubnetIds:b,natGatewayIds:v.length>0?v:void 0}}}static NatGatewayCostWarning=`
616
616
  ⚠️ NAT Gateway Cost Warning:
617
617
  - Each NAT Gateway costs approximately $32-45/month (hourly charges)
618
618
  - Data processing charges: $0.045/GB processed
@@ -620,7 +620,7 @@ echo "Redis server setup complete!"
620
620
  - Using a single NAT Gateway (singleNatGateway: true)
621
621
  - Using NAT Instances instead (cheaper but requires management)
622
622
  - Disabling NAT entirely for isolated private subnets
623
- `}class ze{static createFileSystem(n){let{slug:i,environment:s,encrypted:o=!0,kmsKeyId:c,performanceMode:l="generalPurpose",throughputMode:u="bursting",provisionedThroughput:h,enableBackup:y=!0}=n,f=r({slug:i,environment:s,resourceType:"efs"}),b=t(f),C={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:o,PerformanceMode:l,ThroughputMode:u,FileSystemTags:[{Key:"Name",Value:f},{Key:"Environment",Value:s}]}};if(c)C.Properties.KmsKeyId=c;if(u==="provisioned"&&h)C.Properties.ProvisionedThroughputInMibps=h;if(y)C.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:C,logicalId:b}}static createMountTarget(n,i){let{slug:s,environment:o,subnetId:c,securityGroups:l,ipAddress:u}=i,h=r({slug:s,environment:o,resourceType:"efs-mt"}),y=t(`${h}-${c}`),f={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:k.Ref(n),SubnetId:c,SecurityGroups:l}};if(u)f.Properties.IpAddress=u;return{mountTarget:f,logicalId:y}}static createAccessPoint(n,i){let{slug:s,environment:o,path:c="/",uid:l="1000",gid:u="1000",permissions:h="755"}=i,y=r({slug:s,environment:o,resourceType:"efs-ap"}),f=t(`${y}-${c.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:k.Ref(n),PosixUser:{Uid:l,Gid:u},RootDirectory:{Path:c,CreationInfo:{OwnerUid:l,OwnerGid:u,Permissions:h}},AccessPointTags:[{Key:"Name",Value:`${y}-${c}`},{Key:"Environment",Value:o}]}},logicalId:f}}static setLifecyclePolicy(n,i){let{transitionToIA:s,transitionToPrimary:o=!1}=i;if(!n.Properties)n.Properties={};if(n.Properties.LifecyclePolicies=[],s){let c=`AFTER_${s}_DAYS`;n.Properties.LifecyclePolicies.push({TransitionToIA:c})}if(o)n.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return n}static enableBackup(n){if(!n.Properties)n.Properties={};return n.Properties.BackupPolicy={Status:"ENABLED"},n}static disableBackup(n){if(!n.Properties)n.Properties={};return n.Properties.BackupPolicy={Status:"DISABLED"},n}static setProvisionedThroughput(n,i){if(!n.Properties)n.Properties={};return n.Properties.ThroughputMode="provisioned",n.Properties.ProvisionedThroughputInMibps=i,n}static setElasticThroughput(n){if(!n.Properties)n.Properties={};return n.Properties.ThroughputMode="elastic",n}static enableMaxIO(n){if(!n.Properties)n.Properties={};return n.Properties.PerformanceMode="maxIO",n}static createEfsSecurityGroup(n){let{slug:i,environment:s,vpcId:o,sourceSecurityGroupIds:c=[],sourceCidrBlocks:l=[],description:u}=n,h=r({slug:i,environment:s,resourceType:"efs-sg"}),y=t(h),f=[];for(let b of c)f.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:b,Description:"NFS from security group"});for(let b of l)f.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:b,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:h,GroupDescription:u||`Security group for EFS mount targets - ${i} ${s}`,VpcId:o,SecurityGroupIngress:f,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}},logicalId:y}}static createMultiAzMountTargets(n,i){let{slug:s,environment:o,subnetIds:c,securityGroupId:l}=i,u=[],h=[];for(let y=0;y<c.length;y++){let f=c[y],b=r({slug:s,environment:o,resourceType:"efs-mt"}),C=t(`${b}-az${y+1}`),T={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:k.Ref(n),SubnetId:f,SecurityGroups:[l]}};u.push(T),h.push(C)}return{mountTargets:u,logicalIds:h}}static createCompleteFileSystem(n){let{slug:i,environment:s,vpcId:o,subnetIds:c,sourceSecurityGroupIds:l=[],encrypted:u=!0,performanceMode:h="generalPurpose",throughputMode:y="elastic",enableBackup:f=!0,transitionToIA:b}=n,C={},{fileSystem:T,logicalId:w}=ze.createFileSystem({slug:i,environment:s,encrypted:u,performanceMode:h,throughputMode:y,enableBackup:f});if(b)ze.setLifecyclePolicy(T,{transitionToIA:b,transitionToPrimary:!0});C[w]=T;let{securityGroup:E,logicalId:I}=ze.createEfsSecurityGroup({slug:i,environment:s,vpcId:o,sourceSecurityGroupIds:l});C[I]=E;let{mountTargets:N,logicalIds:D}=ze.createMultiAzMountTargets(w,{slug:i,environment:s,subnetIds:c,securityGroupId:k.Ref(I)});for(let x=0;x<N.length;x++)C[D[x]]=N[x];return{resources:C,outputs:{fileSystemId:w,securityGroupId:I,mountTargetIds:D}}}}class m{static verifyDomain(n){let{domain:i,slug:s,environment:o,enableDkim:c=!0,dkimKeyLength:l="RSA_2048_BIT"}=n,u=r({slug:s,environment:o,resourceType:"ses-identity"}),h=t(`${u}-${i.replace(/\./g,"")}`),y={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:i,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(c)y.Properties.DkimSigningAttributes={NextSigningKeyLength:l};return{emailIdentity:y,logicalId:h}}static createDkimRecords(n,i,s){let o=[];for(let c=0;c<i.length;c++){let l=i[c],u=t(`dkim-${n.replace(/\./g,"")}-${c+1}`),h={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:s,Name:`${l}._domainkey.${n}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${l}.dkim.amazonses.com`]}};o.push({record:h,logicalId:u})}return o}static createConfigurationSet(n){let{slug:i,environment:s,name:o,reputationMetrics:c=!0,sendingEnabled:l=!0,suppressBounces:u=!0,suppressComplaints:h=!0}=n,y=o||r({slug:i,environment:s,resourceType:"ses-config"}),f=t(y),b=[];if(u)b.push("BOUNCE");if(h)b.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:y,ReputationOptions:{ReputationMetricsEnabled:c},SendingOptions:{SendingEnabled:l},SuppressionOptions:{SuppressedReasons:b}}},logicalId:f}}static createReceiptRuleSet(n){let{slug:i,environment:s,name:o}=n,c=o||r({slug:i,environment:s,resourceType:"ses-ruleset"}),l=t(c);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:c}},logicalId:l}}static createReceiptRule(n,i){let{slug:s,environment:o,ruleSetName:c,recipients:l,enabled:u=!0,scanEnabled:h=!0,tlsPolicy:y="Require",s3Action:f,lambdaAction:b,snsAction:C}=i,T=r({slug:s,environment:o,resourceType:"ses-rule"}),w=t(T),E=[];if(f)E.push({S3Action:{BucketName:f.bucketName,ObjectKeyPrefix:f.prefix,KmsKeyArn:f.kmsKeyArn}});if(b)E.push({LambdaAction:{FunctionArn:b.functionArn,InvocationType:b.invocationType||"Event"}});if(C)E.push({SNSAction:{TopicArn:C.topicArn,Encoding:C.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:c,Rule:{Name:T,Enabled:u,ScanEnabled:h,TlsPolicy:y,Recipients:l,Actions:E.length>0?E:void 0}}},logicalId:w}}static createMxRecord(n,i,s){let o=t(`mx-${n.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:n,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${s}.amazonaws.com`]}},logicalId:o}}static createVerificationRecord(n,i,s){let o=t(`verification-${n.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:s,Name:`_amazonses.${n}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${i}"`]}},logicalId:o}}static getSmtpEndpoint(n){return`email-smtp.${n}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(n,i,s){let{includeDomains:o=[],softFail:c=!1}=s||{},l=t(`spf-${n.replace(/\./g,"")}`),u="v=spf1 include:amazonses.com";for(let h of o)u+=` include:${h}`;return u+=c?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:n,Type:"TXT",TTL:300,ResourceRecords:[`"${u}"`]}},logicalId:l}}static createDmarcRecord(n,i,s){let{policy:o="none",subdomainPolicy:c,percentage:l=100,reportingEmail:u,forensicEmail:h}=s||{},y=t(`dmarc-${n.replace(/\./g,"")}`),f=`v=DMARC1; p=${o}; pct=${l}`;if(c)f+=`; sp=${c}`;if(u)f+=`; rua=mailto:${u}`;if(h)f+=`; ruf=mailto:${h}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:`_dmarc.${n}`,Type:"TXT",TTL:300,ResourceRecords:[`"${f}"`]}},logicalId:y}}static createInboundEmailSetup(n){let{slug:i,environment:s,domain:o,s3BucketName:c,s3KeyPrefix:l="inbound/",region:u,hostedZoneId:h,lambdaFunctionArn:y,snsTopicArn:f}=n,b={},{ruleSet:C,logicalId:T}=m.createReceiptRuleSet({slug:i,environment:s});b[T]=C;let{receiptRule:w,logicalId:E}=m.createReceiptRule(T,{slug:i,environment:s,ruleSetName:C.Properties.RuleSetName||`${i}-${s}-receipt-rule-set`,recipients:[o],s3Action:{bucketName:c,prefix:l},lambdaAction:y?{functionArn:y,invocationType:"Event"}:void 0,snsAction:f?{topicArn:f}:void 0});b[E]=w;let{record:I,logicalId:N}=m.createMxRecord(o,h,u);return b[N]=I,{resources:b,outputs:{ruleSetLogicalId:T,ruleLogicalId:E,mxRecordLogicalId:N}}}static createCompleteDomainSetup(n){let{slug:i,environment:s,domain:o,hostedZoneId:c,region:l,enableInbound:u=!1,inboundS3Bucket:h,dmarcReportingEmail:y}=n,f={},{emailIdentity:b,logicalId:C}=m.verifyDomain({domain:o,slug:i,environment:s});f[C]=b;let{configurationSet:T,logicalId:w}=m.createConfigurationSet({slug:i,environment:s});f[w]=T;let{record:E,logicalId:I}=m.createSpfRecord(o,c);f[I]=E;let{record:N,logicalId:D}=m.createDmarcRecord(o,c,{policy:"none",reportingEmail:y||`dmarc-reports@${o}`});if(f[D]=N,u&&h){let x=m.createInboundEmailSetup({slug:i,environment:s,domain:o,s3BucketName:h,region:l,hostedZoneId:c});Object.assign(f,x.resources)}return{resources:f,outputs:{identityLogicalId:C,configSetLogicalId:w}}}static InboundSmtpEndpoints={"us-east-1":"inbound-smtp.us-east-1.amazonaws.com","us-west-2":"inbound-smtp.us-west-2.amazonaws.com","eu-west-1":"inbound-smtp.eu-west-1.amazonaws.com"};static supportsInboundEmail(n){return n in m.InboundSmtpEndpoints}static createEmailLambdaRole(n){let{slug:i,environment:s,s3BucketArn:o,sesIdentityArn:c}=n,l=r({slug:i,environment:s,resourceType:"email-lambda-role"}),u=t(l),h=t(`${l}-policy`),y={Type:"AWS::IAM::Role",Properties:{RoleName:l,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"],Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:s}]}},f=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[o,`${o}/*`]}];if(c)f.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:c});let b={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${l}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:f},Roles:[k.Ref(u)]}};return{role:y,policy:b,roleLogicalId:u,policyLogicalId:h}}static createOutboundEmailLambda(n){let{slug:i,environment:s,roleArn:o,domain:c,configurationSetName:l,timeout:u=30,memorySize:h=256}=n,y=r({slug:i,environment:s,resourceType:"outbound-email"}),f=t(y);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:u,MemorySize:h,Environment:{Variables:{DOMAIN:c,CONFIGURATION_SET:l||""}},Code:{ZipFile:m.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:f}}static createInboundEmailLambda(n){let{slug:i,environment:s,roleArn:o,s3BucketName:c,organizedPrefix:l="organized/",timeout:u=60,memorySize:h=512}=n,y=r({slug:i,environment:s,resourceType:"inbound-email"}),f=t(y),b=t(`${y}-permission`),C={Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:u,MemorySize:h,Environment:{Variables:{S3_BUCKET:c,ORGANIZED_PREFIX:l}},Code:{ZipFile:m.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"InboundEmail"}]}},T={Type:"AWS::Lambda::Permission",Properties:{FunctionName:k.Ref(f),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:k.Ref("AWS::AccountId")}};return{function:C,permission:T,logicalId:f,permissionLogicalId:b}}static createEmailConversionLambda(n){let{slug:i,environment:s,roleArn:o,s3BucketName:c,convertedPrefix:l="converted/",timeout:u=60,memorySize:h=512}=n,y=r({slug:i,environment:s,resourceType:"email-conversion"}),f=t(y);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:u,MemorySize:h,Environment:{Variables:{S3_BUCKET:c,CONVERTED_PREFIX:l}},Code:{ZipFile:m.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:f}}static createEmailBucketNotification(n){let{lambdaArn:i,prefix:s="inbound/",suffix:o,events:c}=n,l=c??["s3:ObjectCreated:*"],u={};if(s||o){if(u.S3Key={Rules:[]},s)u.S3Key.Rules.push({Name:"prefix",Value:s});if(o)u.S3Key.Rules.push({Name:"suffix",Value:o})}return{notificationConfiguration:{LambdaConfigurations:[{Event:l[0],Function:i,Filter:Object.keys(u).length>0?u:void 0}]}}}static createS3LambdaPermission(n){let{slug:i,environment:s,lambdaLogicalId:o,s3BucketArn:c}=n,l=r({slug:i,environment:s,resourceType:"s3-lambda-permission"}),u=t(l);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:k.Ref(o),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:c}},logicalId:u}}static createEmailProcessingStack(n){let{slug:i,environment:s,domain:o,s3BucketName:c,s3BucketArn:l,configurationSetName:u,enableInbound:h=!0,enableConversion:y=!0}=n,f={},{role:b,policy:C,roleLogicalId:T,policyLogicalId:w}=m.createEmailLambdaRole({slug:i,environment:s,s3BucketArn:l,sesIdentityArn:`arn:aws:ses:*:*:identity/${o}`});f[T]=b,f[w]=C;let{function:E,logicalId:I}=m.createOutboundEmailLambda({slug:i,environment:s,roleArn:k.GetAtt(T,"Arn"),domain:o,configurationSetName:u});f[I]=E;let N={roleLogicalId:T,outboundLambdaLogicalId:I};if(h){let{function:D,permission:x,logicalId:R,permissionLogicalId:_}=m.createInboundEmailLambda({slug:i,environment:s,roleArn:k.GetAtt(T,"Arn"),s3BucketName:c});f[R]=D,f[_]=x;let{permission:B,logicalId:W}=m.createS3LambdaPermission({slug:i,environment:s,lambdaLogicalId:R,s3BucketArn:l});f[W]=B,N.inboundLambdaLogicalId=R}if(y){let{function:D,logicalId:x}=m.createEmailConversionLambda({slug:i,environment:s,roleArn:k.GetAtt(T,"Arn"),s3BucketName:c});f[x]=D,N.conversionLambdaLogicalId=x}return{resources:f,outputs:N}}static LambdaCode={outboundEmail:`
623
+ `}class ze{static createFileSystem(n){let{slug:i,environment:s,encrypted:o=!0,kmsKeyId:c,performanceMode:l="generalPurpose",throughputMode:u="bursting",provisionedThroughput:h,enableBackup:y=!0}=n,f=r({slug:i,environment:s,resourceType:"efs"}),S=t(f),b={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:o,PerformanceMode:l,ThroughputMode:u,FileSystemTags:[{Key:"Name",Value:f},{Key:"Environment",Value:s}]}};if(c)b.Properties.KmsKeyId=c;if(u==="provisioned"&&h)b.Properties.ProvisionedThroughputInMibps=h;if(y)b.Properties.BackupPolicy={Status:"ENABLED"};return{fileSystem:b,logicalId:S}}static createMountTarget(n,i){let{slug:s,environment:o,subnetId:c,securityGroups:l,ipAddress:u}=i,h=r({slug:s,environment:o,resourceType:"efs-mt"}),y=t(`${h}-${c}`),f={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:k.Ref(n),SubnetId:c,SecurityGroups:l}};if(u)f.Properties.IpAddress=u;return{mountTarget:f,logicalId:y}}static createAccessPoint(n,i){let{slug:s,environment:o,path:c="/",uid:l="1000",gid:u="1000",permissions:h="755"}=i,y=r({slug:s,environment:o,resourceType:"efs-ap"}),f=t(`${y}-${c.replace(/\//g,"-")}`);return{accessPoint:{Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:k.Ref(n),PosixUser:{Uid:l,Gid:u},RootDirectory:{Path:c,CreationInfo:{OwnerUid:l,OwnerGid:u,Permissions:h}},AccessPointTags:[{Key:"Name",Value:`${y}-${c}`},{Key:"Environment",Value:o}]}},logicalId:f}}static setLifecyclePolicy(n,i){let{transitionToIA:s,transitionToPrimary:o=!1}=i;if(!n.Properties)n.Properties={};if(n.Properties.LifecyclePolicies=[],s){let c=`AFTER_${s}_DAYS`;n.Properties.LifecyclePolicies.push({TransitionToIA:c})}if(o)n.Properties.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"});return n}static enableBackup(n){if(!n.Properties)n.Properties={};return n.Properties.BackupPolicy={Status:"ENABLED"},n}static disableBackup(n){if(!n.Properties)n.Properties={};return n.Properties.BackupPolicy={Status:"DISABLED"},n}static setProvisionedThroughput(n,i){if(!n.Properties)n.Properties={};return n.Properties.ThroughputMode="provisioned",n.Properties.ProvisionedThroughputInMibps=i,n}static setElasticThroughput(n){if(!n.Properties)n.Properties={};return n.Properties.ThroughputMode="elastic",n}static enableMaxIO(n){if(!n.Properties)n.Properties={};return n.Properties.PerformanceMode="maxIO",n}static createEfsSecurityGroup(n){let{slug:i,environment:s,vpcId:o,sourceSecurityGroupIds:c=[],sourceCidrBlocks:l=[],description:u}=n,h=r({slug:i,environment:s,resourceType:"efs-sg"}),y=t(h),f=[];for(let S of c)f.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:S,Description:"NFS from security group"});for(let S of l)f.push({IpProtocol:"tcp",FromPort:2049,ToPort:2049,CidrIp:S,Description:"NFS from CIDR block"});return{securityGroup:{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:h,GroupDescription:u||`Security group for EFS mount targets - ${i} ${s}`,VpcId:o,SecurityGroupIngress:f,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}},logicalId:y}}static createMultiAzMountTargets(n,i){let{slug:s,environment:o,subnetIds:c,securityGroupId:l}=i,u=[],h=[];for(let y=0;y<c.length;y++){let f=c[y],S=r({slug:s,environment:o,resourceType:"efs-mt"}),b=t(`${S}-az${y+1}`),v={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:k.Ref(n),SubnetId:f,SecurityGroups:[l]}};u.push(v),h.push(b)}return{mountTargets:u,logicalIds:h}}static createCompleteFileSystem(n){let{slug:i,environment:s,vpcId:o,subnetIds:c,sourceSecurityGroupIds:l=[],encrypted:u=!0,performanceMode:h="generalPurpose",throughputMode:y="elastic",enableBackup:f=!0,transitionToIA:S}=n,b={},{fileSystem:v,logicalId:w}=ze.createFileSystem({slug:i,environment:s,encrypted:u,performanceMode:h,throughputMode:y,enableBackup:f});if(S)ze.setLifecyclePolicy(v,{transitionToIA:S,transitionToPrimary:!0});b[w]=v;let{securityGroup:E,logicalId:P}=ze.createEfsSecurityGroup({slug:i,environment:s,vpcId:o,sourceSecurityGroupIds:l});b[P]=E;let{mountTargets:R,logicalIds:D}=ze.createMultiAzMountTargets(w,{slug:i,environment:s,subnetIds:c,securityGroupId:k.Ref(P)});for(let x=0;x<R.length;x++)b[D[x]]=R[x];return{resources:b,outputs:{fileSystemId:w,securityGroupId:P,mountTargetIds:D}}}}class m{static verifyDomain(n){let{domain:i,slug:s,environment:o,enableDkim:c=!0,dkimKeyLength:l="RSA_2048_BIT"}=n,u=r({slug:s,environment:o,resourceType:"ses-identity"}),h=t(`${u}-${i.replace(/\./g,"")}`),y={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:i,FeedbackAttributes:{EmailForwardingEnabled:!0}}};if(c)y.Properties.DkimSigningAttributes={NextSigningKeyLength:l};return{emailIdentity:y,logicalId:h}}static createDkimRecords(n,i,s){let o=[];for(let c=0;c<i.length;c++){let l=i[c],u=t(`dkim-${n.replace(/\./g,"")}-${c+1}`),h={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:s,Name:`${l}._domainkey.${n}`,Type:"CNAME",TTL:1800,ResourceRecords:[`${l}.dkim.amazonses.com`]}};o.push({record:h,logicalId:u})}return o}static createConfigurationSet(n){let{slug:i,environment:s,name:o,reputationMetrics:c=!0,sendingEnabled:l=!0,suppressBounces:u=!0,suppressComplaints:h=!0}=n,y=o||r({slug:i,environment:s,resourceType:"ses-config"}),f=t(y),S=[];if(u)S.push("BOUNCE");if(h)S.push("COMPLAINT");return{configurationSet:{Type:"AWS::SES::ConfigurationSet",Properties:{Name:y,ReputationOptions:{ReputationMetricsEnabled:c},SendingOptions:{SendingEnabled:l},SuppressionOptions:{SuppressedReasons:S}}},logicalId:f}}static createReceiptRuleSet(n){let{slug:i,environment:s,name:o}=n,c=o||r({slug:i,environment:s,resourceType:"ses-ruleset"}),l=t(c);return{ruleSet:{Type:"AWS::SES::ReceiptRuleSet",Properties:{RuleSetName:c}},logicalId:l}}static createReceiptRule(n,i){let{slug:s,environment:o,ruleSetName:c,recipients:l,enabled:u=!0,scanEnabled:h=!0,tlsPolicy:y="Require",s3Action:f,lambdaAction:S,snsAction:b}=i,v=r({slug:s,environment:o,resourceType:"ses-rule"}),w=t(v),E=[];if(f)E.push({S3Action:{BucketName:f.bucketName,ObjectKeyPrefix:f.prefix,KmsKeyArn:f.kmsKeyArn}});if(S)E.push({LambdaAction:{FunctionArn:S.functionArn,InvocationType:S.invocationType||"Event"}});if(b)E.push({SNSAction:{TopicArn:b.topicArn,Encoding:b.encoding||"UTF-8"}});return{receiptRule:{Type:"AWS::SES::ReceiptRule",Properties:{RuleSetName:c,Rule:{Name:v,Enabled:u,ScanEnabled:h,TlsPolicy:y,Recipients:l,Actions:E.length>0?E:void 0}}},logicalId:w}}static createMxRecord(n,i,s){let o=t(`mx-${n.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:n,Type:"MX",TTL:300,ResourceRecords:[`10 inbound-smtp.${s}.amazonaws.com`]}},logicalId:o}}static createVerificationRecord(n,i,s){let o=t(`verification-${n.replace(/\./g,"")}`);return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:s,Name:`_amazonses.${n}`,Type:"TXT",TTL:1800,ResourceRecords:[`"${i}"`]}},logicalId:o}}static getSmtpEndpoint(n){return`email-smtp.${n}.amazonaws.com`}static SmtpPorts={TLS:587,SSL:465,Unencrypted:25};static createSpfRecord(n,i,s){let{includeDomains:o=[],softFail:c=!1}=s||{},l=t(`spf-${n.replace(/\./g,"")}`),u="v=spf1 include:amazonses.com";for(let h of o)u+=` include:${h}`;return u+=c?" ~all":" -all",{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:n,Type:"TXT",TTL:300,ResourceRecords:[`"${u}"`]}},logicalId:l}}static createDmarcRecord(n,i,s){let{policy:o="none",subdomainPolicy:c,percentage:l=100,reportingEmail:u,forensicEmail:h}=s||{},y=t(`dmarc-${n.replace(/\./g,"")}`),f=`v=DMARC1; p=${o}; pct=${l}`;if(c)f+=`; sp=${c}`;if(u)f+=`; rua=mailto:${u}`;if(h)f+=`; ruf=mailto:${h}`;return{record:{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i,Name:`_dmarc.${n}`,Type:"TXT",TTL:300,ResourceRecords:[`"${f}"`]}},logicalId:y}}static createInboundEmailSetup(n){let{slug:i,environment:s,domain:o,s3BucketName:c,s3KeyPrefix:l="inbound/",region:u,hostedZoneId:h,lambdaFunctionArn:y,snsTopicArn:f}=n,S={},{ruleSet:b,logicalId:v}=m.createReceiptRuleSet({slug:i,environment:s});S[v]=b;let{receiptRule:w,logicalId:E}=m.createReceiptRule(v,{slug:i,environment:s,ruleSetName:b.Properties.RuleSetName||`${i}-${s}-receipt-rule-set`,recipients:[o],s3Action:{bucketName:c,prefix:l},lambdaAction:y?{functionArn:y,invocationType:"Event"}:void 0,snsAction:f?{topicArn:f}:void 0});S[E]=w;let{record:P,logicalId:R}=m.createMxRecord(o,h,u);return S[R]=P,{resources:S,outputs:{ruleSetLogicalId:v,ruleLogicalId:E,mxRecordLogicalId:R}}}static createCompleteDomainSetup(n){let{slug:i,environment:s,domain:o,hostedZoneId:c,region:l,enableInbound:u=!1,inboundS3Bucket:h,dmarcReportingEmail:y}=n,f={},{emailIdentity:S,logicalId:b}=m.verifyDomain({domain:o,slug:i,environment:s});f[b]=S;let{configurationSet:v,logicalId:w}=m.createConfigurationSet({slug:i,environment:s});f[w]=v;let{record:E,logicalId:P}=m.createSpfRecord(o,c);f[P]=E;let{record:R,logicalId:D}=m.createDmarcRecord(o,c,{policy:"none",reportingEmail:y||`dmarc-reports@${o}`});if(f[D]=R,u&&h){let x=m.createInboundEmailSetup({slug:i,environment:s,domain:o,s3BucketName:h,region:l,hostedZoneId:c});Object.assign(f,x.resources)}return{resources:f,outputs:{identityLogicalId:b,configSetLogicalId:w}}}static InboundSmtpEndpoints={"us-east-1":"inbound-smtp.us-east-1.amazonaws.com","us-west-2":"inbound-smtp.us-west-2.amazonaws.com","eu-west-1":"inbound-smtp.eu-west-1.amazonaws.com"};static supportsInboundEmail(n){return n in m.InboundSmtpEndpoints}static createEmailLambdaRole(n){let{slug:i,environment:s,s3BucketArn:o,sesIdentityArn:c}=n,l=r({slug:i,environment:s,resourceType:"email-lambda-role"}),u=t(l),h=t(`${l}-policy`),y={Type:"AWS::IAM::Role",Properties:{RoleName:l,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"],Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:s}]}},f=[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[o,`${o}/*`]}];if(c)f.push({Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:c});let S={Type:"AWS::IAM::Policy",Properties:{PolicyName:`${l}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:f},Roles:[k.Ref(u)]}};return{role:y,policy:S,roleLogicalId:u,policyLogicalId:h}}static createOutboundEmailLambda(n){let{slug:i,environment:s,roleArn:o,domain:c,configurationSetName:l,timeout:u=30,memorySize:h=256}=n,y=r({slug:i,environment:s,resourceType:"outbound-email"}),f=t(y);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:u,MemorySize:h,Environment:{Variables:{DOMAIN:c,CONFIGURATION_SET:l||""}},Code:{ZipFile:m.LambdaCode.outboundEmail},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"OutboundEmail"}]}},logicalId:f}}static createInboundEmailLambda(n){let{slug:i,environment:s,roleArn:o,s3BucketName:c,organizedPrefix:l="organized/",timeout:u=60,memorySize:h=512}=n,y=r({slug:i,environment:s,resourceType:"inbound-email"}),f=t(y),S=t(`${y}-permission`),b={Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:u,MemorySize:h,Environment:{Variables:{S3_BUCKET:c,ORGANIZED_PREFIX:l}},Code:{ZipFile:m.LambdaCode.inboundEmail},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"InboundEmail"}]}},v={Type:"AWS::Lambda::Permission",Properties:{FunctionName:k.Ref(f),Action:"lambda:InvokeFunction",Principal:"ses.amazonaws.com",SourceAccount:k.Ref("AWS::AccountId")}};return{function:b,permission:v,logicalId:f,permissionLogicalId:S}}static createEmailConversionLambda(n){let{slug:i,environment:s,roleArn:o,s3BucketName:c,convertedPrefix:l="converted/",timeout:u=60,memorySize:h=512}=n,y=r({slug:i,environment:s,resourceType:"email-conversion"}),f=t(y);return{function:{Type:"AWS::Lambda::Function",Properties:{FunctionName:y,Runtime:"nodejs20.x",Handler:"index.handler",Role:o,Timeout:u,MemorySize:h,Environment:{Variables:{S3_BUCKET:c,CONVERTED_PREFIX:l}},Code:{ZipFile:m.LambdaCode.emailConversion},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},{Key:"Purpose",Value:"EmailConversion"}]}},logicalId:f}}static createEmailBucketNotification(n){let{lambdaArn:i,prefix:s="inbound/",suffix:o,events:c}=n,l=c??["s3:ObjectCreated:*"],u={};if(s||o){if(u.S3Key={Rules:[]},s)u.S3Key.Rules.push({Name:"prefix",Value:s});if(o)u.S3Key.Rules.push({Name:"suffix",Value:o})}return{notificationConfiguration:{LambdaConfigurations:[{Event:l[0],Function:i,Filter:Object.keys(u).length>0?u:void 0}]}}}static createS3LambdaPermission(n){let{slug:i,environment:s,lambdaLogicalId:o,s3BucketArn:c}=n,l=r({slug:i,environment:s,resourceType:"s3-lambda-permission"}),u=t(l);return{permission:{Type:"AWS::Lambda::Permission",Properties:{FunctionName:k.Ref(o),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:c}},logicalId:u}}static createEmailProcessingStack(n){let{slug:i,environment:s,domain:o,s3BucketName:c,s3BucketArn:l,configurationSetName:u,enableInbound:h=!0,enableConversion:y=!0}=n,f={},{role:S,policy:b,roleLogicalId:v,policyLogicalId:w}=m.createEmailLambdaRole({slug:i,environment:s,s3BucketArn:l,sesIdentityArn:`arn:aws:ses:*:*:identity/${o}`});f[v]=S,f[w]=b;let{function:E,logicalId:P}=m.createOutboundEmailLambda({slug:i,environment:s,roleArn:k.GetAtt(v,"Arn"),domain:o,configurationSetName:u});f[P]=E;let R={roleLogicalId:v,outboundLambdaLogicalId:P};if(h){let{function:D,permission:x,logicalId:I,permissionLogicalId:_}=m.createInboundEmailLambda({slug:i,environment:s,roleArn:k.GetAtt(v,"Arn"),s3BucketName:c});f[I]=D,f[_]=x;let{permission:B,logicalId:W}=m.createS3LambdaPermission({slug:i,environment:s,lambdaLogicalId:I,s3BucketArn:l});f[W]=B,R.inboundLambdaLogicalId=I}if(y){let{function:D,logicalId:x}=m.createEmailConversionLambda({slug:i,environment:s,roleArn:k.GetAtt(v,"Arn"),s3BucketName:c});f[x]=D,R.conversionLambdaLogicalId=x}return{resources:f,outputs:R}}static LambdaCode={outboundEmail:`
624
624
  const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
625
625
  const ses = new SESClient({});
626
626
 
@@ -1658,7 +1658,7 @@ catch (error) {
1658
1658
 
1659
1659
  return { statusCode: 200, body: 'OK' };
1660
1660
  };
1661
- `;class Ke{static LambdaCode={incomingCall:Da,voicemail:Ar,missedCall:br};static createConnectInstance(n){let{slug:i,environment:s,instanceAlias:o,inboundCallsEnabled:c=!0,outboundCallsEnabled:l=!0}=n;return{[`${i}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:o,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:c,OutboundCalls:l,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(n){return{[`${n.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:n.instanceArn,Name:n.name,TimeZone:n.timezone,Config:n.schedule.map((i)=>({Day:i.day,StartTime:{Hours:i.startHour,Minutes:i.startMinute},EndTime:{Hours:i.endHour,Minutes:i.endMinute}}))}}}}static createQueue(n){return{[`${n.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:n.instanceArn,Name:n.name,HoursOfOperationArn:n.hoursOfOperationArn,MaxContacts:n.maxContacts||10}}}}static createContactFlow(n){return{[`${n.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:n.instanceArn,Name:n.name,Type:n.type,Content:n.content}}}}static createBasicIvrFlow(n){let i={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:n.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:n.queueArn},Transitions:{NextAction:n.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...n.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:n.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(i)}static createPhoneLambdaRole(n){return{[`${n.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${n.slug}-phone-lambda-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:"PhoneLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"}]}}]}}}}static createIncomingCallLambda(n){return{[`${n.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Ke.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createVoicemailLambda(n){return{[`${n.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:Ke.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:n.voicemailBucket,NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",TRANSCRIPTION_ENABLED:n.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(n){return{[`${n.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Ke.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createCallLogTable(n){return{[`${n.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(n){let i={},s={};Object.assign(i,Ke.createPhoneLambdaRole({slug:n.slug})),Object.assign(i,Ke.createCallLogTable({slug:n.slug})),i[`${n.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${n.slug}-phone-notifications`}},i[`${n.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${n.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let o={"Fn::GetAtt":[`${n.slug}PhoneLambdaRole`,"Arn"]},c={Ref:`${n.slug}PhoneNotificationTopic`},l={Ref:`${n.slug}CallLogTable`},u={Ref:`${n.slug}VoicemailBucket`};if(Object.assign(i,Ke.createIncomingCallLambda({slug:n.slug,roleArn:o,notificationTopicArn:c,callLogTable:l,webhookUrl:n.webhookUrl})),n.voicemailEnabled!==!1)Object.assign(i,Ke.createVoicemailLambda({slug:n.slug,roleArn:o,voicemailBucket:u,notificationTopicArn:c,callLogTable:l,transcriptionEnabled:n.transcriptionEnabled}));return Object.assign(i,Ke.createMissedCallLambda({slug:n.slug,roleArn:o,notificationTopicArn:c,callLogTable:l,webhookUrl:n.webhookUrl})),s[`${n.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${n.slug}PhoneNotificationTopic`}},s[`${n.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${n.slug}CallLogTable`}},s[`${n.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${n.slug}VoicemailBucket`}},{resources:i,outputs:s}}}class U{static createQueue(n){let{slug:i,environment:s,name:o,delaySeconds:c=0,visibilityTimeout:l=30,messageRetentionPeriod:u=345600,maxMessageSize:h=262144,receiveMessageWaitTime:y=0,fifo:f=!1,contentBasedDeduplication:b=!1,encrypted:C=!0,kmsKeyId:T}=n,w=o||r({slug:i,environment:s,resourceType:"queue"}),E=f?`${w}.fifo`:w,I=t(w),N={Type:"AWS::SQS::Queue",Properties:{QueueName:E,DelaySeconds:c,MaximumMessageSize:h,MessageRetentionPeriod:u,ReceiveMessageWaitTimeSeconds:y,VisibilityTimeout:l,Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:s}]}};if(f)N.Properties.FifoQueue=!0,N.Properties.ContentBasedDeduplication=b;if(C)if(T)N.Properties.KmsMasterKeyId=T;else N.Properties.SqsManagedSseEnabled=!0;return{queue:N,logicalId:I}}static createDeadLetterQueue(n,i){let{slug:s,environment:o,maxReceiveCount:c=3}=i,l=r({slug:s,environment:o,resourceType:"dlq"}),u=t(l),h={Type:"AWS::SQS::Queue",Properties:{QueueName:l,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:o},{Key:"Type",Value:"DeadLetterQueue"}]}},y={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:k.GetAtt(u,"Arn"),maxReceiveCount:c}}};return{deadLetterQueue:h,updatedSourceQueue:y,deadLetterLogicalId:u}}static createSchedule(n,i){let{slug:s,environment:o,name:c,description:l,enabled:u=!0}=i,h=c||r({slug:s,environment:o,resourceType:"schedule"}),y=t(h);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:h,Description:l,ScheduleExpression:n,State:u?"ENABLED":"DISABLED",Targets:[]}},logicalId:y}}static scheduleEcsTask(n,i,s){let{slug:o,environment:c,name:l,description:u,enabled:h=!0,taskDefinitionArn:y,clusterArn:f,subnets:b,securityGroups:C=[],assignPublicIp:T=!1,taskCount:w=1,containerOverrides:E}=s,I=l||r({slug:o,environment:c,resourceType:"ecs-schedule"}),N=t(I),D={Id:"1",Arn:f,RoleArn:i,EcsParameters:{TaskDefinitionArn:y,TaskCount:w,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:b,SecurityGroups:C,AssignPublicIp:T?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(E&&E.length>0)D.Input=JSON.stringify({containerOverrides:E});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:I,Description:u||`Scheduled ECS task: ${y}`,ScheduleExpression:n,State:h?"ENABLED":"DISABLED",Targets:[D]}},logicalId:N}}static scheduleLambda(n,i){let{slug:s,environment:o,name:c,description:l,enabled:u=!0,functionArn:h,input:y}=i,f=c||r({slug:s,environment:o,resourceType:"lambda-schedule"}),b=t(f),C={Id:"1",Arn:h};if(y)C.Input=JSON.stringify(y);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:f,Description:l||`Scheduled Lambda: ${h}`,ScheduleExpression:n,State:u?"ENABLED":"DISABLED",Targets:[C]}},logicalId:b}}static scheduleSqsMessage(n,i){let{slug:s,environment:o,name:c,description:l,enabled:u=!0,queueArn:h,messageGroupId:y}=i,f=c||r({slug:s,environment:o,resourceType:"sqs-schedule"}),b=t(f),C={Id:"1",Arn:h};if(y)C.SqsParameters={MessageGroupId:y};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:f,Description:l||`Scheduled SQS message: ${h}`,ScheduleExpression:n,State:u?"ENABLED":"DISABLED",Targets:[C]}},logicalId:b}}static addTarget(n,i){if(!n.Properties.Targets)n.Properties.Targets=[];let s={Id:i.id,Arn:i.arn};if(i.roleArn)s.RoleArn=i.roleArn;if(i.input)s.Input=JSON.stringify(i.input);return n.Properties.Targets.push(s),n}static toCronExpression(n){if(n.startsWith("cron(")||n.startsWith("rate("))return n;return`cron(${n})`}static rateExpression(n,i){return`rate(${n} ${i})`}static CronExpressions={EveryMinute:"cron(* * * * ? *)",Every5Minutes:"cron(*/5 * * * ? *)",Every15Minutes:"cron(*/15 * * * ? *)",Every30Minutes:"cron(*/30 * * * ? *)",Hourly:"cron(0 * * * ? *)",Daily:"cron(0 0 * * ? *)",DailyAt9AM:"cron(0 9 * * ? *)",DailyAtMidnight:"cron(0 0 * * ? *)",Weekly:"cron(0 0 ? * SUN *)",Monthly:"cron(0 0 1 * ? *)"};static RateExpressions={Every1Minute:"rate(1 minute)",Every5Minutes:"rate(5 minutes)",Every10Minutes:"rate(10 minutes)",Every15Minutes:"rate(15 minutes)",Every30Minutes:"rate(30 minutes)",Every1Hour:"rate(1 hour)",Every6Hours:"rate(6 hours)",Every12Hours:"rate(12 hours)",Every1Day:"rate(1 day)"};static rateStringToExpression(n){let i=n.toLowerCase().trim(),s=i.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(s){let f=parseInt(s[1],10),b=s[2].toLowerCase(),C=b.endsWith("s")&&f===1?b.slice(0,-1):b,T=!b.endsWith("s")&&f>1?`${b}s`:b;return`rate(${f} ${f===1?C:T})`}let o=i.match(/^every\s+(minute|hour|day)$/i);if(o)return`rate(1 ${o[1]})`;let c={"every minute":"rate(1 minute)","every hour":"rate(1 hour)","every day":"rate(1 day)",hourly:"cron(0 * * * ? *)",daily:"cron(0 0 * * ? *)","daily at midnight":"cron(0 0 * * ? *)",weekly:"cron(0 0 ? * SUN *)",monthly:"cron(0 0 1 * ? *)",yearly:"cron(0 0 1 1 ? *)"};if(c[i])return c[i];let l=i.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(l){let f=parseInt(l[1],10),b=l[2]?.toLowerCase();if(b==="pm"&&f!==12)f+=12;else if(b==="am"&&f===12)f=0;return`cron(0 ${f} * * ? *)`}let u=i.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(u){let f=parseInt(u[1],10);return`cron(${parseInt(u[2],10)} ${f} * * ? *)`}let h={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},y=i.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(y)return`cron(0 0 ? * ${h[y[1].toLowerCase()]} *)`;return U.toCronExpression(n)}static JobConfig={create:(n)=>{let{name:i,handler:s,retries:o=3,backoff:c="exponential",backoffDelay:l=1000,maxDelay:u=30000,timeout:h=60000,jitter:y=!0}=n;return{name:i,handler:s,retries:o,backoff:c,backoffDelay:l,maxDelay:u,timeout:h,jitter:y}},calculateDelay:(n,i)=>{let{backoff:s,backoffDelay:o,maxDelay:c,jitter:l}=i,u;switch(s){case"linear":u=o*n;break;case"exponential":u=o*2**(n-1);break;case"fixed":default:u=o}if(u=Math.min(u,c||Number.MAX_SAFE_INTEGER),l){let h=u*0.25*Math.random();u+=h}return Math.floor(u)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(n){let{containerName:i,jobClass:s,jobData:o,environment:c={}}=n,l=[{name:"JOB_CLASS",value:s}];if(o)l.push({name:"JOB_DATA",value:JSON.stringify(o)});for(let[u,h]of Object.entries(c))l.push({name:u,value:h});return{name:i,command:["bun","run","app/Jobs/runner.ts"],environment:l}}static createScheduledJob(n){let{slug:i,environment:s,schedule:o,jobClass:c,jobData:l,taskDefinitionArn:u,clusterArn:h,subnets:y,securityGroups:f=[],roleArn:b,containerName:C="app"}=n,T=U.rateStringToExpression(o),w=U.createJobContainerOverride({containerName:C,jobClass:c,jobData:l});return U.scheduleEcsTask(T,b,{slug:i,environment:s,name:`${i}-${c.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${c}`,taskDefinitionArn:u,clusterArn:h,subnets:y,securityGroups:f,containerOverrides:[w]})}static QueuePresets={highThroughput:(n,i)=>U.createQueue({slug:n,environment:i,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(n,i)=>U.createQueue({slug:n,environment:i,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(n,i)=>U.createQueue({slug:n,environment:i,fifo:!0,contentBasedDeduplication:!0}),delayed:(n,i,s=60)=>U.createQueue({slug:n,environment:i,delaySeconds:s})}}class ft{static async discoverJobs(n){let{projectRoot:i,jobsPath:s="app/Jobs"}=n,o=`${i}/${s}`,c=[];try{let l=await import("node:fs"),u=await import("node:path");if(!l.existsSync(o))return[];let h=l.readdirSync(o).filter((y)=>y.endsWith(".ts")&&!y.startsWith("_")&&y!=="runner.ts");for(let y of h){let f=u.join(o,y),b=y.replace(".ts",""),C=l.readFileSync(f,"utf-8"),T=ft.parseJobMetadata(C,b,f);if(T)c.push(T)}}catch{return[]}return c}static parseJobMetadata(n,i,s){let o=n.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/schedule:\s*['"`]([^'"`]+)['"`]/),c=n.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||n.match(/enabled:\s*(true|false)/),l=n.match(/export\s+const\s+retries\s*=\s*(\d+)/)||n.match(/retries:\s*(\d+)/),u=n.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||n.match(/timeout:\s*(\d+)/),h=n.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||n.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),y=n.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(n.includes("export async function handle")||n.includes("export function handle")||n.includes("export default")))return null;return{name:i,path:s,schedule:o?.[1],handler:`${i}.handle`,enabled:c?.[1]!=="false",retries:l?parseInt(l[1],10):void 0,backoff:h?.[1],timeout:u?parseInt(u[1],10):void 0,description:y?.[1]}}static async discoverActions(n){let{projectRoot:i,actionsPath:s="app/Actions"}=n,o=`${i}/${s}`,c=[];try{let l=await import("node:fs"),u=await import("node:path");if(!l.existsSync(o))return[];let h=l.readdirSync(o).filter((y)=>y.endsWith(".ts")&&!y.startsWith("_"));for(let y of h){let f=u.join(o,y),b=y.replace(".ts",""),C=l.readFileSync(f,"utf-8"),T=ft.parseActionMetadata(C,b,f);if(T)c.push(T)}}catch{return[]}return c}static parseActionMetadata(n,i,s){if(!(n.includes("export async function handle")||n.includes("export function handle")||n.includes("export default")))return null;let o=n.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:i,path:s,handler:`${i}.handle`,description:o?.[1]}}static generateScheduledJobResources(n){let{slug:i,environment:s,jobs:o,taskDefinitionArn:c,clusterArn:l,subnets:u,securityGroups:h=[],roleArn:y,containerName:f="app"}=n,b={},C=0;for(let T of o){if(!T.schedule||!T.enabled)continue;let{rule:w,logicalId:E}=U.createScheduledJob({slug:i,environment:s,schedule:T.schedule,jobClass:T.name,taskDefinitionArn:c,clusterArn:l,subnets:u,securityGroups:h,roleArn:y,containerName:f});b[E]=w,C++}return{rules:b,count:C}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
1661
+ `;class Ke{static LambdaCode={incomingCall:Da,voicemail:Ar,missedCall:br};static createConnectInstance(n){let{slug:i,environment:s,instanceAlias:o,inboundCallsEnabled:c=!0,outboundCallsEnabled:l=!0}=n;return{[`${i}ConnectInstance`]:{Type:"AWS::Connect::Instance",Properties:{InstanceAlias:o,IdentityManagementType:"CONNECT_MANAGED",Attributes:{InboundCalls:c,OutboundCalls:l,ContactflowLogs:!0,ContactLens:!0,AutoResolveBestVoices:!0,UseCustomTTSVoices:!1,EarlyMedia:!0}}}}}static createHoursOfOperation(n){return{[`${n.slug}HoursOfOperation`]:{Type:"AWS::Connect::HoursOfOperation",Properties:{InstanceArn:n.instanceArn,Name:n.name,TimeZone:n.timezone,Config:n.schedule.map((i)=>({Day:i.day,StartTime:{Hours:i.startHour,Minutes:i.startMinute},EndTime:{Hours:i.endHour,Minutes:i.endMinute}}))}}}}static createQueue(n){return{[`${n.slug}Queue`]:{Type:"AWS::Connect::Queue",Properties:{InstanceArn:n.instanceArn,Name:n.name,HoursOfOperationArn:n.hoursOfOperationArn,MaxContacts:n.maxContacts||10}}}}static createContactFlow(n){return{[`${n.slug}ContactFlow`]:{Type:"AWS::Connect::ContactFlow",Properties:{InstanceArn:n.instanceArn,Name:n.name,Type:n.type,Content:n.content}}}}static createBasicIvrFlow(n){let i={Version:"2019-10-30",StartAction:"greeting",Actions:[{Identifier:"greeting",Type:"MessageParticipant",Parameters:{Text:n.greeting},Transitions:{NextAction:"transfer_to_queue",Errors:[{NextAction:"disconnect"}]}},{Identifier:"transfer_to_queue",Type:"TransferToQueue",Parameters:{QueueId:n.queueArn},Transitions:{NextAction:n.voicemailLambdaArn?"voicemail":"disconnect",Errors:[{NextAction:"disconnect"}]}},...n.voicemailLambdaArn?[{Identifier:"voicemail",Type:"InvokeLambdaFunction",Parameters:{LambdaFunctionARN:n.voicemailLambdaArn},Transitions:{NextAction:"disconnect",Errors:[{NextAction:"disconnect"}]}}]:[],{Identifier:"disconnect",Type:"DisconnectParticipant",Parameters:{},Transitions:{}}]};return JSON.stringify(i)}static createPhoneLambdaRole(n){return{[`${n.slug}PhoneLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${n.slug}-phone-lambda-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:"PhoneLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"}]}}]}}}}static createIncomingCallLambda(n){return{[`${n.slug}IncomingCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Ke.LambdaCode.incomingCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createVoicemailLambda(n){return{[`${n.slug}VoicemailLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-voicemail`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:300,MemorySize:512,Code:{ZipFile:Ke.LambdaCode.voicemail},Environment:{Variables:{VOICEMAIL_BUCKET:n.voicemailBucket,NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",TRANSCRIPTION_ENABLED:n.transcriptionEnabled?"true":"false"}}}}}}static createMissedCallLambda(n){return{[`${n.slug}MissedCallLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-missed-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Ke.LambdaCode.missedCall},Environment:{Variables:{NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",CALL_LOG_TABLE:n.callLogTable||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createCallLogTable(n){return{[`${n.slug}CallLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createCompleteSetup(n){let i={},s={};Object.assign(i,Ke.createPhoneLambdaRole({slug:n.slug})),Object.assign(i,Ke.createCallLogTable({slug:n.slug})),i[`${n.slug}PhoneNotificationTopic`]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${n.slug}-phone-notifications`}},i[`${n.slug}VoicemailBucket`]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${n.slug}-voicemails`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}};let o={"Fn::GetAtt":[`${n.slug}PhoneLambdaRole`,"Arn"]},c={Ref:`${n.slug}PhoneNotificationTopic`},l={Ref:`${n.slug}CallLogTable`},u={Ref:`${n.slug}VoicemailBucket`};if(Object.assign(i,Ke.createIncomingCallLambda({slug:n.slug,roleArn:o,notificationTopicArn:c,callLogTable:l,webhookUrl:n.webhookUrl})),n.voicemailEnabled!==!1)Object.assign(i,Ke.createVoicemailLambda({slug:n.slug,roleArn:o,voicemailBucket:u,notificationTopicArn:c,callLogTable:l,transcriptionEnabled:n.transcriptionEnabled}));return Object.assign(i,Ke.createMissedCallLambda({slug:n.slug,roleArn:o,notificationTopicArn:c,callLogTable:l,webhookUrl:n.webhookUrl})),s[`${n.slug}PhoneNotificationTopicArn`]={Description:"Phone notification topic ARN",Value:{Ref:`${n.slug}PhoneNotificationTopic`}},s[`${n.slug}CallLogTableName`]={Description:"Call log table name",Value:{Ref:`${n.slug}CallLogTable`}},s[`${n.slug}VoicemailBucketName`]={Description:"Voicemail bucket name",Value:{Ref:`${n.slug}VoicemailBucket`}},{resources:i,outputs:s}}}class U{static createQueue(n){let{slug:i,environment:s,name:o,delaySeconds:c=0,visibilityTimeout:l=30,messageRetentionPeriod:u=345600,maxMessageSize:h=262144,receiveMessageWaitTime:y=0,fifo:f=!1,contentBasedDeduplication:S=!1,encrypted:b=!0,kmsKeyId:v}=n,w=o||r({slug:i,environment:s,resourceType:"queue"}),E=f?`${w}.fifo`:w,P=t(w),R={Type:"AWS::SQS::Queue",Properties:{QueueName:E,DelaySeconds:c,MaximumMessageSize:h,MessageRetentionPeriod:u,ReceiveMessageWaitTimeSeconds:y,VisibilityTimeout:l,Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:s}]}};if(f)R.Properties.FifoQueue=!0,R.Properties.ContentBasedDeduplication=S;if(b)if(v)R.Properties.KmsMasterKeyId=v;else R.Properties.SqsManagedSseEnabled=!0;return{queue:R,logicalId:P}}static createDeadLetterQueue(n,i){let{slug:s,environment:o,maxReceiveCount:c=3}=i,l=r({slug:s,environment:o,resourceType:"dlq"}),u=t(l),h={Type:"AWS::SQS::Queue",Properties:{QueueName:l,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:o},{Key:"Type",Value:"DeadLetterQueue"}]}},y={Type:"AWS::SQS::Queue",Properties:{RedrivePolicy:{deadLetterTargetArn:k.GetAtt(u,"Arn"),maxReceiveCount:c}}};return{deadLetterQueue:h,updatedSourceQueue:y,deadLetterLogicalId:u}}static createSchedule(n,i){let{slug:s,environment:o,name:c,description:l,enabled:u=!0}=i,h=c||r({slug:s,environment:o,resourceType:"schedule"}),y=t(h);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:h,Description:l,ScheduleExpression:n,State:u?"ENABLED":"DISABLED",Targets:[]}},logicalId:y}}static scheduleEcsTask(n,i,s){let{slug:o,environment:c,name:l,description:u,enabled:h=!0,taskDefinitionArn:y,clusterArn:f,subnets:S,securityGroups:b=[],assignPublicIp:v=!1,taskCount:w=1,containerOverrides:E}=s,P=l||r({slug:o,environment:c,resourceType:"ecs-schedule"}),R=t(P),D={Id:"1",Arn:f,RoleArn:i,EcsParameters:{TaskDefinitionArn:y,TaskCount:w,LaunchType:"FARGATE",NetworkConfiguration:{awsvpcConfiguration:{Subnets:S,SecurityGroups:b,AssignPublicIp:v?"ENABLED":"DISABLED"}},PlatformVersion:"LATEST"}};if(E&&E.length>0)D.Input=JSON.stringify({containerOverrides:E});return{rule:{Type:"AWS::Events::Rule",Properties:{Name:P,Description:u||`Scheduled ECS task: ${y}`,ScheduleExpression:n,State:h?"ENABLED":"DISABLED",Targets:[D]}},logicalId:R}}static scheduleLambda(n,i){let{slug:s,environment:o,name:c,description:l,enabled:u=!0,functionArn:h,input:y}=i,f=c||r({slug:s,environment:o,resourceType:"lambda-schedule"}),S=t(f),b={Id:"1",Arn:h};if(y)b.Input=JSON.stringify(y);return{rule:{Type:"AWS::Events::Rule",Properties:{Name:f,Description:l||`Scheduled Lambda: ${h}`,ScheduleExpression:n,State:u?"ENABLED":"DISABLED",Targets:[b]}},logicalId:S}}static scheduleSqsMessage(n,i){let{slug:s,environment:o,name:c,description:l,enabled:u=!0,queueArn:h,messageGroupId:y}=i,f=c||r({slug:s,environment:o,resourceType:"sqs-schedule"}),S=t(f),b={Id:"1",Arn:h};if(y)b.SqsParameters={MessageGroupId:y};return{rule:{Type:"AWS::Events::Rule",Properties:{Name:f,Description:l||`Scheduled SQS message: ${h}`,ScheduleExpression:n,State:u?"ENABLED":"DISABLED",Targets:[b]}},logicalId:S}}static addTarget(n,i){if(!n.Properties.Targets)n.Properties.Targets=[];let s={Id:i.id,Arn:i.arn};if(i.roleArn)s.RoleArn=i.roleArn;if(i.input)s.Input=JSON.stringify(i.input);return n.Properties.Targets.push(s),n}static toCronExpression(n){if(n.startsWith("cron(")||n.startsWith("rate("))return n;return`cron(${n})`}static rateExpression(n,i){return`rate(${n} ${i})`}static CronExpressions={EveryMinute:"cron(* * * * ? *)",Every5Minutes:"cron(*/5 * * * ? *)",Every15Minutes:"cron(*/15 * * * ? *)",Every30Minutes:"cron(*/30 * * * ? *)",Hourly:"cron(0 * * * ? *)",Daily:"cron(0 0 * * ? *)",DailyAt9AM:"cron(0 9 * * ? *)",DailyAtMidnight:"cron(0 0 * * ? *)",Weekly:"cron(0 0 ? * SUN *)",Monthly:"cron(0 0 1 * ? *)"};static RateExpressions={Every1Minute:"rate(1 minute)",Every5Minutes:"rate(5 minutes)",Every10Minutes:"rate(10 minutes)",Every15Minutes:"rate(15 minutes)",Every30Minutes:"rate(30 minutes)",Every1Hour:"rate(1 hour)",Every6Hours:"rate(6 hours)",Every12Hours:"rate(12 hours)",Every1Day:"rate(1 day)"};static rateStringToExpression(n){let i=n.toLowerCase().trim(),s=i.match(/^every\s+(\d+)\s+(minute|minutes|hour|hours|day|days)$/i);if(s){let f=parseInt(s[1],10),S=s[2].toLowerCase(),b=S.endsWith("s")&&f===1?S.slice(0,-1):S,v=!S.endsWith("s")&&f>1?`${S}s`:S;return`rate(${f} ${f===1?b:v})`}let o=i.match(/^every\s+(minute|hour|day)$/i);if(o)return`rate(1 ${o[1]})`;let c={"every minute":"rate(1 minute)","every hour":"rate(1 hour)","every day":"rate(1 day)",hourly:"cron(0 * * * ? *)",daily:"cron(0 0 * * ? *)","daily at midnight":"cron(0 0 * * ? *)",weekly:"cron(0 0 ? * SUN *)",monthly:"cron(0 0 1 * ? *)",yearly:"cron(0 0 1 1 ? *)"};if(c[i])return c[i];let l=i.match(/^daily\s+at\s+(\d{1,2})\s*(am|pm)?$/i);if(l){let f=parseInt(l[1],10),S=l[2]?.toLowerCase();if(S==="pm"&&f!==12)f+=12;else if(S==="am"&&f===12)f=0;return`cron(0 ${f} * * ? *)`}let u=i.match(/^at\s+(\d{1,2}):(\d{2})$/i);if(u){let f=parseInt(u[1],10);return`cron(${parseInt(u[2],10)} ${f} * * ? *)`}let h={monday:"MON",tuesday:"TUE",wednesday:"WED",thursday:"THU",friday:"FRI",saturday:"SAT",sunday:"SUN"},y=i.match(/^every\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)$/i);if(y)return`cron(0 0 ? * ${h[y[1].toLowerCase()]} *)`;return U.toCronExpression(n)}static JobConfig={create:(n)=>{let{name:i,handler:s,retries:o=3,backoff:c="exponential",backoffDelay:l=1000,maxDelay:u=30000,timeout:h=60000,jitter:y=!0}=n;return{name:i,handler:s,retries:o,backoff:c,backoffDelay:l,maxDelay:u,timeout:h,jitter:y}},calculateDelay:(n,i)=>{let{backoff:s,backoffDelay:o,maxDelay:c,jitter:l}=i,u;switch(s){case"linear":u=o*n;break;case"exponential":u=o*2**(n-1);break;case"fixed":default:u=o}if(u=Math.min(u,c||Number.MAX_SAFE_INTEGER),l){let h=u*0.25*Math.random();u+=h}return Math.floor(u)},presets:{fastRetry:{retries:5,backoff:"exponential",backoffDelay:100,maxDelay:5000,jitter:!0},standard:{retries:3,backoff:"exponential",backoffDelay:1000,maxDelay:30000,jitter:!0},longRunning:{retries:2,backoff:"exponential",backoffDelay:5000,maxDelay:60000,timeout:300000,jitter:!0},critical:{retries:10,backoff:"exponential",backoffDelay:500,maxDelay:60000,jitter:!0},noRetry:{retries:0,backoff:"fixed",backoffDelay:0,maxDelay:0,jitter:!1}}};static createJobContainerOverride(n){let{containerName:i,jobClass:s,jobData:o,environment:c={}}=n,l=[{name:"JOB_CLASS",value:s}];if(o)l.push({name:"JOB_DATA",value:JSON.stringify(o)});for(let[u,h]of Object.entries(c))l.push({name:u,value:h});return{name:i,command:["bun","run","app/Jobs/runner.ts"],environment:l}}static createScheduledJob(n){let{slug:i,environment:s,schedule:o,jobClass:c,jobData:l,taskDefinitionArn:u,clusterArn:h,subnets:y,securityGroups:f=[],roleArn:S,containerName:b="app"}=n,v=U.rateStringToExpression(o),w=U.createJobContainerOverride({containerName:b,jobClass:c,jobData:l});return U.scheduleEcsTask(v,S,{slug:i,environment:s,name:`${i}-${c.toLowerCase().replace(/[^a-z0-9]/g,"-")}`,description:`Scheduled job: ${c}`,taskDefinitionArn:u,clusterArn:h,subnets:y,securityGroups:f,containerOverrides:[w]})}static QueuePresets={highThroughput:(n,i)=>U.createQueue({slug:n,environment:i,visibilityTimeout:30,receiveMessageWaitTime:0,delaySeconds:0}),longRunning:(n,i)=>U.createQueue({slug:n,environment:i,visibilityTimeout:300,messageRetentionPeriod:1209600}),fifo:(n,i)=>U.createQueue({slug:n,environment:i,fifo:!0,contentBasedDeduplication:!0}),delayed:(n,i,s=60)=>U.createQueue({slug:n,environment:i,delaySeconds:s})}}class ft{static async discoverJobs(n){let{projectRoot:i,jobsPath:s="app/Jobs"}=n,o=`${i}/${s}`,c=[];try{let l=await import("node:fs"),u=await import("node:path");if(!l.existsSync(o))return[];let h=l.readdirSync(o).filter((y)=>y.endsWith(".ts")&&!y.startsWith("_")&&y!=="runner.ts");for(let y of h){let f=u.join(o,y),S=y.replace(".ts",""),b=l.readFileSync(f,"utf-8"),v=ft.parseJobMetadata(b,S,f);if(v)c.push(v)}}catch{return[]}return c}static parseJobMetadata(n,i,s){let o=n.match(/export\s + const\s + schedule\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/schedule:\s*['"`]([^'"`]+)['"`]/),c=n.match(/export\s+const\s+enabled\s*=\s*(true|false)/)||n.match(/enabled:\s*(true|false)/),l=n.match(/export\s+const\s+retries\s*=\s*(\d+)/)||n.match(/retries:\s*(\d+)/),u=n.match(/export\s+const\s+timeout\s*=\s*(\d+)/)||n.match(/timeout:\s*(\d+)/),h=n.match(/export\s+const\s+backoff\s*=\s*['"`](linear|exponential|fixed)['"`]/)||n.match(/backoff:\s*['"`](linear|exponential|fixed)['"`]/),y=n.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/description:\s*['"`]([^'"`]+)['"`]/);if(!(n.includes("export async function handle")||n.includes("export function handle")||n.includes("export default")))return null;return{name:i,path:s,schedule:o?.[1],handler:`${i}.handle`,enabled:c?.[1]!=="false",retries:l?parseInt(l[1],10):void 0,backoff:h?.[1],timeout:u?parseInt(u[1],10):void 0,description:y?.[1]}}static async discoverActions(n){let{projectRoot:i,actionsPath:s="app/Actions"}=n,o=`${i}/${s}`,c=[];try{let l=await import("node:fs"),u=await import("node:path");if(!l.existsSync(o))return[];let h=l.readdirSync(o).filter((y)=>y.endsWith(".ts")&&!y.startsWith("_"));for(let y of h){let f=u.join(o,y),S=y.replace(".ts",""),b=l.readFileSync(f,"utf-8"),v=ft.parseActionMetadata(b,S,f);if(v)c.push(v)}}catch{return[]}return c}static parseActionMetadata(n,i,s){if(!(n.includes("export async function handle")||n.includes("export function handle")||n.includes("export default")))return null;let o=n.match(/export\s + const\s + description\s*=\s*['"`]([^'"`]+)['"`]/)||n.match(/description:\s*['"`]([^'"`]+)['"`]/);return{name:i,path:s,handler:`${i}.handle`,description:o?.[1]}}static generateScheduledJobResources(n){let{slug:i,environment:s,jobs:o,taskDefinitionArn:c,clusterArn:l,subnets:u,securityGroups:h=[],roleArn:y,containerName:f="app"}=n,S={},b=0;for(let v of o){if(!v.schedule||!v.enabled)continue;let{rule:w,logicalId:E}=U.createScheduledJob({slug:i,environment:s,schedule:v.schedule,jobClass:v.name,taskDefinitionArn:c,clusterArn:l,subnets:u,securityGroups:h,roleArn:y,containerName:f});S[E]=w,b++}return{rules:S,count:b}}static generateJobRunnerScript(){return`#!/usr/bin/env bun
1662
1662
  /**
1663
1663
  * Job Runner Script
1664
1664
  * This script is invoked by ECS scheduled tasks to run jobs
@@ -2306,14 +2306,14 @@ function resolveTemplate(template, data) {
2306
2306
  }
2307
2307
  return result;
2308
2308
  }
2309
- `;class Q{static LambdaCode={send:ka,receive:vr,deliveryStatus:Cr};static createPinpointApp(n){return{[`${n.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:n.name||`${n.slug}-sms`}}}}static createSmsChannel(n){let i={ApplicationId:n.applicationId,Enabled:n.enabled!==!1};if(n.senderId)i.SenderId=n.senderId;if(n.shortCode)i.ShortCode=n.shortCode;return{[`${n.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:i}}}static createSmsLambdaRole(n){return{[`${n.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${n.slug}-sms-lambda-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:"SmsLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetSmsChannel"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem","dynamodb:DeleteItem"],Resource:"*"}]}}]}}}}static createSendLambda(n){return{[`${n.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Q.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:n.pinpointAppId,MESSAGE_LOG_TABLE:n.messageLogTable||"",SMS_SENDER_ID:n.senderId||"",SMS_ORIGINATION_NUMBER:n.originationNumber||""}}}}}}static createReceiveLambda(n){return{[`${n.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Q.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:n.optOutTable||"",MESSAGE_LOG_TABLE:n.messageLogTable||"",NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createDeliveryStatusLambda(n){return{[`${n.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Q.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:n.messageLogTable||"",NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createMessageLogTable(n){return{[`${n.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(n){return{[`${n.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(n){return{[`${n.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${n.slug}-sms-notifications`}}}}static createCompleteSetup(n){let i={},s={};Object.assign(i,Q.createPinpointApp({slug:n.slug})),Object.assign(i,Q.createSmsChannel({slug:n.slug,applicationId:{Ref:`${n.slug}PinpointApp`},senderId:n.senderId})),Object.assign(i,Q.createSmsLambdaRole({slug:n.slug})),Object.assign(i,Q.createMessageLogTable({slug:n.slug})),Object.assign(i,Q.createOptOutTable({slug:n.slug})),Object.assign(i,Q.createNotificationTopic({slug:n.slug}));let o={"Fn::GetAtt":[`${n.slug}SmsLambdaRole`,"Arn"]},c={Ref:`${n.slug}PinpointApp`},l={Ref:`${n.slug}SmsMessageLogTable`},u={Ref:`${n.slug}SmsOptOutTable`},h={Ref:`${n.slug}SmsNotificationTopic`};if(Object.assign(i,Q.createSendLambda({slug:n.slug,roleArn:o,pinpointAppId:c,messageLogTable:l,senderId:n.senderId,originationNumber:n.originationNumber})),n.twoWayEnabled)Object.assign(i,Q.createReceiveLambda({slug:n.slug,roleArn:o,optOutTable:u,messageLogTable:l,notificationTopicArn:h,webhookUrl:n.webhookUrl}));return Object.assign(i,Q.createDeliveryStatusLambda({slug:n.slug,roleArn:o,messageLogTable:l,notificationTopicArn:h,webhookUrl:n.webhookUrl})),s[`${n.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${n.slug}PinpointApp`}},s[`${n.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${n.slug}SmsSendLambda`,"Arn"]}},s[`${n.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${n.slug}SmsNotificationTopic`}},s[`${n.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${n.slug}SmsMessageLogTable`}},{resources:i,outputs:s}}}function Rt(n){return n.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")||"User"}function wr(n,i){let s=(n||i).replace(/^\/+|\/+$/g,"");if(!s||s.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${i}`);return s}function Er(n){let i=n.storage;if(i?.type==="efs"){let o="fileSystemId"in i?i.fileSystemId:void 0;if(!o||typeof o==="string"&&!o.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:o,posixProfile:i.posixProfile}}let s=(i?.type==="s3"?i.bucket??n.bucket:n.bucket)?.trim();if(!s)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:s}}function Pr(n,i,s){let o=i.posixProfile??s;if(!o)throw Error(`sftp: user ${n} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let c of[o.uid,o.gid,...o.secondaryGids??[]])if(!Number.isInteger(c)||c<0||c>4294967295)throw Error(`sftp: user ${n} has an invalid posixProfile id ${c}`);return{Uid:o.uid,Gid:o.gid,...o.secondaryGids?.length?{SecondaryGids:o.secondaryGids}:{}}}function Ir(n,i){return typeof n==="string"?`/${n}/${i}`:{"Fn::Sub":[`/\${FileSystemId}/${i}`,{FileSystemId:n}]}}function Rr(n){return typeof n==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",n)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:n}]}}class xd{static create(n){let i=Er(n),s=i.type==="efs"?"EFS":"S3",o=n.endpointType??"PUBLIC";if(o==="VPC"&&(!n.endpointDetails?.vpcId||!n.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let c=`${Rt(n.slug)}${Rt(n.environment)}Sftp`,l=`${c}Server`,u={},h;if(n.logging!==!1){let y=`${c}LoggingRole`;u[y]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},h={"Fn::GetAtt":[y,"Arn"]}}u[l]={Type:"AWS::Transfer::Server",Properties:{Domain:s,EndpointType:o,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...o==="VPC"?{EndpointDetails:{VpcId:n.endpointDetails.vpcId,SubnetIds:n.endpointDetails.subnetIds,...n.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:n.endpointDetails.securityGroupIds}:{},...n.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:n.endpointDetails.addressAllocationIds}:{}}}:{},...n.securityPolicyName?{SecurityPolicyName:n.securityPolicyName}:{},...h?{LoggingRole:h}:{},Tags:[{Key:"Project",Value:n.slug},{Key:"Environment",Value:n.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[y,f]of Object.entries(n.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(y))throw Error(`sftp: invalid username ${y}`);if(!f.sshPublicKeys.length)throw Error(`sftp: user ${y} requires at least one SSH public key`);let b=Rt(y),C=wr(f.homeDirectory,y),T=`${c}${b}User`,w=f.roleArn;if(!w){let E=`${c}${b}Role`,I;if(i.type==="efs")I=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Rr(i.fileSystemId)}];else{let N=`arn:aws:s3:::${i.bucket}`;I=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:N,Condition:{StringLike:{"s3:prefix":[C,`${C}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${N}/${C}/*`}]}u[E]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"SftpHomeDirectory",PolicyDocument:{Version:"2012-10-17",Statement:I}}]}},w={"Fn::GetAtt":[E,"Arn"]}}u[T]={Type:"AWS::Transfer::User",DependsOn:[l],Properties:{ServerId:{Ref:l},UserName:y,Role:w,HomeDirectoryType:"PATH",HomeDirectory:i.type==="efs"?Ir(i.fileSystemId,C):`/${i.bucket}/${C}`,...i.type==="efs"?{PosixProfile:Pr(y,f,i.posixProfile)}:{},SshPublicKeys:f.sshPublicKeys}}}return{resources:u,serverLogicalId:l,domain:s}}}class Pe{static createBedrockRole(n,i){let{slug:s,environment:o,name:c,models:l=["*"],allowStreaming:u=!0}=i,h=c||r({slug:s,environment:o,resourceType:"bedrock-role"}),y=t(h),f=["bedrock:InvokeModel"];if(u)f.push("bedrock:InvokeModelWithResponseStream");let b=l.map((C)=>C==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${C}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:h,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:n},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${h}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:f,Resource:b}]}}],Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:o}]}},logicalId:y}}static createBedrockPolicy(n){let{slug:i,environment:s,name:o,models:c=["*"],allowInvoke:l=!0,allowStreaming:u=!0,allowAsync:h=!1}=n,y=o||r({slug:i,environment:s,resourceType:"bedrock-policy"}),f=t(y),b=[];if(l)b.push("bedrock:InvokeModel");if(u)b.push("bedrock:InvokeModelWithResponseStream");if(h)b.push("bedrock:InvokeModelAsync");let C=c.map((T)=>T==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${T}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:y,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:b,Resource:C}]}}},logicalId:f}}static enableBedrockForLambda(n){return Pe.createBedrockRole("lambda.amazonaws.com",n)}static enableBedrockForEcs(n){return Pe.createBedrockRole("ecs-tasks.amazonaws.com",n)}static enableBedrockForEc2(n){return Pe.createBedrockRole("ec2.amazonaws.com",n)}static addBedrockPermissions(n,i=["*"],s=!0){let o=["bedrock:InvokeModel"];if(s)o.push("bedrock:InvokeModelWithResponseStream");let c=i.map((l)=>l==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${l}`);if(!n.Properties.Policies)n.Properties.Policies=[];return n.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:o,Resource:c}]}}),n}static Models={Claude3_5_Sonnet:"anthropic.claude-3-5-sonnet-20241022-v2:0",Claude3_5_Haiku:"anthropic.claude-3-5-haiku-20241022-v1:0",Claude3_Opus:"anthropic.claude-3-opus-20240229-v1:0",Claude3_Sonnet:"anthropic.claude-3-sonnet-20240229-v1:0",Claude3_Haiku:"anthropic.claude-3-haiku-20240307-v1:0",TitanTextG1Express:"amazon.titan-text-express-v1",TitanTextG1Lite:"amazon.titan-text-lite-v1",TitanEmbedG1Text:"amazon.titan-embed-text-v1",TitanImageG1:"amazon.titan-image-generator-v1",JurassicUltra:"ai21.j2-ultra-v1",JurassicMid:"ai21.j2-mid-v1",CommandText:"cohere.command-text-v14",CommandLight:"cohere.command-light-text-v14",EmbedEnglish:"cohere.embed-english-v3",EmbedMultilingual:"cohere.embed-multilingual-v3",Llama3_2_1B:"meta.llama3-2-1b-instruct-v1:0",Llama3_2_3B:"meta.llama3-2-3b-instruct-v1:0",Llama3_2_11B:"meta.llama3-2-11b-instruct-v1:0",Llama3_2_90B:"meta.llama3-2-90b-instruct-v1:0",Llama3_1_8B:"meta.llama3-1-8b-instruct-v1:0",Llama3_1_70B:"meta.llama3-1-70b-instruct-v1:0",Llama3_1_405B:"meta.llama3-1-405b-instruct-v1:0",Mistral7B:"mistral.mistral-7b-instruct-v0:2",Mixtral8x7B:"mistral.mixtral-8x7b-instruct-v0:1",MistralLarge:"mistral.mistral-large-2402-v1:0",StableDiffusionXL:"stability.stable-diffusion-xl-v1"};static ModelGroups={AllClaude:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","anthropic.claude-3-opus-20240229-v1:0","anthropic.claude-3-sonnet-20240229-v1:0","anthropic.claude-3-haiku-20240307-v1:0"],AllTitan:["amazon.titan-text-express-v1","amazon.titan-text-lite-v1","amazon.titan-embed-text-v1","amazon.titan-image-generator-v1"],AllLlama:["meta.llama3-2-1b-instruct-v1:0","meta.llama3-2-3b-instruct-v1:0","meta.llama3-2-11b-instruct-v1:0","meta.llama3-2-90b-instruct-v1:0","meta.llama3-1-8b-instruct-v1:0","meta.llama3-1-70b-instruct-v1:0","meta.llama3-1-405b-instruct-v1:0"],TextModels:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","amazon.titan-text-express-v1","meta.llama3-2-11b-instruct-v1:0","mistral.mistral-7b-instruct-v0:2"],EmbeddingModels:["amazon.titan-embed-text-v1","cohere.embed-english-v3","cohere.embed-multilingual-v3"],ImageModels:["amazon.titan-image-generator-v1","stability.stable-diffusion-xl-v1"]}}class jt{static createPostgres(n){return jt.createRDSInstance("postgres","16.2",n)}static createMysql(n){return jt.createRDSInstance("mysql","8.0.35",n)}static createRDSInstance(n,i,s){let{slug:o,environment:c,instanceClass:l="db.t3.micro",allocatedStorage:u=20,storageType:h="gp3",masterUsername:y="admin",masterPassword:f,databaseName:b,subnetIds:C,securityGroupIds:T,encrypted:w=!0,kmsKeyId:E,multiAz:I=!1,backupRetentionDays:N=7,publiclyAccessible:D=!1,enableCloudwatchLogs:x=!0,deletionProtection:R=!0}=s,_=r({slug:o,environment:c,resourceType:`${n}-db`}),B=t(_),W,J;if(C&&C.length>0){let Y=r({slug:o,environment:c,resourceType:"db-subnet-group"});J=t(Y),W={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:Y,DBSubnetGroupDescription:`Subnet group for ${_}`,SubnetIds:C,Tags:[{Key:"Name",Value:Y},{Key:"Environment",Value:c}]}}}let K={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:_,DBInstanceClass:l,Engine:n,EngineVersion:i,MasterUsername:y,MasterUserPassword:f,AllocatedStorage:u,StorageType:h,StorageEncrypted:w,MultiAZ:I,BackupRetentionPeriod:N,PubliclyAccessible:D,DeletionProtection:R,Tags:[{Key:"Name",Value:_},{Key:"Environment",Value:c}]}};if(b)K.Properties.DBName=b;if(E)K.Properties.KmsKeyId=E;if(J)K.Properties.DBSubnetGroupName=k.Ref(J);if(T&&T.length>0)K.Properties.VPCSecurityGroups=T;if(x)K.Properties.EnableCloudwatchLogsExports=n==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:K,subnetGroup:W,logicalId:B,subnetGroupId:J}}static createReadReplica(n,i){let{slug:s,environment:o,instanceClass:c="db.t3.micro",securityGroupIds:l,publiclyAccessible:u=!1}=i,h=r({slug:s,environment:o,resourceType:"db-replica"}),y=t(h),f={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:h,DBInstanceClass:c,SourceDBInstanceIdentifier:k.Ref(n),PubliclyAccessible:u,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:o},{Key:"Type",Value:"ReadReplica"}]}};if(l&&l.length>0)f.Properties.VPCSecurityGroups=l;return{replica:f,logicalId:y}}static createParameterGroup(n,i,s){let{slug:o,environment:c,parameters:l={}}=s,u=r({slug:o,environment:c,resourceType:"db-params"}),h=t(u),y=n==="postgres"?`postgres${i.split(".")[0]}`:`mysql${i.split(".")[0]}.${i.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:u,Description:`Parameter group for ${u}`,Family:y,Parameters:l,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:c}]}},logicalId:h}}static enableBackup(n,i=7){return n.Properties.BackupRetentionPeriod=i,n}static createTable(n){let{slug:i,environment:s,tableName:o,partitionKey:c,sortKey:l,billingMode:u="PAY_PER_REQUEST",readCapacity:h=5,writeCapacity:y=5,streamEnabled:f=!1,streamViewType:b="NEW_AND_OLD_IMAGES",encrypted:C=!0,kmsKeyId:T,pointInTimeRecovery:w=!0,ttlAttribute:E}=n,I=o||r({slug:i,environment:s,resourceType:"table"}),N=t(I),D=[{AttributeName:c.name,AttributeType:c.type}];if(l)D.push({AttributeName:l.name,AttributeType:l.type});let x=[{AttributeName:c.name,KeyType:"HASH"}];if(l)x.push({AttributeName:l.name,KeyType:"RANGE"});let R={Type:"AWS::DynamoDB::Table",Properties:{TableName:I,BillingMode:u,AttributeDefinitions:D,KeySchema:x,Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:s}]}};if(u==="PROVISIONED")R.Properties.ProvisionedThroughput={ReadCapacityUnits:h,WriteCapacityUnits:y};if(f)R.Properties.StreamSpecification={StreamViewType:b};if(C)R.Properties.SSESpecification={SSEEnabled:!0,SSEType:T?"KMS":"AES256",KMSMasterKeyId:T};if(w)R.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(E)R.Properties.TimeToLiveSpecification={AttributeName:E,Enabled:!0};return{table:R,logicalId:N}}static addGlobalSecondaryIndex(n,i){let{indexName:s,partitionKey:o,sortKey:c,projectionType:l="ALL",nonKeyAttributes:u,readCapacity:h=5,writeCapacity:y=5}=i;if(!n.Properties.AttributeDefinitions.some((C)=>C.AttributeName===o.name))n.Properties.AttributeDefinitions.push({AttributeName:o.name,AttributeType:o.type});if(c&&!n.Properties.AttributeDefinitions.some((C)=>C.AttributeName===c.name))n.Properties.AttributeDefinitions.push({AttributeName:c.name,AttributeType:c.type});let f=[{AttributeName:o.name,KeyType:"HASH"}];if(c)f.push({AttributeName:c.name,KeyType:"RANGE"});let b={IndexName:s,KeySchema:f,Projection:{ProjectionType:l,NonKeyAttributes:l==="INCLUDE"?u:void 0},ProvisionedThroughput:void 0};if(n.Properties.BillingMode==="PROVISIONED")b.ProvisionedThroughput={ReadCapacityUnits:h,WriteCapacityUnits:y};if(!n.Properties.GlobalSecondaryIndexes)n.Properties.GlobalSecondaryIndexes=[];return n.Properties.GlobalSecondaryIndexes.push(b),n}static enableStreams(n,i="NEW_AND_OLD_IMAGES"){return n.Properties.StreamSpecification={StreamViewType:i},n}static InstanceClasses={T3_Micro:"db.t3.micro",T3_Small:"db.t3.small",T3_Medium:"db.t3.medium",T3_Large:"db.t3.large",T4g_Micro:"db.t4g.micro",T4g_Small:"db.t4g.small",T4g_Medium:"db.t4g.medium",M5_Large:"db.m5.large",M5_XLarge:"db.m5.xlarge",M5_2XLarge:"db.m5.2xlarge",R5_Large:"db.r5.large",R5_XLarge:"db.r5.xlarge",R5_2XLarge:"db.r5.2xlarge"}}class go{static createRedis(n){let{slug:i,environment:s,nodeType:o="cache.t3.micro",engineVersion:c="7.1",port:l=6379,subnetIds:u,securityGroupIds:h,numCacheClusters:y=2,automaticFailover:f=!0,multiAz:b=!0,clusterMode:C=!1,numNodeGroups:T=1,replicasPerNodeGroup:w=1,atRestEncryption:E=!0,transitEncryption:I=!0,authToken:N,kmsKeyId:D,snapshotRetentionDays:x=7,snapshotWindow:R,maintenanceWindow:_}=n,B=r({slug:i,environment:s,resourceType:"redis"}),W=t(B),J,K;if(u&&u.length>0){let Z=r({slug:i,environment:s,resourceType:"cache-subnet-group"});K=t(Z),J={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:Z,Description:`Subnet group for ${B}`,SubnetIds:u,Tags:[{Key:"Name",Value:Z},{Key:"Environment",Value:s}]}}}let Y={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:B,ReplicationGroupDescription:`Redis cluster for ${i} ${s}`,Engine:"redis",EngineVersion:c,CacheNodeType:o,Port:l,AutomaticFailoverEnabled:f,MultiAZEnabled:b,AtRestEncryptionEnabled:E,TransitEncryptionEnabled:I,SnapshotRetentionLimit:x,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:B},{Key:"Environment",Value:s}]}};if(C)Y.Properties.NumNodeGroups=T,Y.Properties.ReplicasPerNodeGroup=w;else Y.Properties.NumCacheClusters=y;if(N)Y.Properties.AuthToken=N;if(D)Y.Properties.KmsKeyId=D;if(K)Y.Properties.CacheSubnetGroupName=k.Ref(K);if(h&&h.length>0)Y.Properties.SecurityGroupIds=h;if(R)Y.Properties.SnapshotWindow=R;if(_)Y.Properties.PreferredMaintenanceWindow=_;return{replicationGroup:Y,subnetGroup:J,logicalId:W,subnetGroupId:K}}static createMemcached(n){let{slug:i,environment:s,nodeType:o="cache.t3.micro",engineVersion:c="1.6.22",port:l=11211,numCacheNodes:u=2,subnetIds:h,securityGroupIds:y,azMode:f="cross-az",preferredAzs:b,maintenanceWindow:C}=n,T=r({slug:i,environment:s,resourceType:"memcached"}),w=t(T),E,I;if(h&&h.length>0){let D=r({slug:i,environment:s,resourceType:"cache-subnet-group"});I=t(D),E={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:D,Description:`Subnet group for ${T}`,SubnetIds:h,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:s}]}}}let N={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:T,CacheNodeType:o,Engine:"memcached",EngineVersion:c,NumCacheNodes:u,Port:l,AZMode:f,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:T},{Key:"Environment",Value:s}]}};if(I)N.Properties.CacheSubnetGroupName=k.Ref(I);if(y&&y.length>0)N.Properties.VpcSecurityGroupIds=y;if(b&&b.length>0)N.Properties.PreferredAvailabilityZones=b;if(C)N.Properties.PreferredMaintenanceWindow=C;return{cluster:N,subnetGroup:E,logicalId:w,subnetGroupId:I}}static enableClusterMode(n,i=3,s=2){return delete n.Properties.NumCacheClusters,n.Properties.NumNodeGroups=i,n.Properties.ReplicasPerNodeGroup=s,n}static createRedisParameterGroup(n,i){let{slug:s,environment:o,parameters:c={}}=i,l=r({slug:s,environment:o,resourceType:"redis-params"}),u=t(l);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${n.split(".")[0]}.x`,Description:`Parameter group for ${l}`,Properties:c,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:o}]}},logicalId:u}}static createMemcachedParameterGroup(n,i){let{slug:s,environment:o,parameters:c={}}=i,l=r({slug:s,environment:o,resourceType:"memcached-params"}),u=t(l);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${n.split(".")[0]}.${n.split(".")[1]}`,Description:`Parameter group for ${l}`,Properties:c,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:o}]}},logicalId:u}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class ee{static createUser(n){let{slug:i,environment:s,userName:o,groups:c,managedPolicyArns:l}=n,u=o||r({slug:i,environment:s,resourceType:"user"}),h=t(u),y={Type:"AWS::IAM::User",Properties:{UserName:u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s}]}};if(c&&c.length>0)y.Properties.Groups=c;if(l&&l.length>0)y.Properties.ManagedPolicyArns=l;return{user:y,logicalId:h}}static createRole(n){let{slug:i,environment:s,roleName:o,servicePrincipal:c,awsPrincipal:l,managedPolicyArns:u}=n,h=o||r({slug:i,environment:s,resourceType:"role"}),y=t(h),f={};if(c)f.Service=c;if(l)f.AWS=l;let b={Type:"AWS::IAM::Role",Properties:{RoleName:h,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:f,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(u&&u.length>0)b.Properties.ManagedPolicyArns=u;return{role:b,logicalId:y}}static createGroup(n){let{slug:i,environment:s,groupName:o,managedPolicyArns:c}=n,l=o||r({slug:i,environment:s,resourceType:"group"}),u=t(l),h={Type:"AWS::IAM::Group",Properties:{GroupName:l}};if(c&&c.length>0)h.Properties.ManagedPolicyArns=c;return{group:h,logicalId:u}}static createPolicy(n){let{slug:i,environment:s,policyName:o,description:c,statements:l}=n,u=o||r({slug:i,environment:s,resourceType:"policy"}),h=t(u),y=l.map((f)=>({Sid:f.sid,Effect:f.effect||"Allow",Action:f.actions,Resource:f.resources,Condition:f.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:u,Description:c||`Managed policy for ${u}`,PolicyDocument:{Version:"2012-10-17",Statement:y}}},logicalId:h}}static attachPolicyToRole(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static attachPolicyToUser(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static attachPolicyToGroup(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static addInlinePolicyToRole(n,i,s){if(!n.Properties.Policies)n.Properties.Policies=[];let o=s.map((c)=>({Effect:c.effect||"Allow",Action:c.actions,Resource:c.resources}));return n.Properties.Policies.push({PolicyName:i,PolicyDocument:{Version:"2012-10-17",Statement:o}}),n}static addInlinePolicyToUser(n,i,s){if(!n.Properties.Policies)n.Properties.Policies=[];let o=s.map((c)=>({Effect:c.effect||"Allow",Action:c.actions,Resource:c.resources}));return n.Properties.Policies.push({PolicyName:i,PolicyDocument:{Version:"2012-10-17",Statement:o}}),n}static createAccessKey(n,i){let{slug:s,environment:o,status:c="Active"}=i,l=r({slug:s,environment:o,resourceType:"access-key"}),u=t(l);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:k.Ref(n),Status:c}},logicalId:u}}static createInstanceProfile(n,i){let{slug:s,environment:o,profileName:c}=i,l=c||r({slug:s,environment:o,resourceType:"instance-profile"}),u=t(l);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:l,Roles:[k.Ref(n)]}},logicalId:u}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(n){let{slug:i,environment:s,permissions:o,createAccessKey:c=!0}=n,l={},u=[];if(o.s3Buckets&&o.s3Buckets.length>0)u.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...o.s3Buckets,...o.s3Buckets.map((w)=>`${w}/*`)]});if(o.cloudFrontDistributions&&o.cloudFrontDistributions.length>0)u.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:o.cloudFrontDistributions});if(o.ecrRepositories&&o.ecrRepositories.length>0)u.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:o.ecrRepositories}),u.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(o.ecsServices&&o.ecsServices.length>0)u.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:o.ecsServices}),u.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),u.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(o.cloudFormationStacks&&o.cloudFormationStacks.length>0)u.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:o.cloudFormationStacks});if(o.lambdaFunctions&&o.lambdaFunctions.length>0)u.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:o.lambdaFunctions});if(o.secretsManagerSecrets&&o.secretsManagerSecrets.length>0)u.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:o.secretsManagerSecrets});let{policy:h,logicalId:y}=ee.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${i} (${s})`,statements:u});l[y]=h;let{user:f,logicalId:b}=ee.createUser({slug:i,environment:s,userName:r({slug:i,environment:s,resourceType:"cicd-user"}),managedPolicyArns:[k.Ref(y)]});l[b]=f;let C,T;if(c){let w=ee.createAccessKey(b,{slug:i,environment:s});C=w.accessKey,T=w.logicalId,l[T]=C}return{user:f,accessKey:C,policy:h,userLogicalId:b,accessKeyLogicalId:T,policyLogicalId:y,resources:l}}static createCrossAccountRole(n){let{slug:i,environment:s,trustedAccountIds:o,externalId:c,permissions:l,maxSessionDuration:u=3600}=n,h={},{policy:y,logicalId:f}=ee.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${i} (${s})`,statements:l});h[f]=y;let b=r({slug:i,environment:s,resourceType:"cross-account-role"}),C=t(b),T={};if(c)T.StringEquals={"sts:ExternalId":c};let w={Type:"AWS::IAM::Role",Properties:{RoleName:b,MaxSessionDuration:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:o.map((E)=>`arn:aws:iam::${E}:root`)},Action:"sts:AssumeRole",...Object.keys(T).length>0?{Condition:T}:{}}]},ManagedPolicyArns:[k.Ref(f)],Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s},{Key:"Purpose",Value:"Cross-Account Access"}]}};return h[C]=w,{role:w,policy:y,roleLogicalId:C,policyLogicalId:f,resources:h}}static createCliUser(n){let{slug:i,environment:s,permissions:o="readonly"}=n,c={},l=[],u=[];switch(o){case"readonly":u=[ee.ManagedPolicies.ReadOnlyAccess];break;case"deploy":l=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":u=[ee.ManagedPolicies.AdministratorAccess];break}let h,y;if(l.length>0){let w=ee.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cli-policy"}),description:`CLI access policy for ${i} (${s})`,statements:l});h=w.policy,y=w.logicalId,c[y]=h,u=[k.Ref(y)]}let{user:f,logicalId:b}=ee.createUser({slug:i,environment:s,userName:r({slug:i,environment:s,resourceType:"cli-user"}),managedPolicyArns:u});c[b]=f;let{accessKey:C,logicalId:T}=ee.createAccessKey(b,{slug:i,environment:s});return c[T]=C,{user:f,accessKey:C,policy:h,userLogicalId:b,accessKeyLogicalId:T,policyLogicalId:y,resources:c}}static CiCdPolicies={s3Deployment:(n)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:n},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:n.map((i)=>`${i}/*`)}],cloudFrontInvalidation:(n)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:n}],ecsDeployment:()=>[{sid:"ECSServices",actions:["ecs:DescribeServices","ecs:UpdateService","ecs:DescribeTaskDefinition","ecs:RegisterTaskDefinition"],resources:"*"},{sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}}],ecrPush:(n)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:n}],lambdaDeployment:(n)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:n}],cloudFormationDeployment:(n)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:n}]}}class Od{static createRestApi(n){let{slug:i,environment:s,name:o,description:c,endpointType:l="REGIONAL",binaryMediaTypes:u,compressionSize:h}=n,y=o||r({slug:i,environment:s,resourceType:"rest-api"}),f=t(y),b={Type:"AWS::ApiGateway::RestApi",Properties:{Name:y,Description:c||`REST API for ${i} ${s}`,EndpointConfiguration:{Types:[l]},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s}]}};if(u&&u.length>0)b.Properties.BinaryMediaTypes=u;if(h!==void 0)b.Properties.MinimumCompressionSize=h;return{restApi:b,logicalId:f}}static createHttpApi(n){let{slug:i,environment:s,name:o,description:c,corsEnabled:l=!0,corsOrigins:u=["*"],corsMethods:h=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:y=["*"],corsMaxAge:f=86400,corsAllowCredentials:b=!1}=n,C=o||r({slug:i,environment:s,resourceType:"http-api"}),T=t(C),w={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:C,Description:c||`HTTP API for ${i} ${s}`,ProtocolType:"HTTP",Tags:{Name:C,Environment:s}}};if(l)w.Properties.CorsConfiguration={AllowOrigins:u,AllowMethods:h,AllowHeaders:y,MaxAge:f,AllowCredentials:b};return{httpApi:w,logicalId:T}}static createWebSocketApi(n){let{slug:i,environment:s,name:o,description:c}=n,l=o||r({slug:i,environment:s,resourceType:"ws-api"}),u=t(l);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:l,Description:c||`WebSocket API for ${i} ${s}`,ProtocolType:"WEBSOCKET",Tags:{Name:l,Environment:s}}},logicalId:u}}static createDeployment(n,i){let{slug:s,environment:o,description:c}=i,l=r({slug:s,environment:o,resourceType:"api-deployment"}),u=t(l);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:k.Ref(n),Description:c||`Deployment for ${l}`}},logicalId:u}}static createStage(n,i,s){let{slug:o,environment:c,stageName:l,description:u,cacheEnabled:h=!1,cacheSize:y="0.5",variables:f,throttling:b}=s,C=r({slug:o,environment:c,resourceType:"api-stage"}),T=t(C),w={Type:"AWS::ApiGateway::Stage",Properties:{StageName:l||c,RestApiId:k.Ref(n),DeploymentId:k.Ref(i),Description:u,CacheClusterEnabled:h,Tags:[{Key:"Name",Value:C},{Key:"Environment",Value:c}]}};if(h)w.Properties.CacheClusterSize=y;if(f)w.Properties.Variables=f;if(b)w.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:b.burstLimit,ThrottlingRateLimit:b.rateLimit}];return{stage:w,logicalId:T}}static createAuthorizer(n,i){let{slug:s,environment:o,name:c,type:l,functionArn:u,identitySource:h,userPoolArns:y,ttl:f=300}=i,b=c||r({slug:s,environment:o,resourceType:"api-authorizer"}),C=t(b),T={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:b,Type:l,RestApiId:k.Ref(n),AuthorizerResultTtlInSeconds:f}};if(l==="TOKEN"||l==="REQUEST"){if(!u)throw Error("Lambda authorizer requires functionArn");T.Properties.AuthorizerUri=u,T.Properties.IdentitySource=h||"method.request.header.Authorization"}if(l==="COGNITO_USER_POOLS"){if(!y||y.length===0)throw Error("Cognito authorizer requires userPoolArns");T.Properties.ProviderARNs=y,T.Properties.IdentitySource=h||"method.request.header.Authorization"}return{authorizer:T,logicalId:C}}static setCors(n,i={}){let{origins:s=["*"],methods:o=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:c=["*"],maxAge:l=86400,allowCredentials:u=!1}=i;return n.Properties.CorsConfiguration={AllowOrigins:s,AllowMethods:o,AllowHeaders:c,MaxAge:l,AllowCredentials:u},n}static addThrottling(n,i=5000,s=1e4){if(!n.Properties.MethodSettings)n.Properties.MethodSettings=[];return n.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:i,ThrottlingRateLimit:s}),n}static enableCaching(n,i="0.5",s=300){if(n.Properties.CacheClusterEnabled=!0,n.Properties.CacheClusterSize=i,!n.Properties.MethodSettings)n.Properties.MethodSettings=[];return n.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:s}),n}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class te{static createTopic(n){let{slug:i,environment:s,topicName:o,displayName:c,encrypted:l=!1,kmsKeyId:u}=n,h=o||r({slug:i,environment:s,resourceType:"topic"}),y=t(h),f={Type:"AWS::SNS::Topic",Properties:{TopicName:h,DisplayName:c||h,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(l&&u)f.Properties.KmsMasterKeyId=u;return{topic:f,logicalId:y}}static subscribe(n,i){let{slug:s,environment:o,protocol:c,endpoint:l,filterPolicy:u,rawMessageDelivery:h=!1}=i,y=r({slug:s,environment:o,resourceType:"subscription"}),f=l.replace(/[^a-zA-Z0-9]/g,""),b=f.length>12?f.slice(-12):f,C=t(`${y}-${c}-${b}`),T={Type:"AWS::SNS::Subscription",Properties:{TopicArn:k.Ref(n),Protocol:c,Endpoint:l,RawMessageDelivery:h}};if(u)T.Properties.FilterPolicy=u;return{subscription:T,logicalId:C}}static subscribeEmail(n,i,s){return te.subscribe(n,{...s,protocol:"email",endpoint:i})}static subscribeLambda(n,i,s){return te.subscribe(n,{...s,protocol:"lambda",endpoint:i,rawMessageDelivery:!0})}static subscribeSqs(n,i,s){return te.subscribe(n,{...s,protocol:"sqs",endpoint:i})}static subscribeHttp(n,i,s){let o=i.startsWith("https://")?"https":"http";return te.subscribe(n,{...s,protocol:o,endpoint:i})}static subscribeSms(n,i,s){return te.subscribe(n,{...s,protocol:"sms",endpoint:i})}static setTopicPolicy(n,i){let{slug:s,environment:o,allowedPrincipals:c,allowedServices:l,actions:u="SNS:Publish"}=i,h=r({slug:s,environment:o,resourceType:"topic-policy"}),y=t(h),f={};if(c)f.AWS=c;if(l)f.Service=l;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[k.Ref(n)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:f,Action:u,Resource:k.Ref(n)}]}}},logicalId:y}}static allowCloudWatchAlarms(n,i){return te.setTopicPolicy(n,{...i,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(n,i){return te.setTopicPolicy(n,{...i,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(n,i){return te.setTopicPolicy(n,{...i,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(n,i){if(!n.Properties)n.Properties={};return n.Properties.KmsMasterKeyId=i,n}static addInlineSubscription(n,i,s){if(!n.Properties)n.Properties={};if(!n.Properties.Subscription)n.Properties.Subscription=[];return n.Properties.Subscription.push({Protocol:i,Endpoint:s}),n}static FilterPolicies={eventType:(n)=>({eventType:n}),status:(n)=>({status:n}),numericRange:(n,i,s)=>({[n]:[{numeric:[">=",i,"<=",s]}]}),prefix:(n,i)=>({[n]:[{prefix:i}]}),and:(...n)=>Object.assign({},...n),exists:(n,i)=>({[n]:[{exists:i}]})};static UseCases={createAlertTopic:(n)=>te.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-alerts`,displayName:n.displayName||"Alert Notifications"}),createEventFanout:(n)=>te.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-events`,displayName:n.displayName||"Event Fanout"}),createNotificationTopic:(n)=>te.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-notifications`,displayName:n.displayName||"User Notifications"})}}class lA{static createStateMachine(n){let{slug:i,environment:s,stateMachineName:o,type:c="STANDARD",definition:l,roleArn:u,loggingConfiguration:h,tracingConfiguration:y}=n,f=o||r({slug:i,environment:s,resourceType:"state-machine"}),b=t(f),C,T,w;if(u)w=u;else{let I=r({slug:i,environment:s,resourceType:"state-machine-role"});T=t(I),C={Type:"AWS::IAM::Role",Properties:{RoleName:I,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"states.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"],Tags:[{Key:"Name",Value:I},{Key:"Environment",Value:s}]}},w=k.GetAtt(T,"Arn")}let E={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:f,StateMachineType:c,DefinitionString:JSON.stringify(l),RoleArn:w,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:s}]}};if(h)E.Properties.LoggingConfiguration={Level:h.level,IncludeExecutionData:h.includeExecutionData,Destinations:h.destinations?.map((I)=>({CloudWatchLogsLogGroup:{LogGroupArn:I}}))};if(y)E.Properties.TracingConfiguration={Enabled:y.enabled};return{stateMachine:E,logicalId:b,role:C,roleLogicalId:T}}static createLambdaTask(n,i){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:n,Payload:i?.parameters||{"Input.$":"$"}},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createDynamoDBTask(n,i,s,o){return{Type:"Task",Resource:{GetItem:"arn:aws:states:::dynamodb:getItem",PutItem:"arn:aws:states:::dynamodb:putItem",UpdateItem:"arn:aws:states:::dynamodb:updateItem",DeleteItem:"arn:aws:states:::dynamodb:deleteItem"}[n],Parameters:{TableName:i,...s},ResultPath:o?.resultPath,Retry:o?.retry,Catch:o?.catch,Next:o?.next,End:o?.end}}static createSNSPublishTask(n,i,s){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:n,Message:i},ResultPath:s?.resultPath,Retry:s?.retry,Catch:s?.catch,Next:s?.next,End:s?.end}}static createSQSSendMessageTask(n,i,s){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:n,MessageBody:i},ResultPath:s?.resultPath,Retry:s?.retry,Catch:s?.catch,Next:s?.next,End:s?.end}}static createPassState(n){return{Type:"Pass",Result:n?.result,ResultPath:n?.resultPath,Parameters:n?.parameters,Next:n?.next,End:n?.end}}static createWaitState(n){return{Type:"Wait",Seconds:n.seconds,Timestamp:n.timestamp,SecondsPath:n.secondsPath,TimestampPath:n.timestampPath,Next:n.next,End:n.end}}static createChoiceState(n,i){return{Type:"Choice",Choices:n,Default:i}}static createParallelState(n,i){return{Type:"Parallel",Branches:n,ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createMapState(n,i){return{Type:"Map",ItemsPath:i?.itemsPath||"$.items",Iterator:n,MaxConcurrency:i?.maxConcurrency,ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(n,i){return{Type:"Fail",Error:n,Cause:i}}static RetryPolicies={standard:()=>({ErrorEquals:["States.ALL"],IntervalSeconds:2,MaxAttempts:3,BackoffRate:2}),aggressive:()=>({ErrorEquals:["States.TaskFailed","States.Timeout"],IntervalSeconds:1,MaxAttempts:5,BackoffRate:1.5}),custom:(n,i,s,o)=>({ErrorEquals:n,IntervalSeconds:i,MaxAttempts:s,BackoffRate:o})};static CatchPolicies={all:(n,i)=>({ErrorEquals:["States.ALL"],Next:n,ResultPath:i||"$.error"}),specific:(n,i,s)=>({ErrorEquals:n,Next:i,ResultPath:s||"$.error"})};static Patterns={sequential:(n,i,s)=>{let o={};return s.forEach((c,l)=>{let u=l===s.length-1;o[c.name]={...c.state,Next:u?void 0:s[l+1].name,End:u}}),{Comment:"Sequential workflow",StartAt:s[0].name,States:o}},fanout:(n,i,s)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:s.map((o)=>o.definition),End:!0}}}),map:(n,i,s,o)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:s,MaxConcurrency:o,End:!0}}}),withErrorHandling:(n,i,s,o)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...s,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:o,Success:{Type:"Succeed"}}})}}class mo{static createAlarm(n){let{slug:i,environment:s,alarmName:o,metricName:c,namespace:l,statistic:u="Average",period:h=300,evaluationPeriods:y=1,threshold:f,comparisonOperator:b,treatMissingData:C="notBreaching",actionsEnabled:T=!0,alarmActions:w,okActions:E,insufficientDataActions:I,dimensions:N,unit:D,datapointsToAlarm:x}=n,R=o||r({slug:i,environment:s,resourceType:"alarm"}),_=t(R),B={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:R,MetricName:c,Namespace:l,Statistic:u,Period:h,EvaluationPeriods:y,Threshold:f,ComparisonOperator:b,TreatMissingData:C,ActionsEnabled:T}};if(w&&w.length>0)B.Properties.AlarmActions=w;if(E&&E.length>0)B.Properties.OKActions=E;if(I&&I.length>0)B.Properties.InsufficientDataActions=I;if(N)B.Properties.Dimensions=Object.entries(N).map(([W,J])=>({Name:W,Value:J}));if(D)B.Properties.Unit=D;if(x!==void 0)B.Properties.DatapointsToAlarm=x;return{alarm:B,logicalId:_}}static createCompositeAlarm(n){let{slug:i,environment:s,alarmName:o,alarmRule:c,actionsEnabled:l=!0,alarmActions:u,okActions:h,insufficientDataActions:y}=n,f=o||r({slug:i,environment:s,resourceType:"composite-alarm"}),b=t(f),C={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:f,AlarmRule:c,ActionsEnabled:l}};if(u&&u.length>0)C.Properties.AlarmActions=u;if(h&&h.length>0)C.Properties.OKActions=h;if(y&&y.length>0)C.Properties.InsufficientDataActions=y;return{alarm:C,logicalId:b}}static createDashboard(n){let{slug:i,environment:s,dashboardName:o,widgets:c}=n,l=o||r({slug:i,environment:s,resourceType:"dashboard"}),u=t(l),h={widgets:c.map((y)=>({type:y.type,x:y.x,y:y.y,width:y.width,height:y.height,properties:y.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:l,DashboardBody:JSON.stringify(h)}},logicalId:u}}static createLogGroup(n){let{slug:i,environment:s,logGroupName:o,retentionInDays:c,kmsKeyId:l}=n,u=o||r({slug:i,environment:s,resourceType:"log-group"}),h=t(u),y={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:u}};if(c!==void 0)y.Properties.RetentionInDays=c;if(l)y.Properties.KmsKeyId=l;return{logGroup:y,logicalId:h}}static createLogStream(n,i){let{slug:s,environment:o,logStreamName:c}=i,l=c||r({slug:s,environment:o,resourceType:"log-stream"}),u=t(l);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:k.Ref(n),LogStreamName:l}},logicalId:u}}static createMetricFilter(n,i){let{slug:s,environment:o,filterName:c,filterPattern:l,metricTransformations:u}=i,h=c||r({slug:s,environment:o,resourceType:"metric-filter"}),y=t(h);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:k.Ref(n),FilterPattern:l,MetricTransformations:u.map((f)=>({MetricName:f.metricName,MetricNamespace:f.metricNamespace,MetricValue:f.metricValue,DefaultValue:f.defaultValue,Unit:f.unit}))}},logicalId:y}}static AlarmTypes={highCpu:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0}),highMemory:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0}),highDisk:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:c?[c]:void 0}),lambdaErrors:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:s},alarmActions:c?[c]:void 0}),lambdaThrottles:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:s},alarmActions:c?[c]:void 0}),apiGateway5xxErrors:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:s},alarmActions:c?[c]:void 0}),apiGateway4xxErrors:(n,i,s,o=50,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:s},alarmActions:c?[c]:void 0}),dynamoDBThrottles:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:s},alarmActions:c?[c]:void 0}),rdsCpu:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:s},alarmActions:c?[c]:void 0}),rdsFreeStorage:(n,i,s,o=5368709120,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:s},alarmActions:c?[c]:void 0,unit:"Bytes"}),sqsQueueDepth:(n,i,s,o=100,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:s},alarmActions:c?[c]:void 0}),albUnhealthyTargets:(n,i,s,o,c=1,l)=>({slug:n,environment:i,alarmName:`${n}-${i}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:c,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:s,TargetGroup:o},alarmActions:l?[l]:void 0}),sesBounceRate:(n,i,s=5,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:s/100,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),sesComplaintRate:(n,i,s=0.1,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:s/100,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),smsDeliveryFailure:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:s},alarmActions:c?[c]:void 0}),smsSpendLimit:(n,i,s=100,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:s,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),connectMissedCalls:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0})};static DashboardWidgets={metric:(n,i,s,o,c,l)=>({type:"metric",x:n,y:i,width:s,height:o,properties:{metrics:c,title:l||"Metrics",region:"us-east-1",period:300}}),text:(n,i,s,o,c)=>({type:"text",x:n,y:i,width:s,height:o,properties:{markdown:c}}),log:(n,i,s,o,c,l)=>({type:"log",x:n,y:i,width:s,height:o,properties:{query:`SOURCE '${c.join("' | SOURCE '")}'
2309
+ `;class Q{static LambdaCode={send:ka,receive:vr,deliveryStatus:Cr};static createPinpointApp(n){return{[`${n.slug}PinpointApp`]:{Type:"AWS::Pinpoint::App",Properties:{Name:n.name||`${n.slug}-sms`}}}}static createSmsChannel(n){let i={ApplicationId:n.applicationId,Enabled:n.enabled!==!1};if(n.senderId)i.SenderId=n.senderId;if(n.shortCode)i.ShortCode=n.shortCode;return{[`${n.slug}SmsChannel`]:{Type:"AWS::Pinpoint::SMSChannel",Properties:i}}}static createSmsLambdaRole(n){return{[`${n.slug}SmsLambdaRole`]:{Type:"AWS::IAM::Role",Properties:{RoleName:`${n.slug}-sms-lambda-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:"SmsLambdaPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetSmsChannel"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:GetItem","dynamodb:DeleteItem"],Resource:"*"}]}}]}}}}static createSendLambda(n){return{[`${n.slug}SmsSendLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-send`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Q.LambdaCode.send},Environment:{Variables:{PINPOINT_APP_ID:n.pinpointAppId,MESSAGE_LOG_TABLE:n.messageLogTable||"",SMS_SENDER_ID:n.senderId||"",SMS_ORIGINATION_NUMBER:n.originationNumber||""}}}}}}static createReceiveLambda(n){return{[`${n.slug}SmsReceiveLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-receive`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Q.LambdaCode.receive},Environment:{Variables:{OPT_OUT_TABLE:n.optOutTable||"",MESSAGE_LOG_TABLE:n.messageLogTable||"",NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createDeliveryStatusLambda(n){return{[`${n.slug}SmsDeliveryStatusLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-sms-delivery-status`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Q.LambdaCode.deliveryStatus},Environment:{Variables:{MESSAGE_LOG_TABLE:n.messageLogTable||"",NOTIFICATION_TOPIC_ARN:n.notificationTopicArn||"",WEBHOOK_URL:n.webhookUrl||""}}}}}}static createMessageLogTable(n){return{[`${n.slug}SmsMessageLogTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-sms-messages`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}}static createOptOutTable(n){return{[`${n.slug}SmsOptOutTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-sms-optouts`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}}static createNotificationTopic(n){return{[`${n.slug}SmsNotificationTopic`]:{Type:"AWS::SNS::Topic",Properties:{TopicName:`${n.slug}-sms-notifications`}}}}static createCompleteSetup(n){let i={},s={};Object.assign(i,Q.createPinpointApp({slug:n.slug})),Object.assign(i,Q.createSmsChannel({slug:n.slug,applicationId:{Ref:`${n.slug}PinpointApp`},senderId:n.senderId})),Object.assign(i,Q.createSmsLambdaRole({slug:n.slug})),Object.assign(i,Q.createMessageLogTable({slug:n.slug})),Object.assign(i,Q.createOptOutTable({slug:n.slug})),Object.assign(i,Q.createNotificationTopic({slug:n.slug}));let o={"Fn::GetAtt":[`${n.slug}SmsLambdaRole`,"Arn"]},c={Ref:`${n.slug}PinpointApp`},l={Ref:`${n.slug}SmsMessageLogTable`},u={Ref:`${n.slug}SmsOptOutTable`},h={Ref:`${n.slug}SmsNotificationTopic`};if(Object.assign(i,Q.createSendLambda({slug:n.slug,roleArn:o,pinpointAppId:c,messageLogTable:l,senderId:n.senderId,originationNumber:n.originationNumber})),n.twoWayEnabled)Object.assign(i,Q.createReceiveLambda({slug:n.slug,roleArn:o,optOutTable:u,messageLogTable:l,notificationTopicArn:h,webhookUrl:n.webhookUrl}));return Object.assign(i,Q.createDeliveryStatusLambda({slug:n.slug,roleArn:o,messageLogTable:l,notificationTopicArn:h,webhookUrl:n.webhookUrl})),s[`${n.slug}PinpointAppId`]={Description:"Pinpoint application ID",Value:{Ref:`${n.slug}PinpointApp`}},s[`${n.slug}SmsSendLambdaArn`]={Description:"SMS send Lambda ARN",Value:{"Fn::GetAtt":[`${n.slug}SmsSendLambda`,"Arn"]}},s[`${n.slug}SmsNotificationTopicArn`]={Description:"SMS notification topic ARN",Value:{Ref:`${n.slug}SmsNotificationTopic`}},s[`${n.slug}SmsMessageLogTableName`]={Description:"SMS message log table name",Value:{Ref:`${n.slug}SmsMessageLogTable`}},{resources:i,outputs:s}}}function Rt(n){return n.replace(/[^a-zA-Z0-9]/g," ").trim().split(/\s+/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1)).join("")||"User"}function wr(n,i){let s=(n||i).replace(/^\/+|\/+$/g,"");if(!s||s.split("/").includes(".."))throw Error(`sftp: invalid homeDirectory for user ${i}`);return s}function Er(n){let i=n.storage;if(i?.type==="efs"){let o="fileSystemId"in i?i.fileSystemId:void 0;if(!o||typeof o==="string"&&!o.trim())throw Error("sftp: EFS storage requires fileSystemId, or a fileSystem name defined in infrastructure.fileSystem");return{type:"efs",fileSystemId:o,posixProfile:i.posixProfile}}let s=(i?.type==="s3"?i.bucket??n.bucket:n.bucket)?.trim();if(!s)throw Error("sftp: S3 storage requires bucket, or a storageBucket name defined in infrastructure.storage");return{type:"s3",bucket:s}}function Pr(n,i,s){let o=i.posixProfile??s;if(!o)throw Error(`sftp: user ${n} requires a posixProfile (uid/gid) on an EFS-backed server`);for(let c of[o.uid,o.gid,...o.secondaryGids??[]])if(!Number.isInteger(c)||c<0||c>4294967295)throw Error(`sftp: user ${n} has an invalid posixProfile id ${c}`);return{Uid:o.uid,Gid:o.gid,...o.secondaryGids?.length?{SecondaryGids:o.secondaryGids}:{}}}function Ir(n,i){return typeof n==="string"?`/${n}/${i}`:{"Fn::Sub":[`/\${FileSystemId}/${i}`,{FileSystemId:n}]}}function Rr(n){return typeof n==="string"?{"Fn::Sub":"arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}".replace("${FileSystemId}",n)}:{"Fn::Sub":["arn:aws:elasticfilesystem:${AWS::Region}:${AWS::AccountId}:file-system/${FileSystemId}",{FileSystemId:n}]}}class xd{static create(n){let i=Er(n),s=i.type==="efs"?"EFS":"S3",o=n.endpointType??"PUBLIC";if(o==="VPC"&&(!n.endpointDetails?.vpcId||!n.endpointDetails.subnetIds.length))throw Error("sftp: VPC endpoints require endpointDetails.vpcId and at least one subnet");let c=`${Rt(n.slug)}${Rt(n.environment)}Sftp`,l=`${c}Server`,u={},h;if(n.logging!==!1){let y=`${c}LoggingRole`;u[y]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"TransferLogging",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:DescribeLogStreams","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:log-group:/aws/transfer/*"}]}}]}},h={"Fn::GetAtt":[y,"Arn"]}}u[l]={Type:"AWS::Transfer::Server",Properties:{Domain:s,EndpointType:o,IdentityProviderType:"SERVICE_MANAGED",Protocols:["SFTP"],...o==="VPC"?{EndpointDetails:{VpcId:n.endpointDetails.vpcId,SubnetIds:n.endpointDetails.subnetIds,...n.endpointDetails.securityGroupIds?.length?{SecurityGroupIds:n.endpointDetails.securityGroupIds}:{},...n.endpointDetails.addressAllocationIds?.length?{AddressAllocationIds:n.endpointDetails.addressAllocationIds}:{}}}:{},...n.securityPolicyName?{SecurityPolicyName:n.securityPolicyName}:{},...h?{LoggingRole:h}:{},Tags:[{Key:"Project",Value:n.slug},{Key:"Environment",Value:n.environment},{Key:"ManagedBy",Value:"ts-cloud"}]}};for(let[y,f]of Object.entries(n.users)){if(!/^[a-zA-Z0-9_.@-]{3,100}$/.test(y))throw Error(`sftp: invalid username ${y}`);if(!f.sshPublicKeys.length)throw Error(`sftp: user ${y} requires at least one SSH public key`);let S=Rt(y),b=wr(f.homeDirectory,y),v=`${c}${S}User`,w=f.roleArn;if(!w){let E=`${c}${S}Role`,P;if(i.type==="efs")P=[{Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:DescribeMountTargets"],Resource:Rr(i.fileSystemId)}];else{let R=`arn:aws:s3:::${i.bucket}`;P=[{Effect:"Allow",Action:["s3:ListBucket","s3:GetBucketLocation"],Resource:R,Condition:{StringLike:{"s3:prefix":[b,`${b}/*`]}}},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:GetObjectVersion"],Resource:`${R}/${b}/*`}]}u[E]={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"transfer.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"SftpHomeDirectory",PolicyDocument:{Version:"2012-10-17",Statement:P}}]}},w={"Fn::GetAtt":[E,"Arn"]}}u[v]={Type:"AWS::Transfer::User",DependsOn:[l],Properties:{ServerId:{Ref:l},UserName:y,Role:w,HomeDirectoryType:"PATH",HomeDirectory:i.type==="efs"?Ir(i.fileSystemId,b):`/${i.bucket}/${b}`,...i.type==="efs"?{PosixProfile:Pr(y,f,i.posixProfile)}:{},SshPublicKeys:f.sshPublicKeys}}}return{resources:u,serverLogicalId:l,domain:s}}}class Pe{static createBedrockRole(n,i){let{slug:s,environment:o,name:c,models:l=["*"],allowStreaming:u=!0}=i,h=c||r({slug:s,environment:o,resourceType:"bedrock-role"}),y=t(h),f=["bedrock:InvokeModel"];if(u)f.push("bedrock:InvokeModelWithResponseStream");let S=l.map((b)=>b==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${b}`);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:h,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:n},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:`${h}-policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:f,Resource:S}]}}],Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:o}]}},logicalId:y}}static createBedrockPolicy(n){let{slug:i,environment:s,name:o,models:c=["*"],allowInvoke:l=!0,allowStreaming:u=!0,allowAsync:h=!1}=n,y=o||r({slug:i,environment:s,resourceType:"bedrock-policy"}),f=t(y),S=[];if(l)S.push("bedrock:InvokeModel");if(u)S.push("bedrock:InvokeModelWithResponseStream");if(h)S.push("bedrock:InvokeModelAsync");let b=c.map((v)=>v==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${v}`);return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:y,PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"BedrockModelInvocation",Effect:"Allow",Action:S,Resource:b}]}}},logicalId:f}}static enableBedrockForLambda(n){return Pe.createBedrockRole("lambda.amazonaws.com",n)}static enableBedrockForEcs(n){return Pe.createBedrockRole("ecs-tasks.amazonaws.com",n)}static enableBedrockForEc2(n){return Pe.createBedrockRole("ec2.amazonaws.com",n)}static addBedrockPermissions(n,i=["*"],s=!0){let o=["bedrock:InvokeModel"];if(s)o.push("bedrock:InvokeModelWithResponseStream");let c=i.map((l)=>l==="*"?"arn:aws:bedrock:*::foundation-model/*":`arn:aws:bedrock:*::foundation-model/${l}`);if(!n.Properties.Policies)n.Properties.Policies=[];return n.Properties.Policies.push({PolicyName:"bedrock-permissions",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:o,Resource:c}]}}),n}static Models={Claude3_5_Sonnet:"anthropic.claude-3-5-sonnet-20241022-v2:0",Claude3_5_Haiku:"anthropic.claude-3-5-haiku-20241022-v1:0",Claude3_Opus:"anthropic.claude-3-opus-20240229-v1:0",Claude3_Sonnet:"anthropic.claude-3-sonnet-20240229-v1:0",Claude3_Haiku:"anthropic.claude-3-haiku-20240307-v1:0",TitanTextG1Express:"amazon.titan-text-express-v1",TitanTextG1Lite:"amazon.titan-text-lite-v1",TitanEmbedG1Text:"amazon.titan-embed-text-v1",TitanImageG1:"amazon.titan-image-generator-v1",JurassicUltra:"ai21.j2-ultra-v1",JurassicMid:"ai21.j2-mid-v1",CommandText:"cohere.command-text-v14",CommandLight:"cohere.command-light-text-v14",EmbedEnglish:"cohere.embed-english-v3",EmbedMultilingual:"cohere.embed-multilingual-v3",Llama3_2_1B:"meta.llama3-2-1b-instruct-v1:0",Llama3_2_3B:"meta.llama3-2-3b-instruct-v1:0",Llama3_2_11B:"meta.llama3-2-11b-instruct-v1:0",Llama3_2_90B:"meta.llama3-2-90b-instruct-v1:0",Llama3_1_8B:"meta.llama3-1-8b-instruct-v1:0",Llama3_1_70B:"meta.llama3-1-70b-instruct-v1:0",Llama3_1_405B:"meta.llama3-1-405b-instruct-v1:0",Mistral7B:"mistral.mistral-7b-instruct-v0:2",Mixtral8x7B:"mistral.mixtral-8x7b-instruct-v0:1",MistralLarge:"mistral.mistral-large-2402-v1:0",StableDiffusionXL:"stability.stable-diffusion-xl-v1"};static ModelGroups={AllClaude:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","anthropic.claude-3-opus-20240229-v1:0","anthropic.claude-3-sonnet-20240229-v1:0","anthropic.claude-3-haiku-20240307-v1:0"],AllTitan:["amazon.titan-text-express-v1","amazon.titan-text-lite-v1","amazon.titan-embed-text-v1","amazon.titan-image-generator-v1"],AllLlama:["meta.llama3-2-1b-instruct-v1:0","meta.llama3-2-3b-instruct-v1:0","meta.llama3-2-11b-instruct-v1:0","meta.llama3-2-90b-instruct-v1:0","meta.llama3-1-8b-instruct-v1:0","meta.llama3-1-70b-instruct-v1:0","meta.llama3-1-405b-instruct-v1:0"],TextModels:["anthropic.claude-3-5-sonnet-20241022-v2:0","anthropic.claude-3-5-haiku-20241022-v1:0","amazon.titan-text-express-v1","meta.llama3-2-11b-instruct-v1:0","mistral.mistral-7b-instruct-v0:2"],EmbeddingModels:["amazon.titan-embed-text-v1","cohere.embed-english-v3","cohere.embed-multilingual-v3"],ImageModels:["amazon.titan-image-generator-v1","stability.stable-diffusion-xl-v1"]}}class jt{static createPostgres(n){return jt.createRDSInstance("postgres","16.2",n)}static createMysql(n){return jt.createRDSInstance("mysql","8.0.35",n)}static createRDSInstance(n,i,s){let{slug:o,environment:c,instanceClass:l="db.t3.micro",allocatedStorage:u=20,storageType:h="gp3",masterUsername:y="admin",masterPassword:f,databaseName:S,subnetIds:b,securityGroupIds:v,encrypted:w=!0,kmsKeyId:E,multiAz:P=!1,backupRetentionDays:R=7,publiclyAccessible:D=!1,enableCloudwatchLogs:x=!0,deletionProtection:I=!0}=s,_=r({slug:o,environment:c,resourceType:`${n}-db`}),B=t(_),W,J;if(b&&b.length>0){let Y=r({slug:o,environment:c,resourceType:"db-subnet-group"});J=t(Y),W={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupName:Y,DBSubnetGroupDescription:`Subnet group for ${_}`,SubnetIds:b,Tags:[{Key:"Name",Value:Y},{Key:"Environment",Value:c}]}}}let K={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:_,DBInstanceClass:l,Engine:n,EngineVersion:i,MasterUsername:y,MasterUserPassword:f,AllocatedStorage:u,StorageType:h,StorageEncrypted:w,MultiAZ:P,BackupRetentionPeriod:R,PubliclyAccessible:D,DeletionProtection:I,Tags:[{Key:"Name",Value:_},{Key:"Environment",Value:c}]}};if(S)K.Properties.DBName=S;if(E)K.Properties.KmsKeyId=E;if(J)K.Properties.DBSubnetGroupName=k.Ref(J);if(v&&v.length>0)K.Properties.VPCSecurityGroups=v;if(x)K.Properties.EnableCloudwatchLogsExports=n==="postgres"?["postgresql"]:["error","general","slowquery"];return{dbInstance:K,subnetGroup:W,logicalId:B,subnetGroupId:J}}static createReadReplica(n,i){let{slug:s,environment:o,instanceClass:c="db.t3.micro",securityGroupIds:l,publiclyAccessible:u=!1}=i,h=r({slug:s,environment:o,resourceType:"db-replica"}),y=t(h),f={Type:"AWS::RDS::DBInstance",Properties:{DBInstanceIdentifier:h,DBInstanceClass:c,SourceDBInstanceIdentifier:k.Ref(n),PubliclyAccessible:u,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:o},{Key:"Type",Value:"ReadReplica"}]}};if(l&&l.length>0)f.Properties.VPCSecurityGroups=l;return{replica:f,logicalId:y}}static createParameterGroup(n,i,s){let{slug:o,environment:c,parameters:l={}}=s,u=r({slug:o,environment:c,resourceType:"db-params"}),h=t(u),y=n==="postgres"?`postgres${i.split(".")[0]}`:`mysql${i.split(".")[0]}.${i.split(".")[1]}`;return{parameterGroup:{Type:"AWS::RDS::DBParameterGroup",Properties:{DBParameterGroupName:u,Description:`Parameter group for ${u}`,Family:y,Parameters:l,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:c}]}},logicalId:h}}static enableBackup(n,i=7){return n.Properties.BackupRetentionPeriod=i,n}static createTable(n){let{slug:i,environment:s,tableName:o,partitionKey:c,sortKey:l,billingMode:u="PAY_PER_REQUEST",readCapacity:h=5,writeCapacity:y=5,streamEnabled:f=!1,streamViewType:S="NEW_AND_OLD_IMAGES",encrypted:b=!0,kmsKeyId:v,pointInTimeRecovery:w=!0,ttlAttribute:E}=n,P=o||r({slug:i,environment:s,resourceType:"table"}),R=t(P),D=[{AttributeName:c.name,AttributeType:c.type}];if(l)D.push({AttributeName:l.name,AttributeType:l.type});let x=[{AttributeName:c.name,KeyType:"HASH"}];if(l)x.push({AttributeName:l.name,KeyType:"RANGE"});let I={Type:"AWS::DynamoDB::Table",Properties:{TableName:P,BillingMode:u,AttributeDefinitions:D,KeySchema:x,Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:s}]}};if(u==="PROVISIONED")I.Properties.ProvisionedThroughput={ReadCapacityUnits:h,WriteCapacityUnits:y};if(f)I.Properties.StreamSpecification={StreamViewType:S};if(b)I.Properties.SSESpecification={SSEEnabled:!0,SSEType:v?"KMS":"AES256",KMSMasterKeyId:v};if(w)I.Properties.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(E)I.Properties.TimeToLiveSpecification={AttributeName:E,Enabled:!0};return{table:I,logicalId:R}}static addGlobalSecondaryIndex(n,i){let{indexName:s,partitionKey:o,sortKey:c,projectionType:l="ALL",nonKeyAttributes:u,readCapacity:h=5,writeCapacity:y=5}=i;if(!n.Properties.AttributeDefinitions.some((b)=>b.AttributeName===o.name))n.Properties.AttributeDefinitions.push({AttributeName:o.name,AttributeType:o.type});if(c&&!n.Properties.AttributeDefinitions.some((b)=>b.AttributeName===c.name))n.Properties.AttributeDefinitions.push({AttributeName:c.name,AttributeType:c.type});let f=[{AttributeName:o.name,KeyType:"HASH"}];if(c)f.push({AttributeName:c.name,KeyType:"RANGE"});let S={IndexName:s,KeySchema:f,Projection:{ProjectionType:l,NonKeyAttributes:l==="INCLUDE"?u:void 0},ProvisionedThroughput:void 0};if(n.Properties.BillingMode==="PROVISIONED")S.ProvisionedThroughput={ReadCapacityUnits:h,WriteCapacityUnits:y};if(!n.Properties.GlobalSecondaryIndexes)n.Properties.GlobalSecondaryIndexes=[];return n.Properties.GlobalSecondaryIndexes.push(S),n}static enableStreams(n,i="NEW_AND_OLD_IMAGES"){return n.Properties.StreamSpecification={StreamViewType:i},n}static InstanceClasses={T3_Micro:"db.t3.micro",T3_Small:"db.t3.small",T3_Medium:"db.t3.medium",T3_Large:"db.t3.large",T4g_Micro:"db.t4g.micro",T4g_Small:"db.t4g.small",T4g_Medium:"db.t4g.medium",M5_Large:"db.m5.large",M5_XLarge:"db.m5.xlarge",M5_2XLarge:"db.m5.2xlarge",R5_Large:"db.r5.large",R5_XLarge:"db.r5.xlarge",R5_2XLarge:"db.r5.2xlarge"}}class go{static createRedis(n){let{slug:i,environment:s,nodeType:o="cache.t3.micro",engineVersion:c="7.1",port:l=6379,subnetIds:u,securityGroupIds:h,numCacheClusters:y=2,automaticFailover:f=!0,multiAz:S=!0,clusterMode:b=!1,numNodeGroups:v=1,replicasPerNodeGroup:w=1,atRestEncryption:E=!0,transitEncryption:P=!0,authToken:R,kmsKeyId:D,snapshotRetentionDays:x=7,snapshotWindow:I,maintenanceWindow:_}=n,B=r({slug:i,environment:s,resourceType:"redis"}),W=t(B),J,K;if(u&&u.length>0){let Z=r({slug:i,environment:s,resourceType:"cache-subnet-group"});K=t(Z),J={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:Z,Description:`Subnet group for ${B}`,SubnetIds:u,Tags:[{Key:"Name",Value:Z},{Key:"Environment",Value:s}]}}}let Y={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:B,ReplicationGroupDescription:`Redis cluster for ${i} ${s}`,Engine:"redis",EngineVersion:c,CacheNodeType:o,Port:l,AutomaticFailoverEnabled:f,MultiAZEnabled:S,AtRestEncryptionEnabled:E,TransitEncryptionEnabled:P,SnapshotRetentionLimit:x,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:B},{Key:"Environment",Value:s}]}};if(b)Y.Properties.NumNodeGroups=v,Y.Properties.ReplicasPerNodeGroup=w;else Y.Properties.NumCacheClusters=y;if(R)Y.Properties.AuthToken=R;if(D)Y.Properties.KmsKeyId=D;if(K)Y.Properties.CacheSubnetGroupName=k.Ref(K);if(h&&h.length>0)Y.Properties.SecurityGroupIds=h;if(I)Y.Properties.SnapshotWindow=I;if(_)Y.Properties.PreferredMaintenanceWindow=_;return{replicationGroup:Y,subnetGroup:J,logicalId:W,subnetGroupId:K}}static createMemcached(n){let{slug:i,environment:s,nodeType:o="cache.t3.micro",engineVersion:c="1.6.22",port:l=11211,numCacheNodes:u=2,subnetIds:h,securityGroupIds:y,azMode:f="cross-az",preferredAzs:S,maintenanceWindow:b}=n,v=r({slug:i,environment:s,resourceType:"memcached"}),w=t(v),E,P;if(h&&h.length>0){let D=r({slug:i,environment:s,resourceType:"cache-subnet-group"});P=t(D),E={Type:"AWS::ElastiCache::SubnetGroup",Properties:{CacheSubnetGroupName:D,Description:`Subnet group for ${v}`,SubnetIds:h,Tags:[{Key:"Name",Value:D},{Key:"Environment",Value:s}]}}}let R={Type:"AWS::ElastiCache::CacheCluster",Properties:{ClusterName:v,CacheNodeType:o,Engine:"memcached",EngineVersion:c,NumCacheNodes:u,Port:l,AZMode:f,AutoMinorVersionUpgrade:!0,Tags:[{Key:"Name",Value:v},{Key:"Environment",Value:s}]}};if(P)R.Properties.CacheSubnetGroupName=k.Ref(P);if(y&&y.length>0)R.Properties.VpcSecurityGroupIds=y;if(S&&S.length>0)R.Properties.PreferredAvailabilityZones=S;if(b)R.Properties.PreferredMaintenanceWindow=b;return{cluster:R,subnetGroup:E,logicalId:w,subnetGroupId:P}}static enableClusterMode(n,i=3,s=2){return delete n.Properties.NumCacheClusters,n.Properties.NumNodeGroups=i,n.Properties.ReplicasPerNodeGroup=s,n}static createRedisParameterGroup(n,i){let{slug:s,environment:o,parameters:c={}}=i,l=r({slug:s,environment:o,resourceType:"redis-params"}),u=t(l);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`redis${n.split(".")[0]}.x`,Description:`Parameter group for ${l}`,Properties:c,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:o}]}},logicalId:u}}static createMemcachedParameterGroup(n,i){let{slug:s,environment:o,parameters:c={}}=i,l=r({slug:s,environment:o,resourceType:"memcached-params"}),u=t(l);return{parameterGroup:{Type:"AWS::ElastiCache::ParameterGroup",Properties:{CacheParameterGroupFamily:`memcached${n.split(".")[0]}.${n.split(".")[1]}`,Description:`Parameter group for ${l}`,Properties:c,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:o}]}},logicalId:u}}static NodeTypes={T3_Micro:"cache.t3.micro",T3_Small:"cache.t3.small",T3_Medium:"cache.t3.medium",T4g_Micro:"cache.t4g.micro",T4g_Small:"cache.t4g.small",T4g_Medium:"cache.t4g.medium",M5_Large:"cache.m5.large",M5_XLarge:"cache.m5.xlarge",M5_2XLarge:"cache.m5.2xlarge",R5_Large:"cache.r5.large",R5_XLarge:"cache.r5.xlarge",R5_2XLarge:"cache.r5.2xlarge",R5_4XLarge:"cache.r5.4xlarge",R6g_Large:"cache.r6g.large",R6g_XLarge:"cache.r6g.xlarge",R6g_2XLarge:"cache.r6g.2xlarge"}}class ee{static createUser(n){let{slug:i,environment:s,userName:o,groups:c,managedPolicyArns:l}=n,u=o||r({slug:i,environment:s,resourceType:"user"}),h=t(u),y={Type:"AWS::IAM::User",Properties:{UserName:u,Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s}]}};if(c&&c.length>0)y.Properties.Groups=c;if(l&&l.length>0)y.Properties.ManagedPolicyArns=l;return{user:y,logicalId:h}}static createRole(n){let{slug:i,environment:s,roleName:o,servicePrincipal:c,awsPrincipal:l,managedPolicyArns:u}=n,h=o||r({slug:i,environment:s,resourceType:"role"}),y=t(h),f={};if(c)f.Service=c;if(l)f.AWS=l;let S={Type:"AWS::IAM::Role",Properties:{RoleName:h,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:f,Action:"sts:AssumeRole"}]},Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(u&&u.length>0)S.Properties.ManagedPolicyArns=u;return{role:S,logicalId:y}}static createGroup(n){let{slug:i,environment:s,groupName:o,managedPolicyArns:c}=n,l=o||r({slug:i,environment:s,resourceType:"group"}),u=t(l),h={Type:"AWS::IAM::Group",Properties:{GroupName:l}};if(c&&c.length>0)h.Properties.ManagedPolicyArns=c;return{group:h,logicalId:u}}static createPolicy(n){let{slug:i,environment:s,policyName:o,description:c,statements:l}=n,u=o||r({slug:i,environment:s,resourceType:"policy"}),h=t(u),y=l.map((f)=>({Sid:f.sid,Effect:f.effect||"Allow",Action:f.actions,Resource:f.resources,Condition:f.conditions}));return{policy:{Type:"AWS::IAM::ManagedPolicy",Properties:{ManagedPolicyName:u,Description:c||`Managed policy for ${u}`,PolicyDocument:{Version:"2012-10-17",Statement:y}}},logicalId:h}}static attachPolicyToRole(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static attachPolicyToUser(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static attachPolicyToGroup(n,i){if(!n.Properties.ManagedPolicyArns)n.Properties.ManagedPolicyArns=[];if(!n.Properties.ManagedPolicyArns.includes(i))n.Properties.ManagedPolicyArns.push(i);return n}static addInlinePolicyToRole(n,i,s){if(!n.Properties.Policies)n.Properties.Policies=[];let o=s.map((c)=>({Effect:c.effect||"Allow",Action:c.actions,Resource:c.resources}));return n.Properties.Policies.push({PolicyName:i,PolicyDocument:{Version:"2012-10-17",Statement:o}}),n}static addInlinePolicyToUser(n,i,s){if(!n.Properties.Policies)n.Properties.Policies=[];let o=s.map((c)=>({Effect:c.effect||"Allow",Action:c.actions,Resource:c.resources}));return n.Properties.Policies.push({PolicyName:i,PolicyDocument:{Version:"2012-10-17",Statement:o}}),n}static createAccessKey(n,i){let{slug:s,environment:o,status:c="Active"}=i,l=r({slug:s,environment:o,resourceType:"access-key"}),u=t(l);return{accessKey:{Type:"AWS::IAM::AccessKey",Properties:{UserName:k.Ref(n),Status:c}},logicalId:u}}static createInstanceProfile(n,i){let{slug:s,environment:o,profileName:c}=i,l=c||r({slug:s,environment:o,resourceType:"instance-profile"}),u=t(l);return{instanceProfile:{Type:"AWS::IAM::InstanceProfile",Properties:{InstanceProfileName:l,Roles:[k.Ref(n)]}},logicalId:u}}static ManagedPolicies={AdministratorAccess:"arn:aws:iam::aws:policy/AdministratorAccess",PowerUserAccess:"arn:aws:iam::aws:policy/PowerUserAccess",ReadOnlyAccess:"arn:aws:iam::aws:policy/ReadOnlyAccess",S3FullAccess:"arn:aws:iam::aws:policy/AmazonS3FullAccess",S3ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",DynamoDBFullAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",DynamoDBReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess",RDSFullAccess:"arn:aws:iam::aws:policy/AmazonRDSFullAccess",RDSReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonRDSReadOnlyAccess",LambdaFullAccess:"arn:aws:iam::aws:policy/AWSLambda_FullAccess",LambdaReadOnlyAccess:"arn:aws:iam::aws:policy/AWSLambda_ReadOnlyAccess",LambdaBasicExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",LambdaVPCAccessExecutionRole:"arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole",EC2FullAccess:"arn:aws:iam::aws:policy/AmazonEC2FullAccess",EC2ReadOnlyAccess:"arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess",EC2ContainerRegistryReadOnly:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly",EC2ContainerRegistryPowerUser:"arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser",ECSTaskExecutionRole:"arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",ECSFullAccess:"arn:aws:iam::aws:policy/AmazonECS_FullAccess",CloudWatchFullAccess:"arn:aws:iam::aws:policy/CloudWatchFullAccess",CloudWatchLogsFullAccess:"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess",SESFullAccess:"arn:aws:iam::aws:policy/AmazonSESFullAccess",SNSFullAccess:"arn:aws:iam::aws:policy/AmazonSNSFullAccess",SQSFullAccess:"arn:aws:iam::aws:policy/AmazonSQSFullAccess",SecretsManagerReadWrite:"arn:aws:iam::aws:policy/SecretsManagerReadWrite"};static ServicePrincipals={Lambda:"lambda.amazonaws.com",EC2:"ec2.amazonaws.com",ECS:"ecs.amazonaws.com",ECSTaskExecution:"ecs-tasks.amazonaws.com",APIGateway:"apigateway.amazonaws.com",Events:"events.amazonaws.com",States:"states.amazonaws.com",CodeBuild:"codebuild.amazonaws.com",CodeDeploy:"codedeploy.amazonaws.com",CloudFormation:"cloudformation.amazonaws.com"};static createCiCdUser(n){let{slug:i,environment:s,permissions:o,createAccessKey:c=!0}=n,l={},u=[];if(o.s3Buckets&&o.s3Buckets.length>0)u.push({sid:"S3Access",actions:["s3:GetBucketLocation","s3:ListBucket","s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucketMultipartUploads","s3:AbortMultipartUpload"],resources:[...o.s3Buckets,...o.s3Buckets.map((w)=>`${w}/*`)]});if(o.cloudFrontDistributions&&o.cloudFrontDistributions.length>0)u.push({sid:"CloudFrontAccess",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations","cloudfront:GetDistribution"],resources:o.cloudFrontDistributions});if(o.ecrRepositories&&o.ecrRepositories.length>0)u.push({sid:"ECRAccess",actions:["ecr:GetAuthorizationToken","ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:GetRepositoryPolicy","ecr:DescribeRepositories","ecr:ListImages","ecr:DescribeImages","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:o.ecrRepositories}),u.push({sid:"ECRLogin",actions:["ecr:GetAuthorizationToken"],resources:"*"});if(o.ecsServices&&o.ecsServices.length>0)u.push({sid:"ECSAccess",actions:["ecs:DescribeServices","ecs:DescribeTaskDefinition","ecs:DescribeTasks","ecs:ListTasks","ecs:RegisterTaskDefinition","ecs:UpdateService","ecs:RunTask","ecs:StopTask"],resources:o.ecsServices}),u.push({sid:"ECSTaskDefinitions",actions:["ecs:RegisterTaskDefinition","ecs:DeregisterTaskDefinition"],resources:"*"}),u.push({sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}});if(o.cloudFormationStacks&&o.cloudFormationStacks.length>0)u.push({sid:"CloudFormationAccess",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DeleteStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:DescribeStackResources","cloudformation:GetTemplate","cloudformation:ListStackResources","cloudformation:ValidateTemplate"],resources:o.cloudFormationStacks});if(o.lambdaFunctions&&o.lambdaFunctions.length>0)u.push({sid:"LambdaAccess",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion","lambda:UpdateAlias","lambda:CreateAlias"],resources:o.lambdaFunctions});if(o.secretsManagerSecrets&&o.secretsManagerSecrets.length>0)u.push({sid:"SecretsManagerAccess",actions:["secretsmanager:GetSecretValue","secretsmanager:DescribeSecret"],resources:o.secretsManagerSecrets});let{policy:h,logicalId:y}=ee.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cicd-policy"}),description:`CI/CD deployment policy for ${i} (${s})`,statements:u});l[y]=h;let{user:f,logicalId:S}=ee.createUser({slug:i,environment:s,userName:r({slug:i,environment:s,resourceType:"cicd-user"}),managedPolicyArns:[k.Ref(y)]});l[S]=f;let b,v;if(c){let w=ee.createAccessKey(S,{slug:i,environment:s});b=w.accessKey,v=w.logicalId,l[v]=b}return{user:f,accessKey:b,policy:h,userLogicalId:S,accessKeyLogicalId:v,policyLogicalId:y,resources:l}}static createCrossAccountRole(n){let{slug:i,environment:s,trustedAccountIds:o,externalId:c,permissions:l,maxSessionDuration:u=3600}=n,h={},{policy:y,logicalId:f}=ee.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cross-account-policy"}),description:`Cross-account access policy for ${i} (${s})`,statements:l});h[f]=y;let S=r({slug:i,environment:s,resourceType:"cross-account-role"}),b=t(S),v={};if(c)v.StringEquals={"sts:ExternalId":c};let w={Type:"AWS::IAM::Role",Properties:{RoleName:S,MaxSessionDuration:u,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:o.map((E)=>`arn:aws:iam::${E}:root`)},Action:"sts:AssumeRole",...Object.keys(v).length>0?{Condition:v}:{}}]},ManagedPolicyArns:[k.Ref(f)],Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:s},{Key:"Purpose",Value:"Cross-Account Access"}]}};return h[b]=w,{role:w,policy:y,roleLogicalId:b,policyLogicalId:f,resources:h}}static createCliUser(n){let{slug:i,environment:s,permissions:o="readonly"}=n,c={},l=[],u=[];switch(o){case"readonly":u=[ee.ManagedPolicies.ReadOnlyAccess];break;case"deploy":l=[{sid:"S3Deploy",actions:["s3:*"],resources:"*"},{sid:"CloudFrontDeploy",actions:["cloudfront:*"],resources:"*"},{sid:"ECSDeploy",actions:["ecs:*"],resources:"*"},{sid:"ECRDeploy",actions:["ecr:*"],resources:"*"},{sid:"LambdaDeploy",actions:["lambda:*"],resources:"*"},{sid:"CloudFormationDeploy",actions:["cloudformation:*"],resources:"*"},{sid:"IAMPassRole",actions:["iam:PassRole"],resources:"*"}];break;case"admin":u=[ee.ManagedPolicies.AdministratorAccess];break}let h,y;if(l.length>0){let w=ee.createPolicy({slug:i,environment:s,policyName:r({slug:i,environment:s,resourceType:"cli-policy"}),description:`CLI access policy for ${i} (${s})`,statements:l});h=w.policy,y=w.logicalId,c[y]=h,u=[k.Ref(y)]}let{user:f,logicalId:S}=ee.createUser({slug:i,environment:s,userName:r({slug:i,environment:s,resourceType:"cli-user"}),managedPolicyArns:u});c[S]=f;let{accessKey:b,logicalId:v}=ee.createAccessKey(S,{slug:i,environment:s});return c[v]=b,{user:f,accessKey:b,policy:h,userLogicalId:S,accessKeyLogicalId:v,policyLogicalId:y,resources:c}}static CiCdPolicies={s3Deployment:(n)=>[{sid:"S3ListBuckets",actions:["s3:ListBucket","s3:GetBucketLocation"],resources:n},{sid:"S3Objects",actions:["s3:GetObject","s3:PutObject","s3:DeleteObject"],resources:n.map((i)=>`${i}/*`)}],cloudFrontInvalidation:(n)=>[{sid:"CloudFrontInvalidation",actions:["cloudfront:CreateInvalidation","cloudfront:GetInvalidation","cloudfront:ListInvalidations"],resources:n}],ecsDeployment:()=>[{sid:"ECSServices",actions:["ecs:DescribeServices","ecs:UpdateService","ecs:DescribeTaskDefinition","ecs:RegisterTaskDefinition"],resources:"*"},{sid:"ECSPassRole",actions:["iam:PassRole"],resources:"*",conditions:{StringLike:{"iam:PassedToService":"ecs-tasks.amazonaws.com"}}}],ecrPush:(n)=>[{sid:"ECRAuth",actions:["ecr:GetAuthorizationToken"],resources:"*"},{sid:"ECRPush",actions:["ecr:BatchCheckLayerAvailability","ecr:GetDownloadUrlForLayer","ecr:BatchGetImage","ecr:InitiateLayerUpload","ecr:UploadLayerPart","ecr:CompleteLayerUpload","ecr:PutImage"],resources:n}],lambdaDeployment:(n)=>[{sid:"LambdaDeploy",actions:["lambda:GetFunction","lambda:UpdateFunctionCode","lambda:UpdateFunctionConfiguration","lambda:PublishVersion"],resources:n}],cloudFormationDeployment:(n)=>[{sid:"CloudFormationDeploy",actions:["cloudformation:CreateStack","cloudformation:UpdateStack","cloudformation:DescribeStacks","cloudformation:DescribeStackEvents","cloudformation:GetTemplate"],resources:n}]}}class Od{static createRestApi(n){let{slug:i,environment:s,name:o,description:c,endpointType:l="REGIONAL",binaryMediaTypes:u,compressionSize:h}=n,y=o||r({slug:i,environment:s,resourceType:"rest-api"}),f=t(y),S={Type:"AWS::ApiGateway::RestApi",Properties:{Name:y,Description:c||`REST API for ${i} ${s}`,EndpointConfiguration:{Types:[l]},Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s}]}};if(u&&u.length>0)S.Properties.BinaryMediaTypes=u;if(h!==void 0)S.Properties.MinimumCompressionSize=h;return{restApi:S,logicalId:f}}static createHttpApi(n){let{slug:i,environment:s,name:o,description:c,corsEnabled:l=!0,corsOrigins:u=["*"],corsMethods:h=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],corsHeaders:y=["*"],corsMaxAge:f=86400,corsAllowCredentials:S=!1}=n,b=o||r({slug:i,environment:s,resourceType:"http-api"}),v=t(b),w={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:b,Description:c||`HTTP API for ${i} ${s}`,ProtocolType:"HTTP",Tags:{Name:b,Environment:s}}};if(l)w.Properties.CorsConfiguration={AllowOrigins:u,AllowMethods:h,AllowHeaders:y,MaxAge:f,AllowCredentials:S};return{httpApi:w,logicalId:v}}static createWebSocketApi(n){let{slug:i,environment:s,name:o,description:c}=n,l=o||r({slug:i,environment:s,resourceType:"ws-api"}),u=t(l);return{webSocketApi:{Type:"AWS::ApiGatewayV2::Api",Properties:{Name:l,Description:c||`WebSocket API for ${i} ${s}`,ProtocolType:"WEBSOCKET",Tags:{Name:l,Environment:s}}},logicalId:u}}static createDeployment(n,i){let{slug:s,environment:o,description:c}=i,l=r({slug:s,environment:o,resourceType:"api-deployment"}),u=t(l);return{deployment:{Type:"AWS::ApiGateway::Deployment",Properties:{RestApiId:k.Ref(n),Description:c||`Deployment for ${l}`}},logicalId:u}}static createStage(n,i,s){let{slug:o,environment:c,stageName:l,description:u,cacheEnabled:h=!1,cacheSize:y="0.5",variables:f,throttling:S}=s,b=r({slug:o,environment:c,resourceType:"api-stage"}),v=t(b),w={Type:"AWS::ApiGateway::Stage",Properties:{StageName:l||c,RestApiId:k.Ref(n),DeploymentId:k.Ref(i),Description:u,CacheClusterEnabled:h,Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:c}]}};if(h)w.Properties.CacheClusterSize=y;if(f)w.Properties.Variables=f;if(S)w.Properties.MethodSettings=[{HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:S.burstLimit,ThrottlingRateLimit:S.rateLimit}];return{stage:w,logicalId:v}}static createAuthorizer(n,i){let{slug:s,environment:o,name:c,type:l,functionArn:u,identitySource:h,userPoolArns:y,ttl:f=300}=i,S=c||r({slug:s,environment:o,resourceType:"api-authorizer"}),b=t(S),v={Type:"AWS::ApiGateway::Authorizer",Properties:{Name:S,Type:l,RestApiId:k.Ref(n),AuthorizerResultTtlInSeconds:f}};if(l==="TOKEN"||l==="REQUEST"){if(!u)throw Error("Lambda authorizer requires functionArn");v.Properties.AuthorizerUri=u,v.Properties.IdentitySource=h||"method.request.header.Authorization"}if(l==="COGNITO_USER_POOLS"){if(!y||y.length===0)throw Error("Cognito authorizer requires userPoolArns");v.Properties.ProviderARNs=y,v.Properties.IdentitySource=h||"method.request.header.Authorization"}return{authorizer:v,logicalId:b}}static setCors(n,i={}){let{origins:s=["*"],methods:o=["GET","POST","PUT","PATCH","DELETE","OPTIONS"],headers:c=["*"],maxAge:l=86400,allowCredentials:u=!1}=i;return n.Properties.CorsConfiguration={AllowOrigins:s,AllowMethods:o,AllowHeaders:c,MaxAge:l,AllowCredentials:u},n}static addThrottling(n,i=5000,s=1e4){if(!n.Properties.MethodSettings)n.Properties.MethodSettings=[];return n.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",ThrottlingBurstLimit:i,ThrottlingRateLimit:s}),n}static enableCaching(n,i="0.5",s=300){if(n.Properties.CacheClusterEnabled=!0,n.Properties.CacheClusterSize=i,!n.Properties.MethodSettings)n.Properties.MethodSettings=[];return n.Properties.MethodSettings.push({HttpMethod:"*",ResourcePath:"/*",CachingEnabled:!0,CacheTtlInSeconds:s}),n}static CacheSizes={Small:"0.5",Medium:"1.6",Large:"6.1",XLarge:"13.5",XXLarge:"28.4",XXXLarge:"58.2",Huge:"118",Massive:"237"};static ThrottlingPresets={Light:{burstLimit:100,rateLimit:50},Medium:{burstLimit:500,rateLimit:250},Heavy:{burstLimit:2000,rateLimit:1000},Default:{burstLimit:5000,rateLimit:1e4}}}class te{static createTopic(n){let{slug:i,environment:s,topicName:o,displayName:c,encrypted:l=!1,kmsKeyId:u}=n,h=o||r({slug:i,environment:s,resourceType:"topic"}),y=t(h),f={Type:"AWS::SNS::Topic",Properties:{TopicName:h,DisplayName:c||h,Tags:[{Key:"Name",Value:h},{Key:"Environment",Value:s}]}};if(l&&u)f.Properties.KmsMasterKeyId=u;return{topic:f,logicalId:y}}static subscribe(n,i){let{slug:s,environment:o,protocol:c,endpoint:l,filterPolicy:u,rawMessageDelivery:h=!1}=i,y=r({slug:s,environment:o,resourceType:"subscription"}),f=l.replace(/[^a-zA-Z0-9]/g,""),S=f.length>12?f.slice(-12):f,b=t(`${y}-${c}-${S}`),v={Type:"AWS::SNS::Subscription",Properties:{TopicArn:k.Ref(n),Protocol:c,Endpoint:l,RawMessageDelivery:h}};if(u)v.Properties.FilterPolicy=u;return{subscription:v,logicalId:b}}static subscribeEmail(n,i,s){return te.subscribe(n,{...s,protocol:"email",endpoint:i})}static subscribeLambda(n,i,s){return te.subscribe(n,{...s,protocol:"lambda",endpoint:i,rawMessageDelivery:!0})}static subscribeSqs(n,i,s){return te.subscribe(n,{...s,protocol:"sqs",endpoint:i})}static subscribeHttp(n,i,s){let o=i.startsWith("https://")?"https":"http";return te.subscribe(n,{...s,protocol:o,endpoint:i})}static subscribeSms(n,i,s){return te.subscribe(n,{...s,protocol:"sms",endpoint:i})}static setTopicPolicy(n,i){let{slug:s,environment:o,allowedPrincipals:c,allowedServices:l,actions:u="SNS:Publish"}=i,h=r({slug:s,environment:o,resourceType:"topic-policy"}),y=t(h),f={};if(c)f.AWS=c;if(l)f.Service=l;return{policy:{Type:"AWS::SNS::TopicPolicy",Properties:{Topics:[k.Ref(n)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:f,Action:u,Resource:k.Ref(n)}]}}},logicalId:y}}static allowCloudWatchAlarms(n,i){return te.setTopicPolicy(n,{...i,allowedServices:"cloudwatch.amazonaws.com",actions:"SNS:Publish"})}static allowEventBridge(n,i){return te.setTopicPolicy(n,{...i,allowedServices:"events.amazonaws.com",actions:"SNS:Publish"})}static allowS3(n,i){return te.setTopicPolicy(n,{...i,allowedServices:"s3.amazonaws.com",actions:"SNS:Publish"})}static enableEncryption(n,i){if(!n.Properties)n.Properties={};return n.Properties.KmsMasterKeyId=i,n}static addInlineSubscription(n,i,s){if(!n.Properties)n.Properties={};if(!n.Properties.Subscription)n.Properties.Subscription=[];return n.Properties.Subscription.push({Protocol:i,Endpoint:s}),n}static FilterPolicies={eventType:(n)=>({eventType:n}),status:(n)=>({status:n}),numericRange:(n,i,s)=>({[n]:[{numeric:[">=",i,"<=",s]}]}),prefix:(n,i)=>({[n]:[{prefix:i}]}),and:(...n)=>Object.assign({},...n),exists:(n,i)=>({[n]:[{exists:i}]})};static UseCases={createAlertTopic:(n)=>te.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-alerts`,displayName:n.displayName||"Alert Notifications"}),createEventFanout:(n)=>te.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-events`,displayName:n.displayName||"Event Fanout"}),createNotificationTopic:(n)=>te.createTopic({...n,topicName:n.topicName||`${n.slug}-${n.environment}-notifications`,displayName:n.displayName||"User Notifications"})}}class lA{static createStateMachine(n){let{slug:i,environment:s,stateMachineName:o,type:c="STANDARD",definition:l,roleArn:u,loggingConfiguration:h,tracingConfiguration:y}=n,f=o||r({slug:i,environment:s,resourceType:"state-machine"}),S=t(f),b,v,w;if(u)w=u;else{let P=r({slug:i,environment:s,resourceType:"state-machine-role"});v=t(P),b={Type:"AWS::IAM::Role",Properties:{RoleName:P,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"states.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:["arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"],Tags:[{Key:"Name",Value:P},{Key:"Environment",Value:s}]}},w=k.GetAtt(v,"Arn")}let E={Type:"AWS::StepFunctions::StateMachine",Properties:{StateMachineName:f,StateMachineType:c,DefinitionString:JSON.stringify(l),RoleArn:w,Tags:[{Key:"Name",Value:f},{Key:"Environment",Value:s}]}};if(h)E.Properties.LoggingConfiguration={Level:h.level,IncludeExecutionData:h.includeExecutionData,Destinations:h.destinations?.map((P)=>({CloudWatchLogsLogGroup:{LogGroupArn:P}}))};if(y)E.Properties.TracingConfiguration={Enabled:y.enabled};return{stateMachine:E,logicalId:S,role:b,roleLogicalId:v}}static createLambdaTask(n,i){return{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Parameters:{FunctionName:n,Payload:i?.parameters||{"Input.$":"$"}},ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createDynamoDBTask(n,i,s,o){return{Type:"Task",Resource:{GetItem:"arn:aws:states:::dynamodb:getItem",PutItem:"arn:aws:states:::dynamodb:putItem",UpdateItem:"arn:aws:states:::dynamodb:updateItem",DeleteItem:"arn:aws:states:::dynamodb:deleteItem"}[n],Parameters:{TableName:i,...s},ResultPath:o?.resultPath,Retry:o?.retry,Catch:o?.catch,Next:o?.next,End:o?.end}}static createSNSPublishTask(n,i,s){return{Type:"Task",Resource:"arn:aws:states:::sns:publish",Parameters:{TopicArn:n,Message:i},ResultPath:s?.resultPath,Retry:s?.retry,Catch:s?.catch,Next:s?.next,End:s?.end}}static createSQSSendMessageTask(n,i,s){return{Type:"Task",Resource:"arn:aws:states:::sqs:sendMessage",Parameters:{QueueUrl:n,MessageBody:i},ResultPath:s?.resultPath,Retry:s?.retry,Catch:s?.catch,Next:s?.next,End:s?.end}}static createPassState(n){return{Type:"Pass",Result:n?.result,ResultPath:n?.resultPath,Parameters:n?.parameters,Next:n?.next,End:n?.end}}static createWaitState(n){return{Type:"Wait",Seconds:n.seconds,Timestamp:n.timestamp,SecondsPath:n.secondsPath,TimestampPath:n.timestampPath,Next:n.next,End:n.end}}static createChoiceState(n,i){return{Type:"Choice",Choices:n,Default:i}}static createParallelState(n,i){return{Type:"Parallel",Branches:n,ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createMapState(n,i){return{Type:"Map",ItemsPath:i?.itemsPath||"$.items",Iterator:n,MaxConcurrency:i?.maxConcurrency,ResultPath:i?.resultPath,Retry:i?.retry,Catch:i?.catch,Next:i?.next,End:i?.end}}static createSucceedState(){return{Type:"Succeed"}}static createFailState(n,i){return{Type:"Fail",Error:n,Cause:i}}static RetryPolicies={standard:()=>({ErrorEquals:["States.ALL"],IntervalSeconds:2,MaxAttempts:3,BackoffRate:2}),aggressive:()=>({ErrorEquals:["States.TaskFailed","States.Timeout"],IntervalSeconds:1,MaxAttempts:5,BackoffRate:1.5}),custom:(n,i,s,o)=>({ErrorEquals:n,IntervalSeconds:i,MaxAttempts:s,BackoffRate:o})};static CatchPolicies={all:(n,i)=>({ErrorEquals:["States.ALL"],Next:n,ResultPath:i||"$.error"}),specific:(n,i,s)=>({ErrorEquals:n,Next:i,ResultPath:s||"$.error"})};static Patterns={sequential:(n,i,s)=>{let o={};return s.forEach((c,l)=>{let u=l===s.length-1;o[c.name]={...c.state,Next:u?void 0:s[l+1].name,End:u}}),{Comment:"Sequential workflow",StartAt:s[0].name,States:o}},fanout:(n,i,s)=>({Comment:"Fan-out workflow",StartAt:"Parallel",States:{Parallel:{Type:"Parallel",Branches:s.map((o)=>o.definition),End:!0}}}),map:(n,i,s,o)=>({Comment:"Map workflow",StartAt:"Map",States:{Map:{Type:"Map",ItemsPath:"$.items",Iterator:s,MaxConcurrency:o,End:!0}}}),withErrorHandling:(n,i,s,o)=>({Comment:"Workflow with error handling",StartAt:"Main",States:{Main:{...s,Catch:[{ErrorEquals:["States.ALL"],Next:"ErrorHandler"}],Next:"Success"},ErrorHandler:o,Success:{Type:"Succeed"}}})}}class mo{static createAlarm(n){let{slug:i,environment:s,alarmName:o,metricName:c,namespace:l,statistic:u="Average",period:h=300,evaluationPeriods:y=1,threshold:f,comparisonOperator:S,treatMissingData:b="notBreaching",actionsEnabled:v=!0,alarmActions:w,okActions:E,insufficientDataActions:P,dimensions:R,unit:D,datapointsToAlarm:x}=n,I=o||r({slug:i,environment:s,resourceType:"alarm"}),_=t(I),B={Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:I,MetricName:c,Namespace:l,Statistic:u,Period:h,EvaluationPeriods:y,Threshold:f,ComparisonOperator:S,TreatMissingData:b,ActionsEnabled:v}};if(w&&w.length>0)B.Properties.AlarmActions=w;if(E&&E.length>0)B.Properties.OKActions=E;if(P&&P.length>0)B.Properties.InsufficientDataActions=P;if(R)B.Properties.Dimensions=Object.entries(R).map(([W,J])=>({Name:W,Value:J}));if(D)B.Properties.Unit=D;if(x!==void 0)B.Properties.DatapointsToAlarm=x;return{alarm:B,logicalId:_}}static createCompositeAlarm(n){let{slug:i,environment:s,alarmName:o,alarmRule:c,actionsEnabled:l=!0,alarmActions:u,okActions:h,insufficientDataActions:y}=n,f=o||r({slug:i,environment:s,resourceType:"composite-alarm"}),S=t(f),b={Type:"AWS::CloudWatch::CompositeAlarm",Properties:{AlarmName:f,AlarmRule:c,ActionsEnabled:l}};if(u&&u.length>0)b.Properties.AlarmActions=u;if(h&&h.length>0)b.Properties.OKActions=h;if(y&&y.length>0)b.Properties.InsufficientDataActions=y;return{alarm:b,logicalId:S}}static createDashboard(n){let{slug:i,environment:s,dashboardName:o,widgets:c}=n,l=o||r({slug:i,environment:s,resourceType:"dashboard"}),u=t(l),h={widgets:c.map((y)=>({type:y.type,x:y.x,y:y.y,width:y.width,height:y.height,properties:y.properties}))};return{dashboard:{Type:"AWS::CloudWatch::Dashboard",Properties:{DashboardName:l,DashboardBody:JSON.stringify(h)}},logicalId:u}}static createLogGroup(n){let{slug:i,environment:s,logGroupName:o,retentionInDays:c,kmsKeyId:l}=n,u=o||r({slug:i,environment:s,resourceType:"log-group"}),h=t(u),y={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:u}};if(c!==void 0)y.Properties.RetentionInDays=c;if(l)y.Properties.KmsKeyId=l;return{logGroup:y,logicalId:h}}static createLogStream(n,i){let{slug:s,environment:o,logStreamName:c}=i,l=c||r({slug:s,environment:o,resourceType:"log-stream"}),u=t(l);return{logStream:{Type:"AWS::Logs::LogStream",Properties:{LogGroupName:k.Ref(n),LogStreamName:l}},logicalId:u}}static createMetricFilter(n,i){let{slug:s,environment:o,filterName:c,filterPattern:l,metricTransformations:u}=i,h=c||r({slug:s,environment:o,resourceType:"metric-filter"}),y=t(h);return{metricFilter:{Type:"AWS::Logs::MetricFilter",Properties:{LogGroupName:k.Ref(n),FilterPattern:l,MetricTransformations:u.map((f)=>({MetricName:f.metricName,MetricNamespace:f.metricNamespace,MetricValue:f.metricValue,DefaultValue:f.defaultValue,Unit:f.unit}))}},logicalId:y}}static AlarmTypes={highCpu:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-cpu`,metricName:"CPUUtilization",namespace:"AWS/EC2",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0}),highMemory:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-memory`,metricName:"MemoryUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0}),highDisk:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-high-disk`,metricName:"DiskSpaceUtilization",namespace:"System/Linux",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s,Filesystem:"/dev/xvda1",MountPath:"/"},alarmActions:c?[c]:void 0}),lambdaErrors:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-lambda-errors`,metricName:"Errors",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:s},alarmActions:c?[c]:void 0}),lambdaThrottles:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-lambda-throttles`,metricName:"Throttles",namespace:"AWS/Lambda",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{FunctionName:s},alarmActions:c?[c]:void 0}),apiGateway5xxErrors:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-api-5xx-errors`,metricName:"5XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:s},alarmActions:c?[c]:void 0}),apiGateway4xxErrors:(n,i,s,o=50,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-api-4xx-errors`,metricName:"4XXError",namespace:"AWS/ApiGateway",statistic:"Sum",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApiName:s},alarmActions:c?[c]:void 0}),dynamoDBThrottles:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-dynamodb-throttles`,metricName:"UserErrors",namespace:"AWS/DynamoDB",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{TableName:s},alarmActions:c?[c]:void 0}),rdsCpu:(n,i,s,o=80,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-rds-cpu`,metricName:"CPUUtilization",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{DBInstanceIdentifier:s},alarmActions:c?[c]:void 0}),rdsFreeStorage:(n,i,s,o=5368709120,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-rds-storage`,metricName:"FreeStorageSpace",namespace:"AWS/RDS",statistic:"Average",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"LessThanThreshold",dimensions:{DBInstanceIdentifier:s},alarmActions:c?[c]:void 0,unit:"Bytes"}),sqsQueueDepth:(n,i,s,o=100,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-sqs-depth`,metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",statistic:"Average",period:300,evaluationPeriods:2,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{QueueName:s},alarmActions:c?[c]:void 0}),albUnhealthyTargets:(n,i,s,o,c=1,l)=>({slug:n,environment:i,alarmName:`${n}-${i}-alb-unhealthy`,metricName:"UnHealthyHostCount",namespace:"AWS/ApplicationELB",statistic:"Average",period:300,evaluationPeriods:2,threshold:c,comparisonOperator:"GreaterThanThreshold",dimensions:{LoadBalancer:s,TargetGroup:o},alarmActions:l?[l]:void 0}),sesBounceRate:(n,i,s=5,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-ses-bounce-rate`,metricName:"Reputation.BounceRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:s/100,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),sesComplaintRate:(n,i,s=0.1,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-ses-complaint-rate`,metricName:"Reputation.ComplaintRate",namespace:"AWS/SES",statistic:"Average",period:3600,evaluationPeriods:1,threshold:s/100,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),smsDeliveryFailure:(n,i,s,o=10,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-sms-delivery-failure`,metricName:"DirectSendMessagePermanentFailure",namespace:"AWS/Pinpoint",statistic:"Sum",period:300,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{ApplicationId:s},alarmActions:c?[c]:void 0}),smsSpendLimit:(n,i,s=100,o)=>({slug:n,environment:i,alarmName:`${n}-${i}-sms-spend-limit`,metricName:"DirectSendMessageSpend",namespace:"AWS/Pinpoint",statistic:"Sum",period:86400,evaluationPeriods:1,threshold:s,comparisonOperator:"GreaterThanThreshold",alarmActions:o?[o]:void 0}),connectMissedCalls:(n,i,s,o=5,c)=>({slug:n,environment:i,alarmName:`${n}-${i}-connect-missed-calls`,metricName:"MissedCalls",namespace:"AWS/Connect",statistic:"Sum",period:3600,evaluationPeriods:1,threshold:o,comparisonOperator:"GreaterThanThreshold",dimensions:{InstanceId:s},alarmActions:c?[c]:void 0})};static DashboardWidgets={metric:(n,i,s,o,c,l)=>({type:"metric",x:n,y:i,width:s,height:o,properties:{metrics:c,title:l||"Metrics",region:"us-east-1",period:300}}),text:(n,i,s,o,c)=>({type:"text",x:n,y:i,width:s,height:o,properties:{markdown:c}}),log:(n,i,s,o,c,l)=>({type:"log",x:n,y:i,width:s,height:o,properties:{query:`SOURCE '${c.join("' | SOURCE '")}'
2310
2310
  | fields @timestamp, @message
2311
2311
  | sort @timestamp desc
2312
2312
  | limit 20`,region:"us-east-1",title:l||"Logs"}})};static RetentionPeriods={ONE_DAY:1,THREE_DAYS:3,FIVE_DAYS:5,ONE_WEEK:7,TWO_WEEKS:14,ONE_MONTH:30,TWO_MONTHS:60,THREE_MONTHS:90,FOUR_MONTHS:120,FIVE_MONTHS:150,SIX_MONTHS:180,ONE_YEAR:365,THIRTEEN_MONTHS:400,EIGHTEEN_MONTHS:545,TWO_YEARS:731,FIVE_YEARS:1827,TEN_YEARS:3653,NEVER_EXPIRE:void 0};static FilterPatterns={errors:"[time, request_id, event_type = ERROR*, ...]",all:"",jsonField:(n,i)=>`{ $.${n} = "${i}" }`,httpStatus:(n)=>`[..., status_code = ${n}, ...]`,http4xx:"[..., status_code = 4*, ...]",http5xx:"[..., status_code = 5*, ...]"};static createApplicationDashboard(n){let{slug:i,environment:s,region:o="us-east-1",components:c={}}=n,l=[],u=0;if(l.push({type:"text",x:0,y:u,width:24,height:1,properties:{markdown:`# ${i.toUpperCase()} Dashboard (${s})`}}),u+=1,c.ec2InstanceIds&&c.ec2InstanceIds.length>0)l.push({type:"text",x:0,y:u,width:24,height:1,properties:{markdown:"## EC2 Instances"}}),u+=1,l.push({type:"metric",x:0,y:u,width:8,height:6,properties:{title:"CPU Utilization",region:o,metrics:c.ec2InstanceIds.map((h)=>["AWS/EC2","CPUUtilization","InstanceId",h]),period:300,stat:"Average"}}),l.push({type:"metric",x:8,y:u,width:8,height:6,properties:{title:"Network Traffic",region:o,metrics:[...c.ec2InstanceIds.flatMap((h)=>[["AWS/EC2","NetworkIn","InstanceId",h,{label:`${h} In`}],["AWS/EC2","NetworkOut","InstanceId",h,{label:`${h} Out`}]])],period:300,stat:"Sum"}}),l.push({type:"metric",x:16,y:u,width:8,height:6,properties:{title:"Status Checks",region:o,metrics:c.ec2InstanceIds.map((h)=>["AWS/EC2","StatusCheckFailed","InstanceId",h]),period:60,stat:"Maximum"}}),u+=6;if(c.lambdaFunctionNames&&c.lambdaFunctionNames.length>0)l.push({type:"text",x:0,y:u,width:24,height:1,properties:{markdown:"## Lambda Functions"}}),u+=1,l.push({type:"metric",x:0,y:u,width:8,height:6,properties:{title:"Invocations",region:o,metrics:c.lambdaFunctionNames.map((h)=>["AWS/Lambda","Invocations","FunctionName",h]),period:300,stat:"Sum"}}),l.push({type:"metric",x:8,y:u,width:8,height:6,properties:{title:"Duration",region:o,metrics:c.lambdaFunctionNames.map((h)=>["AWS/Lambda","Duration","FunctionName",h]),period:300,stat:"Average"}}),l.push({type:"metric",x:16,y:u,width:8,height:6,properties:{title:"Errors",region:o,metrics:c.lambdaFunctionNames.map((h)=>["AWS/Lambda","Errors","FunctionName",h]),period:300,stat:"Sum"}}),u+=6;if(c.ecsClusterName&&c.ecsServiceName)l.push({type:"text",x:0,y:u,width:24,height:1,properties:{markdown:"## ECS Service"}}),u+=1,l.push({type:"metric",x:0,y:u,width:8,height:6,properties:{title:"CPU Utilization",region:o,metrics:[["AWS/ECS","CPUUtilization","ClusterName",c.ecsClusterName,"ServiceName",c.ecsServiceName]],period:300,stat:"Average"}}),l.push({type:"metric",x:8,y:u,width:8,height:6,properties:{title:"Memory Utilization",region:o,metrics:[["AWS/ECS","MemoryUtilization","ClusterName",c.ecsClusterName,"ServiceName",c.ecsServiceName]],period:300,stat:"Average"}}),l.push({type:"metric",x:16,y:u,width:8,height:6,properties:{title:"Running Tasks",region:o,metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",c.ecsClusterName,"ServiceName",c.ecsServiceName]],period:60,stat:"Average"}}),u+=6;if(c.albName)l.push({type:"text",x:0,y:u,width:24,height:1,properties:{markdown:"## Application Load Balancer"}}),u+=1,l.push({type:"metric",x:0,y:u,width:8,height:6,properties:{title:"Request Count",region:o,metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",c.albName]],period:60,stat:"Sum"}}),l.push({type:"metric",x:8,y:u,width:8,height:6,properties:{title:"Response Time",region:o,metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",c.albName]],period:60,stat:"Average"}}),l.push({type:"metric",x:16,y:u,width:8,height:6,properties:{title:"HTTP Errors",region:o,metrics:[["AWS/ApplicationELB","HTTPCode_Target_4XX_Count","LoadBalancer",c.albName,{label:"4XX"}],["AWS/ApplicationELB","HTTPCode_Target_5XX_Count","LoadBalancer",c.albName,{label:"5XX"}]],period:60,stat:"Sum"}}),u+=6;if(c.rdsInstanceId)l.push({type:"text",x:0,y:u,width:24,height:1,properties:{markdown:"## RDS Database"}}),u+=1,l.push({type:"metric",x:0,y:u,width:8,height:6,properties:{title:"CPU Utilization",region:o,metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",c.rdsInstanceId]],period:300,stat:"Average"}}),l.push({type:"metric",x:8,y:u,width:8,height:6,properties:{title:"Database Connections",region:o,metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",c.rdsInstanceId]],period:60,stat:"Sum"}}),l.push({type:"metric",x:16,y:u,width:8,height:6,properties:{title:"Free Storage Space",region:o,metrics:[["AWS/RDS","FreeStorageSpace","DBInstanceIdentifier",c.rdsInstanceId]],period:300,stat:"Average"}}),u+=6;if(c.sqsQueueNames&&c.sqsQueueNames.length>0)l.push({type:"text",x:0,y:u,width:24,height:1,properties:{markdown:"## SQS Queues"}}),u+=1,l.push({type:"metric",x:0,y:u,width:12,height:6,properties:{title:"Messages Visible",region:o,metrics:c.sqsQueueNames.map((h)=>["AWS/SQS","ApproximateNumberOfMessagesVisible","QueueName",h]),period:60,stat:"Sum"}}),l.push({type:"metric",x:12,y:u,width:12,height:6,properties:{title:"Message Age",region:o,metrics:c.sqsQueueNames.map((h)=>["AWS/SQS","ApproximateAgeOfOldestMessage","QueueName",h]),period:60,stat:"Maximum"}}),u+=6;if(c.logGroupNames&&c.logGroupNames.length>0)l.push({type:"text",x:0,y:u,width:24,height:1,properties:{markdown:"## Application Logs"}}),u+=1,l.push({type:"log",x:0,y:u,width:24,height:6,properties:{query:`SOURCE '${c.logGroupNames.join("' | SOURCE '")}'
2313
2313
  | fields @timestamp, @message
2314
2314
  | filter @message like /ERROR|WARN|Exception/
2315
2315
  | sort @timestamp desc
2316
- | limit 50`,region:o,title:"Recent Errors and Warnings"}}),u+=6;return mo.createDashboard({slug:i,environment:s,widgets:l})}static DashboardTemplates={staticWebsite:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",n.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",n.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",n.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",n.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:n.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",n.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:n.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",n.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",n.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",n.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",n.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",n.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...n.lambdaFunctionNames.map((i,s)=>({type:"metric",x:s%3*8,y:7+Math.floor(s/3)*6,width:8,height:6,properties:{title:`${i} Metrics`,region:n.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",i],["AWS/Lambda","Duration","FunctionName",i],["AWS/Lambda","Errors","FunctionName",i]],period:300,stat:"Sum"}}))]}),containerService:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:n.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:n.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:n.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",n.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",n.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",n.albName]],period:60,stat:"Average"}},...n.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:n.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",n.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:n.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",n.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(n)=>{let{metricName:i,namespace:s,threshold:o,comparisonOperator:c="GreaterThanThreshold",evaluationPeriods:l=1,period:u=300,statistic:h="Average",treatMissingData:y="missing"}=n;return{MetricName:i,Namespace:s,Threshold:o,ComparisonOperator:c,EvaluationPeriods:l,Period:u,Statistic:h,TreatMissingData:y}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(n=80)=>({metricName:"CPUUtilization",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(n=80)=>({metricName:"MemoryUtilization",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(n=10)=>({metricName:"Errors",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(n=5000)=>({metricName:"Duration",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(n=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:n,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(n=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(n=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:n,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class H{static createUserPool(n){let{slug:i,environment:s,userPoolName:o,aliasAttributes:c,autoVerifiedAttributes:l,passwordPolicy:u,mfaConfiguration:h,emailConfiguration:y,smsConfiguration:f,lambdaTriggers:b,userPoolAddOns:C,accountRecoverySetting:T}=n,w=o||r({slug:i,environment:s,resourceType:"user-pool"}),E=t(w),I={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:w,Policies:u?{PasswordPolicy:{MinimumLength:u.minimumLength,RequireLowercase:u.requireLowercase,RequireUppercase:u.requireUppercase,RequireNumbers:u.requireNumbers,RequireSymbols:u.requireSymbols,TemporaryPasswordValidityDays:u.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:h,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(c&&c.length>0)I.Properties.UsernameAttributes=c;if(l&&l.length>0)I.Properties.AutoVerifiedAttributes=l;if(y)I.Properties.EmailConfiguration={EmailSendingAccount:y.emailSendingAccount,From:y.from,ReplyToEmailAddress:y.replyToEmailAddress,SourceArn:y.sourceArn,ConfigurationSet:y.configurationSet};if(f)I.Properties.SmsConfiguration={ExternalId:f.externalId,SnsCallerArn:f.snsCallerArn};if(b)I.Properties.LambdaConfig={PreSignUp:b.preSignUp,PostConfirmation:b.postConfirmation,PreAuthentication:b.preAuthentication,PostAuthentication:b.postAuthentication,CustomMessage:b.customMessage,DefineAuthChallenge:b.defineAuthChallenge,CreateAuthChallenge:b.createAuthChallenge,VerifyAuthChallengeResponse:b.verifyAuthChallengeResponse,PreTokenGeneration:b.preTokenGeneration,UserMigration:b.userMigration};if(C)I.Properties.UserPoolAddOns={AdvancedSecurityMode:C.advancedSecurityMode};if(T)I.Properties.AccountRecoverySetting={RecoveryMechanisms:T.recoveryMechanisms};return{userPool:I,logicalId:E}}static createUserPoolClient(n,i){let{slug:s,environment:o,clientName:c,generateSecret:l=!1,refreshTokenValidity:u,accessTokenValidity:h,idTokenValidity:y,tokenValidityUnits:f,readAttributes:b,writeAttributes:C,explicitAuthFlows:T,preventUserExistenceErrors:w,enableTokenRevocation:E,callbackURLs:I,logoutURLs:N,allowedOAuthFlows:D,allowedOAuthScopes:x,allowedOAuthFlowsUserPoolClient:R,supportedIdentityProviders:_}=i,B=c||r({slug:s,environment:o,resourceType:"user-pool-client"}),W=t(B);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:B,UserPoolId:k.Ref(n),GenerateSecret:l,RefreshTokenValidity:u,AccessTokenValidity:h,IdTokenValidity:y,TokenValidityUnits:f,ReadAttributes:b,WriteAttributes:C,ExplicitAuthFlows:T,PreventUserExistenceErrors:w,EnableTokenRevocation:E,CallbackURLs:I,LogoutURLs:N,AllowedOAuthFlows:D,AllowedOAuthScopes:x,AllowedOAuthFlowsUserPoolClient:R,SupportedIdentityProviders:_}},logicalId:W}}static createUserPoolDomain(n,i){let{slug:s,environment:o,domain:c,customDomainConfig:l}=i,u=r({slug:s,environment:o,resourceType:"user-pool-domain"}),h=t(u);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:c,UserPoolId:k.Ref(n),CustomDomainConfig:l}},logicalId:h}}static createIdentityPool(n){let{slug:i,environment:s,identityPoolName:o,allowUnauthenticatedIdentities:c=!1,cognitoIdentityProviders:l,supportedLoginProviders:u,samlProviderARNs:h,openIdConnectProviderARNs:y}=n,f=o||r({slug:i,environment:s,resourceType:"identity-pool"}),b=t(f);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:f,AllowUnauthenticatedIdentities:c,CognitoIdentityProviders:l,SupportedLoginProviders:u,SamlProviderARNs:h,OpenIdConnectProviderARNs:y}},logicalId:b}}static createIdentityPoolRoleAttachment(n,i){let{slug:s,environment:o,authenticatedRole:c,unauthenticatedRole:l,roleMappings:u}=i,h=r({slug:s,environment:o,resourceType:"identity-pool-role-attachment"}),y=t(h),f={authenticated:c};if(l)f.unauthenticated=l;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:k.Ref(n),Roles:f,RoleMappings:u}},logicalId:y}}static createAuthenticatedRole(n){let{slug:i,environment:s,identityPoolLogicalId:o}=n,c=r({slug:i,environment:s,resourceType:"cognito-authenticated-role"}),l=t(c);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":k.Ref(o)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"authenticated"}}}]},Policies:[{PolicyName:"CognitoAuthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*","cognito-identity:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:s}]}},logicalId:l}}static createUnauthenticatedRole(n){let{slug:i,environment:s,identityPoolLogicalId:o}=n,c=r({slug:i,environment:s,resourceType:"cognito-unauthenticated-role"}),l=t(c);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":k.Ref(o)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"unauthenticated"}}}]},Policies:[{PolicyName:"CognitoUnauthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:s}]}},logicalId:l}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(n,i,s)=>{let{userPool:o,logicalId:c}=H.createUserPool({slug:n,environment:i,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:H.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:l,logicalId:u}=H.createUserPoolClient(c,{slug:n,environment:i,explicitAuthFlows:[...H.AuthFlows.standard],callbackURLs:[s],allowedOAuthFlows:["code"],allowedOAuthScopes:[...H.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:o,poolId:c,client:l,clientId:u}},mobileApp:(n,i)=>{let{userPool:s,logicalId:o}=H.createUserPool({slug:n,environment:i,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:H.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:c,logicalId:l}=H.createUserPoolClient(o,{slug:n,environment:i,explicitAuthFlows:[...H.AuthFlows.standard]}),{identityPool:u,logicalId:h}=H.createIdentityPool({slug:n,environment:i,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:k.Ref(l),ProviderName:k.GetAtt(o,"ProviderName")}]}),{role:y,logicalId:f}=H.createAuthenticatedRole({slug:n,environment:i,identityPoolLogicalId:h}),{attachment:b,logicalId:C}=H.createIdentityPoolRoleAttachment(h,{slug:n,environment:i,authenticatedRole:k.GetAtt(f,"Arn")});return{userPool:s,poolId:o,client:c,clientId:l,identityPool:u,identityPoolId:h,authRole:y,authRoleId:f,attachment:b,attachmentId:C}}}}class G{static createApplication(n){let{slug:i,environment:s,applicationName:o,computePlatform:c}=n,l=o||r({slug:i,environment:s,resourceType:"deploy-app"}),u=t(l);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:l,ComputePlatform:c,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:s}]}},logicalId:u}}static createDeploymentGroup(n,i){let{slug:s,environment:o,deploymentGroupName:c,serviceRoleArn:l,autoScalingGroups:u,ec2TagFilters:h,deploymentConfigName:y,autoRollbackConfiguration:f,alarmConfiguration:b,loadBalancerInfo:C,blueGreenDeploymentConfiguration:T}=i,w=c||r({slug:s,environment:o,resourceType:"deploy-group"}),E=t(w);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:k.Ref(n),DeploymentGroupName:w,ServiceRoleArn:l,AutoScalingGroups:u,Ec2TagFilters:h?.map((I)=>({Key:I.key,Value:I.value,Type:I.type})),DeploymentConfigName:y,AutoRollbackConfiguration:f?{Enabled:f.enabled,Events:f.events}:void 0,AlarmConfiguration:b?{Enabled:b.enabled,Alarms:b.alarms?.map((I)=>({Name:I.name})),IgnorePollAlarmFailure:b.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:C?{TargetGroupInfoList:C.targetGroupInfoList?.map((I)=>({Name:I.name})),ElbInfoList:C.elbInfoList?.map((I)=>({Name:I.name}))}:void 0,BlueGreenDeploymentConfiguration:T?{TerminateBlueInstancesOnDeploymentSuccess:T.terminateBlueInstancesOnDeploymentSuccess?{Action:T.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:T.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:T.deploymentReadyOption?{ActionOnTimeout:T.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:T.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:T.greenFleetProvisioningOption?{Action:T.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:w},{Key:"Environment",Value:o}]}},logicalId:E}}static createDeploymentConfig(n){let{slug:i,environment:s,deploymentConfigName:o,minimumHealthyHosts:c,trafficRoutingConfig:l}=n,u=o||r({slug:i,environment:s,resourceType:"deploy-config"}),h=t(u);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:u,MinimumHealthyHosts:c?{Type:c.type,Value:c.value}:void 0,TrafficRoutingConfig:l?{Type:l.type,TimeBasedCanary:l.timeBasedCanary?{CanaryPercentage:l.timeBasedCanary.canaryPercentage,CanaryInterval:l.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:l.timeBasedLinear?{LinearPercentage:l.timeBasedLinear.linearPercentage,LinearInterval:l.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:h}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(n,i)=>({type:n,value:i})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(n,i)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:n,canaryInterval:i}}),linear:(n,i)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:n,linearInterval:i}})};static RollbackConfigs={onFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE"]}),onAlarmOrFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM"]}),onAllEvents:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM","DEPLOYMENT_STOP_ON_REQUEST"]}),disabled:()=>({enabled:!1})};static BlueGreenConfigs={standard:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withDelay:(n)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:n},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(n)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:n},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),keepBlue:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"KEEP_ALIVE"},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}})};static UseCases={ec2Deployment:(n,i,s,o)=>{let{application:c,logicalId:l}=G.createApplication({slug:n,environment:i,computePlatform:"Server"}),{deploymentGroup:u,logicalId:h}=G.createDeploymentGroup(l,{slug:n,environment:i,serviceRoleArn:s,autoScalingGroups:o,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:G.RollbackConfigs.onFailure()});return{application:c,appId:l,deploymentGroup:u,groupId:h}},lambdaCanaryDeployment:(n,i,s,o=10,c=5)=>{let{application:l,logicalId:u}=G.createApplication({slug:n,environment:i,computePlatform:"Lambda"}),{deploymentConfig:h,logicalId:y}=G.createDeploymentConfig({slug:n,environment:i,trafficRoutingConfig:G.TrafficRouting.canary(o,c)}),{deploymentGroup:f,logicalId:b}=G.createDeploymentGroup(u,{slug:n,environment:i,serviceRoleArn:s,deploymentConfigName:k.Ref(y),autoRollbackConfiguration:G.RollbackConfigs.onAlarmOrFailure()});return{application:l,appId:u,deploymentConfig:h,configId:y,deploymentGroup:f,groupId:b}},ecsBlueGreenDeployment:(n,i,s,o)=>{let{application:c,logicalId:l}=G.createApplication({slug:n,environment:i,computePlatform:"ECS"}),{deploymentGroup:u,logicalId:h}=G.createDeploymentGroup(l,{slug:n,environment:i,serviceRoleArn:s,loadBalancerInfo:{targetGroupInfoList:[{name:o}]},blueGreenDeploymentConfiguration:G.BlueGreenConfigs.standard(),autoRollbackConfiguration:G.RollbackConfigs.onFailure()});return{application:c,appId:l,deploymentGroup:u,groupId:h}}};static Strategies={rolling:(n=25)=>({type:"rolling",batchPercentage:n}),blueGreen:()=>({type:"blue-green"}),canary:(n=10,i=5)=>({type:"canary",canaryPercentage:n,canaryInterval:i}),allAtOnce:()=>({type:"all-at-once"})}}class P{static ContentTypes={".html":"text/html",".htm":"text/html",".css":"text/css",".js":"application/javascript",".mjs":"application/javascript",".json":"application/json",".xml":"application/xml",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".map":"application/json"};static NoHashPatterns=[/^index\.html$/,/^favicon\.ico$/,/^robots\.txt$/,/^sitemap\.xml$/,/^manifest\.json$/,/^\.well-known\//,/^_redirects$/,/^_headers$/];static computeFileHash(n,i="md5"){let s=st(n);return Nr(i).update(s).digest("hex")}static computeShortHash(n){return P.computeFileHash(n).slice(0,8)}static getContentType(n){let i=ma(n).toLowerCase();return P.ContentTypes[i]||"application/octet-stream"}static shouldHashFile(n,i){return![...P.NoHashPatterns,...i||[]].some((s)=>s.test(n))}static generateHashedFilename(n,i){let s=ma(n),o=Lr(n,s),c=da(n);if(c===".")return`${o}.${i}${s}`;return Je(c,`${o}.${i}${s}`)}static collectFiles(n,i){let s=[],o=i||n;if(!Nt(n))return s;let c=kr(n,{withFileTypes:!0});for(let l of c){let u=Je(n,l.name);if(l.isDirectory())s.push(...P.collectFiles(u,o));else if(l.isFile())s.push(u)}return s}static hashDirectory(n){let{sourceDir:i,outputDir:s,excludePatterns:o=[],hashAlgorithm:c="md5",copyUnhashed:l=!0}=n,u=P.collectFiles(i),h=[],y={};for(let b of u){let C=b.replace(i,"").replace(/^[/\\]/,""),T=P.shouldHashFile(C,o),w=$r(b),E=T?P.computeFileHash(b,c).slice(0,8):"",I=T?P.generateHashedFilename(C,E):C,N={originalPath:C,hashedPath:I,hash:E,size:w.size,contentType:P.getContentType(b)};if(h.push(N),y[C]=I,s){let D=Je(s,I),x=da(D);if(!Nt(x)){let{mkdirSync:R}=ir("node:fs");R(x,{recursive:!0})}if(T||l)Dr(b,D)}}let f={version:"1.0",timestamp:new Date().toISOString(),assets:h,hashMap:y};if(s){let b=Je(s,"asset-manifest.json");ot(b,JSON.stringify(f,null,2))}return f}static getInvalidationPaths(n,i){let s=[];if(!n)return["/*"];let o=n.hashMap,c=i.hashMap;for(let[l,u]of Object.entries(c)){let h=o[l];if(!h||h!==u){if(s.push(`/${l}`),h&&h!==u)s.push(`/${h}`)}}for(let[l,u]of Object.entries(o))if(!c[l])s.push(`/${l}`),s.push(`/${u}`);if(s.length>100)return["/*"];return[...new Set(s)]}static updateHtmlReferences(n){let{htmlDir:i,manifest:s,basePath:o=""}=n,c=P.collectFiles(i).filter((l)=>l.endsWith(".html")||l.endsWith(".htm"));for(let l of c){let u=st(l,"utf-8");for(let[h,y]of Object.entries(s.hashMap)){if(h===y)continue;let f=[new RegExp(`(src|href)=["']${o}/?${P.escapeRegExp(h)}["']`,"g"),new RegExp(`url\\(["']?${o}/?${P.escapeRegExp(h)}["']?\\)`,"g")];for(let b of f)u=u.replace(b,(C)=>C.replace(h,y))}ot(l,u)}}static updateCssReferences(n){let{cssDir:i,manifest:s,basePath:o=""}=n,c=P.collectFiles(i).filter((l)=>l.endsWith(".css"));for(let l of c){let u=st(l,"utf-8");for(let[h,y]of Object.entries(s.hashMap)){if(h===y)continue;let f=new RegExp(`url\\(["']?${o}/?${P.escapeRegExp(h)}["']?\\)`,"g");u=u.replace(f,`url(${o}/${y})`)}ot(l,u)}}static escapeRegExp(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(n){let{sourceDir:i,keyPrefix:s="",excludePatterns:o=[],cacheControl:c={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=n;return P.hashDirectory({sourceDir:i,excludePatterns:o}).assets.map((l)=>{let u=l.hash!=="",h=l.contentType==="text/html",y=c.unhashed||"public, max-age=3600";if(h)y=c.html||"public, max-age=0, must-revalidate";else if(u)y=c.hashed||"public, max-age=31536000, immutable";return{localPath:Je(i,l.originalPath),s3Key:s?`${s}/${l.hashedPath}`:l.hashedPath,contentType:l.contentType,cacheControl:y,hash:l.hash}})}static compareManifests(n,i){let s={added:[],removed:[],changed:[],unchanged:[]},o=new Set(Object.keys(n.hashMap)),c=new Set(Object.keys(i.hashMap));for(let l of c)if(!o.has(l))s.added.push(l);for(let l of o)if(!c.has(l))s.removed.push(l);for(let l of c)if(o.has(l))if(n.hashMap[l]!==i.hashMap[l])s.changed.push(l);else s.unchanged.push(l);return s}static loadManifest(n){if(!Nt(n))return null;try{let i=st(n,"utf-8");return JSON.parse(i)}catch{return null}}static saveManifest(n,i){ot(i,JSON.stringify(n,null,2))}}class Pi{static createSecret(n){let{slug:i,environment:s,secretName:o,description:c,secretString:l,kmsKeyId:u,tags:h}=n,y=o||r({slug:i,environment:s,resourceType:"secret"}),f=t(y),b={Type:"AWS::SecretsManager::Secret",Properties:{Name:y,Description:c,SecretString:l,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},...h?Object.entries(h).map(([C,T])=>({Key:C,Value:T})):[]]}};if(u)b.Properties.KmsKeyId=u;return{secret:b,logicalId:f}}static createGeneratedSecret(n){let{slug:i,environment:s,secretName:o,description:c,excludeCharacters:l,excludeLowercase:u,excludeNumbers:h,excludePunctuation:y,excludeUppercase:f,passwordLength:b,requireEachIncludedType:C,kmsKeyId:T,tags:w}=n,E=o||r({slug:i,environment:s,resourceType:"secret"}),I=t(E),N={Type:"AWS::SecretsManager::Secret",Properties:{Name:E,Description:c,GenerateSecretString:{ExcludeCharacters:l,ExcludeLowercase:u,ExcludeNumbers:h,ExcludePunctuation:y,ExcludeUppercase:f,PasswordLength:b||32,RequireEachIncludedType:C!==!1},Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:s},...w?Object.entries(w).map(([D,x])=>({Key:D,Value:x})):[]]}};if(T)N.Properties.KmsKeyId=T;return{secret:N,logicalId:I}}static createDatabaseSecret(n){let{slug:i,environment:s,secretName:o,username:c,dbname:l,engine:u,host:h,port:y,kmsKeyId:f}=n,b=o||r({slug:i,environment:s,resourceType:"db-secret"}),C=t(b),T={username:c};if(l)T.dbname=l;if(u)T.engine=u;if(h)T.host=h;if(y)T.port=y;let w={Type:"AWS::SecretsManager::Secret",Properties:{Name:b,Description:`Database credentials for ${c}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(T),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:b},{Key:"Environment",Value:s},{Key:"Type",Value:"database"}]}};if(f)w.Properties.KmsKeyId=f;return{secret:w,logicalId:C}}static attachToDatabase(n){let{slug:i,environment:s,secretId:o,targetId:c,targetType:l}=n,u=r({slug:i,environment:s,resourceType:"secret-attachment"}),h=t(u);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:o,TargetId:c,TargetType:l}},logicalId:h}}static enableRotation(n){let{slug:i,environment:s,secretId:o,rotationLambdaArn:c,automaticallyAfterDays:l,rotationType:u,kmsKeyArn:h,vpcSecurityGroupIds:y,vpcSubnetIds:f}=n,b=r({slug:i,environment:s,resourceType:"secret-rotation"}),C=t(b),T={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:o,RotationRules:{AutomaticallyAfterDays:l||30}}};if(c)T.Properties.RotationLambdaARN=c;else if(u)T.Properties.HostedRotationLambda={RotationType:u,KmsKeyArn:h,VpcSecurityGroupIds:y,VpcSubnetIds:f};return{rotation:T,logicalId:C}}static SecretTypes={apiKey:(n,i,s)=>Pi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-${s}-api-key`,description:`API key for ${s}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(n,i,s)=>Pi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-${s}-oauth-secret`,description:`OAuth client secret for ${s}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(n,i)=>Pi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(n,i)=>Pi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class v{static createParameter(n){let{slug:i,environment:s,parameterName:o,value:c,type:l="String",description:u,tier:h="Standard",tags:y}=n,f=o||r({slug:i,environment:s,resourceType:"parameter"}),b=t(f);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${i}/${s}/${f}`,Type:l,Value:c,Description:u,Tier:h,Tags:{Name:f,Environment:s,...y}}},logicalId:b}}static createString(n,i,s,o,c){return v.createParameter({slug:n,environment:i,parameterName:s,value:o,type:"String",description:c})}static createSecureString(n,i,s,o,c){return v.createParameter({slug:n,environment:i,parameterName:s,value:o,type:"SecureString",description:c})}static createStringList(n,i,s,o,c){return v.createParameter({slug:n,environment:i,parameterName:s,value:o.join(","),type:"StringList",description:c})}static Parameters={databaseUrl:(n,i,s)=>v.createSecureString(n,i,"database-url",s,"Database connection URL"),apiEndpoint:(n,i,s)=>v.createString(n,i,"api-endpoint",s,"API endpoint URL"),appVersion:(n,i,s)=>v.createString(n,i,"app-version",s,"Application version"),featureFlags:(n,i,s)=>v.createStringList(n,i,"feature-flags",s,"Enabled feature flags"),apiKey:(n,i,s,o)=>v.createSecureString(n,i,`${s}-api-key`,o,`API key for ${s}`),oauthCredentials:(n,i,s,o)=>{let c=v.createString(n,i,"oauth-client-id",s,"OAuth client ID"),l=v.createSecureString(n,i,"oauth-client-secret",o,"OAuth client secret");return{clientId:c,clientSecret:l}},smtpCredentials:(n,i,s,o,c,l)=>{let u=v.createString(n,i,"smtp-username",s,"SMTP username"),h=v.createSecureString(n,i,"smtp-password",o,"SMTP password"),y=v.createString(n,i,"smtp-host",c,"SMTP host"),f=v.createString(n,i,"smtp-port",l.toString(),"SMTP port");return{username:u,password:h,host:y,port:f}},redisUrl:(n,i,s)=>v.createSecureString(n,i,"redis-url",s,"Redis connection URL"),s3Bucket:(n,i,s)=>v.createString(n,i,"s3-bucket",s,"S3 bucket name"),cloudFrontDistribution:(n,i,s)=>v.createString(n,i,"cloudfront-distribution-id",s,"CloudFront distribution ID")}}class zt{static createDomain(n){let{slug:i,environment:s,domainName:o,engineVersion:c="OpenSearch_2.11",instanceType:l="t3.small.search",instanceCount:u=1,volumeSize:h=10,volumeType:y="gp3",dedicatedMaster:f=!1,dedicatedMasterType:b,dedicatedMasterCount:C=3,multiAz:T=!1,availabilityZoneCount:w=2,vpc:E,encryption:I,enforceHttps:N=!0,tlsSecurityPolicy:D="Policy-Min-TLS-1-2-2019-07",advancedSecurity:x,autoSnapshotHour:R=0,autoTune:_=!0,tags:B={}}=n,W=o||r({slug:i,environment:s,resourceType:"search"}),J=t(W);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:W,EngineVersion:c,ClusterConfig:{InstanceType:l,InstanceCount:u,DedicatedMasterEnabled:f,...f&&{DedicatedMasterType:b||l,DedicatedMasterCount:C},ZoneAwarenessEnabled:T,...T&&{ZoneAwarenessConfig:{AvailabilityZoneCount:w}}},EBSOptions:{EBSEnabled:!0,VolumeType:y,VolumeSize:h},DomainEndpointOptions:{EnforceHTTPS:N,TLSSecurityPolicy:D},SnapshotOptions:{AutomatedSnapshotStartHour:R},...E&&{VPCOptions:{SubnetIds:E.subnetIds,SecurityGroupIds:E.securityGroupIds}},...I&&{EncryptionAtRestOptions:{Enabled:I.atRest??!0,...I.kmsKeyId&&{KmsKeyId:I.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:I.nodeToNode??!0}},...x&&{AdvancedSecurityOptions:{Enabled:x.enabled,InternalUserDatabaseEnabled:x.internalUserDatabase??!0,...x.masterUserName&&x.masterUserPassword&&{MasterUserOptions:{MasterUserName:x.masterUserName,MasterUserPassword:x.masterUserPassword}},...x.masterUserArn&&{MasterUserOptions:{MasterUserARN:x.masterUserArn}}}},..._&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:W},{Key:"Environment",Value:s},...Object.entries(B).map(([K,Y])=>({Key:K,Value:Y}))]}},logicalId:J}}static createAccessPolicy(n,i){let{ipAddresses:s,iamPrincipalArns:o,allowAll:c,vpcEndpoint:l}=i;if(c)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n}]};let u=[];if(o&&o.length>0)u.push({Effect:"Allow",Principal:{AWS:o},Action:"es:*",Resource:n});if(s&&s.length>0)u.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n,Condition:{IpAddress:{"aws:SourceIp":s}}});if(l)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n}]};return{Version:"2012-10-17",Statement:u}}static DomainPresets={development:(n,i)=>zt.createDomain({slug:n,environment:i,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(n,i,s)=>zt.createDomain({slug:n,environment:i,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:s,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(n,i)=>zt.createDomain({slug:n,environment:i,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(n,i,s)=>zt.createDomain({slug:n,environment:i,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:s,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class At{static createDomainRedirectBucket(n){let{slug:i,environment:s,sourceDomain:o,targetDomain:c,protocol:l="https"}=n,u=r({slug:i,environment:s,resourceType:"s3",suffix:"redirect"}),h=t(u),y=t(`${u}-policy`),f={Type:"AWS::S3::Bucket",Properties:{BucketName:o,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:c,Protocol:l}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s},{Key:"Purpose",Value:"Domain Redirect"}]}},b={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:k.Ref(h),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[k.Join("",[k.GetAtt(h,"Arn"),"/*"])]}]}}};return{bucket:f,bucketPolicy:b,logicalId:h,policyLogicalId:y}}static createPathRedirectFunction(n){let{slug:i,environment:s,rules:o}=n,c=r({slug:i,environment:s,resourceType:"cf-redirect"}),l=t(c),u=At.generateRedirectFunctionCode(o);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:c,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${i} (${s})`,Runtime:"cloudfront-js-2.0"},FunctionCode:u}},logicalId:l,functionCode:u}}static generateRedirectFunctionCode(n){return`function handler(event) {
2316
+ | limit 50`,region:o,title:"Recent Errors and Warnings"}}),u+=6;return mo.createDashboard({slug:i,environment:s,widgets:l})}static DashboardTemplates={staticWebsite:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Static Website Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"CloudFront Requests",region:"us-east-1",metrics:[["AWS/CloudFront","Requests","DistributionId",n.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"Error Rate",region:"us-east-1",metrics:[["AWS/CloudFront","4xxErrorRate","DistributionId",n.cloudFrontDistributionId,"Region","Global",{label:"4XX"}],["AWS/CloudFront","5xxErrorRate","DistributionId",n.cloudFrontDistributionId,"Region","Global",{label:"5XX"}]],period:300,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Bytes Downloaded",region:"us-east-1",metrics:[["AWS/CloudFront","BytesDownloaded","DistributionId",n.cloudFrontDistributionId,"Region","Global"]],period:300,stat:"Sum"}},{type:"metric",x:0,y:7,width:12,height:6,properties:{title:"S3 Bucket Size",region:n.region||"us-east-1",metrics:[["AWS/S3","BucketSizeBytes","BucketName",n.s3BucketName,"StorageType","StandardStorage"]],period:86400,stat:"Average"}},{type:"metric",x:12,y:7,width:12,height:6,properties:{title:"S3 Number of Objects",region:n.region||"us-east-1",metrics:[["AWS/S3","NumberOfObjects","BucketName",n.s3BucketName,"StorageType","AllStorageTypes"]],period:86400,stat:"Average"}}]}),serverlessApi:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Serverless API Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"API Requests",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","Count","ApiName",n.apiGatewayName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"API Latency",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","Latency","ApiName",n.apiGatewayName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"API Errors",region:n.region||"us-east-1",metrics:[["AWS/ApiGateway","4XXError","ApiName",n.apiGatewayName,{label:"4XX"}],["AWS/ApiGateway","5XXError","ApiName",n.apiGatewayName,{label:"5XX"}]],period:60,stat:"Sum"}},...n.lambdaFunctionNames.map((i,s)=>({type:"metric",x:s%3*8,y:7+Math.floor(s/3)*6,width:8,height:6,properties:{title:`${i} Metrics`,region:n.region||"us-east-1",metrics:[["AWS/Lambda","Invocations","FunctionName",i],["AWS/Lambda","Duration","FunctionName",i],["AWS/Lambda","Errors","FunctionName",i]],period:300,stat:"Sum"}}))]}),containerService:(n)=>({slug:n.slug,environment:n.environment,widgets:[{type:"text",x:0,y:0,width:24,height:1,properties:{markdown:`# ${n.slug.toUpperCase()} Container Service Dashboard`}},{type:"metric",x:0,y:1,width:8,height:6,properties:{title:"ECS CPU",region:n.region||"us-east-1",metrics:[["AWS/ECS","CPUUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:8,y:1,width:8,height:6,properties:{title:"ECS Memory",region:n.region||"us-east-1",metrics:[["AWS/ECS","MemoryUtilization","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:16,y:1,width:8,height:6,properties:{title:"Running Tasks",region:n.region||"us-east-1",metrics:[["ECS/ContainerInsights","RunningTaskCount","ClusterName",n.ecsClusterName,"ServiceName",n.ecsServiceName]],period:60,stat:"Average"}},{type:"metric",x:0,y:7,width:8,height:6,properties:{title:"ALB Requests",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","RequestCount","LoadBalancer",n.albName]],period:60,stat:"Sum"}},{type:"metric",x:8,y:7,width:8,height:6,properties:{title:"Response Time",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","TargetResponseTime","LoadBalancer",n.albName]],period:60,stat:"Average"}},{type:"metric",x:16,y:7,width:8,height:6,properties:{title:"Healthy Hosts",region:n.region||"us-east-1",metrics:[["AWS/ApplicationELB","HealthyHostCount","LoadBalancer",n.albName]],period:60,stat:"Average"}},...n.rdsInstanceId?[{type:"metric",x:0,y:13,width:12,height:6,properties:{title:"RDS CPU",region:n.region||"us-east-1",metrics:[["AWS/RDS","CPUUtilization","DBInstanceIdentifier",n.rdsInstanceId]],period:300,stat:"Average"}},{type:"metric",x:12,y:13,width:12,height:6,properties:{title:"RDS Connections",region:n.region||"us-east-1",metrics:[["AWS/RDS","DatabaseConnections","DBInstanceIdentifier",n.rdsInstanceId]],period:60,stat:"Sum"}}]:[]]})};static Config={createAlarmConfig:(n)=>{let{metricName:i,namespace:s,threshold:o,comparisonOperator:c="GreaterThanThreshold",evaluationPeriods:l=1,period:u=300,statistic:h="Average",treatMissingData:y="missing"}=n;return{MetricName:i,Namespace:s,Threshold:o,ComparisonOperator:c,EvaluationPeriods:l,Period:u,Statistic:h,TreatMissingData:y}},namespaces:{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",sqs:"AWS/SQS",sns:"AWS/SNS",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apiGateway:"AWS/ApiGateway",dynamodb:"AWS/DynamoDB",elasticache:"AWS/ElastiCache"},comparisonOperators:{greaterThan:"GreaterThanThreshold",greaterOrEqual:"GreaterThanOrEqualToThreshold",lessThan:"LessThanThreshold",lessOrEqual:"LessThanOrEqualToThreshold"},metrics:{ec2:{cpu:{metricName:"CPUUtilization",namespace:"AWS/EC2"},networkIn:{metricName:"NetworkIn",namespace:"AWS/EC2"},networkOut:{metricName:"NetworkOut",namespace:"AWS/EC2"},statusCheck:{metricName:"StatusCheckFailed",namespace:"AWS/EC2"}},ecs:{cpu:{metricName:"CPUUtilization",namespace:"AWS/ECS"},memory:{metricName:"MemoryUtilization",namespace:"AWS/ECS"}},lambda:{invocations:{metricName:"Invocations",namespace:"AWS/Lambda"},errors:{metricName:"Errors",namespace:"AWS/Lambda"},duration:{metricName:"Duration",namespace:"AWS/Lambda"},throttles:{metricName:"Throttles",namespace:"AWS/Lambda"},concurrentExecutions:{metricName:"ConcurrentExecutions",namespace:"AWS/Lambda"}},rds:{cpu:{metricName:"CPUUtilization",namespace:"AWS/RDS"},connections:{metricName:"DatabaseConnections",namespace:"AWS/RDS"},freeStorage:{metricName:"FreeStorageSpace",namespace:"AWS/RDS"},readLatency:{metricName:"ReadLatency",namespace:"AWS/RDS"},writeLatency:{metricName:"WriteLatency",namespace:"AWS/RDS"}},alb:{requestCount:{metricName:"RequestCount",namespace:"AWS/ApplicationELB"},responseTime:{metricName:"TargetResponseTime",namespace:"AWS/ApplicationELB"},httpCode4xx:{metricName:"HTTPCode_Target_4XX_Count",namespace:"AWS/ApplicationELB"},httpCode5xx:{metricName:"HTTPCode_Target_5XX_Count",namespace:"AWS/ApplicationELB"},healthyHosts:{metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB"}},sqs:{messagesVisible:{metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS"},messagesDelayed:{metricName:"ApproximateNumberOfMessagesDelayed",namespace:"AWS/SQS"},messageAge:{metricName:"ApproximateAgeOfOldestMessage",namespace:"AWS/SQS"}}},presets:{highCpu:(n=80)=>({metricName:"CPUUtilization",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highMemory:(n=80)=>({metricName:"MemoryUtilization",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),highErrors:(n=10)=>({metricName:"Errors",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:1,period:60,statistic:"Sum"}),highLatency:(n=5000)=>({metricName:"Duration",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowHealthyHosts:(n=1)=>({metricName:"HealthyHostCount",namespace:"AWS/ApplicationELB",threshold:n,comparisonOperator:"LessThanThreshold",evaluationPeriods:2,period:60,statistic:"Minimum"}),queueDepth:(n=1000)=>({metricName:"ApproximateNumberOfMessagesVisible",namespace:"AWS/SQS",threshold:n,comparisonOperator:"GreaterThanThreshold",evaluationPeriods:3,period:300,statistic:"Average"}),lowStorage:(n=10737418240)=>({metricName:"FreeStorageSpace",namespace:"AWS/RDS",threshold:n,comparisonOperator:"LessThanThreshold",evaluationPeriods:1,period:300,statistic:"Average"})}}}class H{static createUserPool(n){let{slug:i,environment:s,userPoolName:o,aliasAttributes:c,autoVerifiedAttributes:l,passwordPolicy:u,mfaConfiguration:h,emailConfiguration:y,smsConfiguration:f,lambdaTriggers:S,userPoolAddOns:b,accountRecoverySetting:v}=n,w=o||r({slug:i,environment:s,resourceType:"user-pool"}),E=t(w),P={Type:"AWS::Cognito::UserPool",Properties:{UserPoolName:w,Policies:u?{PasswordPolicy:{MinimumLength:u.minimumLength,RequireLowercase:u.requireLowercase,RequireUppercase:u.requireUppercase,RequireNumbers:u.requireNumbers,RequireSymbols:u.requireSymbols,TemporaryPasswordValidityDays:u.temporaryPasswordValidityDays}}:void 0,MfaConfiguration:h,Schema:[{Name:"email",AttributeDataType:"String",Required:!0,Mutable:!1}]}};if(c&&c.length>0)P.Properties.UsernameAttributes=c;if(l&&l.length>0)P.Properties.AutoVerifiedAttributes=l;if(y)P.Properties.EmailConfiguration={EmailSendingAccount:y.emailSendingAccount,From:y.from,ReplyToEmailAddress:y.replyToEmailAddress,SourceArn:y.sourceArn,ConfigurationSet:y.configurationSet};if(f)P.Properties.SmsConfiguration={ExternalId:f.externalId,SnsCallerArn:f.snsCallerArn};if(S)P.Properties.LambdaConfig={PreSignUp:S.preSignUp,PostConfirmation:S.postConfirmation,PreAuthentication:S.preAuthentication,PostAuthentication:S.postAuthentication,CustomMessage:S.customMessage,DefineAuthChallenge:S.defineAuthChallenge,CreateAuthChallenge:S.createAuthChallenge,VerifyAuthChallengeResponse:S.verifyAuthChallengeResponse,PreTokenGeneration:S.preTokenGeneration,UserMigration:S.userMigration};if(b)P.Properties.UserPoolAddOns={AdvancedSecurityMode:b.advancedSecurityMode};if(v)P.Properties.AccountRecoverySetting={RecoveryMechanisms:v.recoveryMechanisms};return{userPool:P,logicalId:E}}static createUserPoolClient(n,i){let{slug:s,environment:o,clientName:c,generateSecret:l=!1,refreshTokenValidity:u,accessTokenValidity:h,idTokenValidity:y,tokenValidityUnits:f,readAttributes:S,writeAttributes:b,explicitAuthFlows:v,preventUserExistenceErrors:w,enableTokenRevocation:E,callbackURLs:P,logoutURLs:R,allowedOAuthFlows:D,allowedOAuthScopes:x,allowedOAuthFlowsUserPoolClient:I,supportedIdentityProviders:_}=i,B=c||r({slug:s,environment:o,resourceType:"user-pool-client"}),W=t(B);return{client:{Type:"AWS::Cognito::UserPoolClient",Properties:{ClientName:B,UserPoolId:k.Ref(n),GenerateSecret:l,RefreshTokenValidity:u,AccessTokenValidity:h,IdTokenValidity:y,TokenValidityUnits:f,ReadAttributes:S,WriteAttributes:b,ExplicitAuthFlows:v,PreventUserExistenceErrors:w,EnableTokenRevocation:E,CallbackURLs:P,LogoutURLs:R,AllowedOAuthFlows:D,AllowedOAuthScopes:x,AllowedOAuthFlowsUserPoolClient:I,SupportedIdentityProviders:_}},logicalId:W}}static createUserPoolDomain(n,i){let{slug:s,environment:o,domain:c,customDomainConfig:l}=i,u=r({slug:s,environment:o,resourceType:"user-pool-domain"}),h=t(u);return{domain:{Type:"AWS::Cognito::UserPoolDomain",Properties:{Domain:c,UserPoolId:k.Ref(n),CustomDomainConfig:l}},logicalId:h}}static createIdentityPool(n){let{slug:i,environment:s,identityPoolName:o,allowUnauthenticatedIdentities:c=!1,cognitoIdentityProviders:l,supportedLoginProviders:u,samlProviderARNs:h,openIdConnectProviderARNs:y}=n,f=o||r({slug:i,environment:s,resourceType:"identity-pool"}),S=t(f);return{identityPool:{Type:"AWS::Cognito::IdentityPool",Properties:{IdentityPoolName:f,AllowUnauthenticatedIdentities:c,CognitoIdentityProviders:l,SupportedLoginProviders:u,SamlProviderARNs:h,OpenIdConnectProviderARNs:y}},logicalId:S}}static createIdentityPoolRoleAttachment(n,i){let{slug:s,environment:o,authenticatedRole:c,unauthenticatedRole:l,roleMappings:u}=i,h=r({slug:s,environment:o,resourceType:"identity-pool-role-attachment"}),y=t(h),f={authenticated:c};if(l)f.unauthenticated=l;return{attachment:{Type:"AWS::Cognito::IdentityPoolRoleAttachment",Properties:{IdentityPoolId:k.Ref(n),Roles:f,RoleMappings:u}},logicalId:y}}static createAuthenticatedRole(n){let{slug:i,environment:s,identityPoolLogicalId:o}=n,c=r({slug:i,environment:s,resourceType:"cognito-authenticated-role"}),l=t(c);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":k.Ref(o)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"authenticated"}}}]},Policies:[{PolicyName:"CognitoAuthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*","cognito-identity:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:s}]}},logicalId:l}}static createUnauthenticatedRole(n){let{slug:i,environment:s,identityPoolLogicalId:o}=n,c=r({slug:i,environment:s,resourceType:"cognito-unauthenticated-role"}),l=t(c);return{role:{Type:"AWS::IAM::Role",Properties:{RoleName:c,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Federated:"cognito-identity.amazonaws.com"},Action:"sts:AssumeRoleWithWebIdentity",Condition:{StringEquals:{"cognito-identity.amazonaws.com:aud":k.Ref(o)},"ForAnyValue:StringLike":{"cognito-identity.amazonaws.com:amr":"unauthenticated"}}}]},Policies:[{PolicyName:"CognitoUnauthenticatedPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["cognito-sync:*"],Resource:"*"}]}}],Tags:[{Key:"Name",Value:c},{Key:"Environment",Value:s}]}},logicalId:l}}static PasswordPolicies={relaxed:()=>({minimumLength:8,requireLowercase:!1,requireUppercase:!1,requireNumbers:!1,requireSymbols:!1,temporaryPasswordValidityDays:7}),standard:()=>({minimumLength:8,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!1,temporaryPasswordValidityDays:3}),strict:()=>({minimumLength:12,requireLowercase:!0,requireUppercase:!0,requireNumbers:!0,requireSymbols:!0,temporaryPasswordValidityDays:1})};static AuthFlows={standard:["ALLOW_USER_SRP_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],admin:["ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],custom:["ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"],all:["ALLOW_USER_SRP_AUTH","ALLOW_USER_PASSWORD_AUTH","ALLOW_ADMIN_USER_PASSWORD_AUTH","ALLOW_CUSTOM_AUTH","ALLOW_REFRESH_TOKEN_AUTH"]};static OAuthScopes={basic:["openid","email","profile"],all:["openid","email","profile","phone","aws.cognito.signin.user.admin"]};static UseCases={webApp:(n,i,s)=>{let{userPool:o,logicalId:c}=H.createUserPool({slug:n,environment:i,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:H.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:l,logicalId:u}=H.createUserPoolClient(c,{slug:n,environment:i,explicitAuthFlows:[...H.AuthFlows.standard],callbackURLs:[s],allowedOAuthFlows:["code"],allowedOAuthScopes:[...H.OAuthScopes.basic],allowedOAuthFlowsUserPoolClient:!0});return{userPool:o,poolId:c,client:l,clientId:u}},mobileApp:(n,i)=>{let{userPool:s,logicalId:o}=H.createUserPool({slug:n,environment:i,aliasAttributes:["email"],autoVerifiedAttributes:["email"],passwordPolicy:H.PasswordPolicies.standard(),mfaConfiguration:"OPTIONAL"}),{client:c,logicalId:l}=H.createUserPoolClient(o,{slug:n,environment:i,explicitAuthFlows:[...H.AuthFlows.standard]}),{identityPool:u,logicalId:h}=H.createIdentityPool({slug:n,environment:i,allowUnauthenticatedIdentities:!1,cognitoIdentityProviders:[{ClientId:k.Ref(l),ProviderName:k.GetAtt(o,"ProviderName")}]}),{role:y,logicalId:f}=H.createAuthenticatedRole({slug:n,environment:i,identityPoolLogicalId:h}),{attachment:S,logicalId:b}=H.createIdentityPoolRoleAttachment(h,{slug:n,environment:i,authenticatedRole:k.GetAtt(f,"Arn")});return{userPool:s,poolId:o,client:c,clientId:l,identityPool:u,identityPoolId:h,authRole:y,authRoleId:f,attachment:S,attachmentId:b}}}}class G{static createApplication(n){let{slug:i,environment:s,applicationName:o,computePlatform:c}=n,l=o||r({slug:i,environment:s,resourceType:"deploy-app"}),u=t(l);return{application:{Type:"AWS::CodeDeploy::Application",Properties:{ApplicationName:l,ComputePlatform:c,Tags:[{Key:"Name",Value:l},{Key:"Environment",Value:s}]}},logicalId:u}}static createDeploymentGroup(n,i){let{slug:s,environment:o,deploymentGroupName:c,serviceRoleArn:l,autoScalingGroups:u,ec2TagFilters:h,deploymentConfigName:y,autoRollbackConfiguration:f,alarmConfiguration:S,loadBalancerInfo:b,blueGreenDeploymentConfiguration:v}=i,w=c||r({slug:s,environment:o,resourceType:"deploy-group"}),E=t(w);return{deploymentGroup:{Type:"AWS::CodeDeploy::DeploymentGroup",Properties:{ApplicationName:k.Ref(n),DeploymentGroupName:w,ServiceRoleArn:l,AutoScalingGroups:u,Ec2TagFilters:h?.map((P)=>({Key:P.key,Value:P.value,Type:P.type})),DeploymentConfigName:y,AutoRollbackConfiguration:f?{Enabled:f.enabled,Events:f.events}:void 0,AlarmConfiguration:S?{Enabled:S.enabled,Alarms:S.alarms?.map((P)=>({Name:P.name})),IgnorePollAlarmFailure:S.ignorePollAlarmFailure}:void 0,LoadBalancerInfo:b?{TargetGroupInfoList:b.targetGroupInfoList?.map((P)=>({Name:P.name})),ElbInfoList:b.elbInfoList?.map((P)=>({Name:P.name}))}:void 0,BlueGreenDeploymentConfiguration:v?{TerminateBlueInstancesOnDeploymentSuccess:v.terminateBlueInstancesOnDeploymentSuccess?{Action:v.terminateBlueInstancesOnDeploymentSuccess.action,TerminationWaitTimeInMinutes:v.terminateBlueInstancesOnDeploymentSuccess.terminationWaitTimeInMinutes}:void 0,DeploymentReadyOption:v.deploymentReadyOption?{ActionOnTimeout:v.deploymentReadyOption.actionOnTimeout,WaitTimeInMinutes:v.deploymentReadyOption.waitTimeInMinutes}:void 0,GreenFleetProvisioningOption:v.greenFleetProvisioningOption?{Action:v.greenFleetProvisioningOption.action}:void 0}:void 0,Tags:[{Key:"Name",Value:w},{Key:"Environment",Value:o}]}},logicalId:E}}static createDeploymentConfig(n){let{slug:i,environment:s,deploymentConfigName:o,minimumHealthyHosts:c,trafficRoutingConfig:l}=n,u=o||r({slug:i,environment:s,resourceType:"deploy-config"}),h=t(u);return{deploymentConfig:{Type:"AWS::CodeDeploy::DeploymentConfig",Properties:{DeploymentConfigName:u,MinimumHealthyHosts:c?{Type:c.type,Value:c.value}:void 0,TrafficRoutingConfig:l?{Type:l.type,TimeBasedCanary:l.timeBasedCanary?{CanaryPercentage:l.timeBasedCanary.canaryPercentage,CanaryInterval:l.timeBasedCanary.canaryInterval}:void 0,TimeBasedLinear:l.timeBasedLinear?{LinearPercentage:l.timeBasedLinear.linearPercentage,LinearInterval:l.timeBasedLinear.linearInterval}:void 0}:void 0}},logicalId:h}}static DeploymentConfigs={allAtOnce:()=>({type:"FLEET_PERCENT",value:0}),halfAtATime:()=>({type:"FLEET_PERCENT",value:50}),oneAtATime:()=>({type:"HOST_COUNT",value:1}),custom:(n,i)=>({type:n,value:i})};static TrafficRouting={allAtOnce:()=>({type:"AllAtOnce"}),canary:(n,i)=>({type:"TimeBasedCanary",timeBasedCanary:{canaryPercentage:n,canaryInterval:i}}),linear:(n,i)=>({type:"TimeBasedLinear",timeBasedLinear:{linearPercentage:n,linearInterval:i}})};static RollbackConfigs={onFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE"]}),onAlarmOrFailure:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM"]}),onAllEvents:()=>({enabled:!0,events:["DEPLOYMENT_FAILURE","DEPLOYMENT_STOP_ON_ALARM","DEPLOYMENT_STOP_ON_REQUEST"]}),disabled:()=>({enabled:!1})};static BlueGreenConfigs={standard:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withDelay:(n)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:n},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),withManualApproval:(n)=>({terminateBlueInstancesOnDeploymentSuccess:{action:"TERMINATE",terminationWaitTimeInMinutes:5},deploymentReadyOption:{actionOnTimeout:"STOP_DEPLOYMENT",waitTimeInMinutes:n},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}}),keepBlue:()=>({terminateBlueInstancesOnDeploymentSuccess:{action:"KEEP_ALIVE"},deploymentReadyOption:{actionOnTimeout:"CONTINUE_DEPLOYMENT",waitTimeInMinutes:0},greenFleetProvisioningOption:{action:"COPY_AUTO_SCALING_GROUP"}})};static UseCases={ec2Deployment:(n,i,s,o)=>{let{application:c,logicalId:l}=G.createApplication({slug:n,environment:i,computePlatform:"Server"}),{deploymentGroup:u,logicalId:h}=G.createDeploymentGroup(l,{slug:n,environment:i,serviceRoleArn:s,autoScalingGroups:o,deploymentConfigName:"CodeDeployDefault.OneAtATime",autoRollbackConfiguration:G.RollbackConfigs.onFailure()});return{application:c,appId:l,deploymentGroup:u,groupId:h}},lambdaCanaryDeployment:(n,i,s,o=10,c=5)=>{let{application:l,logicalId:u}=G.createApplication({slug:n,environment:i,computePlatform:"Lambda"}),{deploymentConfig:h,logicalId:y}=G.createDeploymentConfig({slug:n,environment:i,trafficRoutingConfig:G.TrafficRouting.canary(o,c)}),{deploymentGroup:f,logicalId:S}=G.createDeploymentGroup(u,{slug:n,environment:i,serviceRoleArn:s,deploymentConfigName:k.Ref(y),autoRollbackConfiguration:G.RollbackConfigs.onAlarmOrFailure()});return{application:l,appId:u,deploymentConfig:h,configId:y,deploymentGroup:f,groupId:S}},ecsBlueGreenDeployment:(n,i,s,o)=>{let{application:c,logicalId:l}=G.createApplication({slug:n,environment:i,computePlatform:"ECS"}),{deploymentGroup:u,logicalId:h}=G.createDeploymentGroup(l,{slug:n,environment:i,serviceRoleArn:s,loadBalancerInfo:{targetGroupInfoList:[{name:o}]},blueGreenDeploymentConfiguration:G.BlueGreenConfigs.standard(),autoRollbackConfiguration:G.RollbackConfigs.onFailure()});return{application:c,appId:l,deploymentGroup:u,groupId:h}}};static Strategies={rolling:(n=25)=>({type:"rolling",batchPercentage:n}),blueGreen:()=>({type:"blue-green"}),canary:(n=10,i=5)=>({type:"canary",canaryPercentage:n,canaryInterval:i}),allAtOnce:()=>({type:"all-at-once"})}}class N{static ContentTypes={".html":"text/html",".htm":"text/html",".css":"text/css",".js":"application/javascript",".mjs":"application/javascript",".json":"application/json",".xml":"application/xml",".svg":"image/svg+xml",".png":"image/png",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp",".avif":"image/avif",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".otf":"font/otf",".eot":"application/vnd.ms-fontobject",".pdf":"application/pdf",".txt":"text/plain",".md":"text/markdown",".map":"application/json"};static NoHashPatterns=[/^index\.html$/,/^favicon\.ico$/,/^robots\.txt$/,/^sitemap\.xml$/,/^manifest\.json$/,/^\.well-known\//,/^_redirects$/,/^_headers$/];static computeFileHash(n,i="md5"){let s=st(n);return Nr(i).update(s).digest("hex")}static computeShortHash(n){return N.computeFileHash(n).slice(0,8)}static getContentType(n){let i=ma(n).toLowerCase();return N.ContentTypes[i]||"application/octet-stream"}static shouldHashFile(n,i){return![...N.NoHashPatterns,...i||[]].some((s)=>s.test(n))}static generateHashedFilename(n,i){let s=ma(n),o=Lr(n,s),c=da(n);if(c===".")return`${o}.${i}${s}`;return Je(c,`${o}.${i}${s}`)}static collectFiles(n,i){let s=[],o=i||n;if(!Nt(n))return s;let c=kr(n,{withFileTypes:!0});for(let l of c){let u=Je(n,l.name);if(l.isDirectory())s.push(...N.collectFiles(u,o));else if(l.isFile())s.push(u)}return s}static hashDirectory(n){let{sourceDir:i,outputDir:s,excludePatterns:o=[],hashAlgorithm:c="md5",copyUnhashed:l=!0}=n,u=N.collectFiles(i),h=[],y={};for(let S of u){let b=S.replace(i,"").replace(/^[/\\]/,""),v=N.shouldHashFile(b,o),w=$r(S),E=v?N.computeFileHash(S,c).slice(0,8):"",P=v?N.generateHashedFilename(b,E):b,R={originalPath:b,hashedPath:P,hash:E,size:w.size,contentType:N.getContentType(S)};if(h.push(R),y[b]=P,s){let D=Je(s,P),x=da(D);if(!Nt(x)){let{mkdirSync:I}=ir("node:fs");I(x,{recursive:!0})}if(v||l)Dr(S,D)}}let f={version:"1.0",timestamp:new Date().toISOString(),assets:h,hashMap:y};if(s){let S=Je(s,"asset-manifest.json");ot(S,JSON.stringify(f,null,2))}return f}static getInvalidationPaths(n,i){let s=[];if(!n)return["/*"];let o=n.hashMap,c=i.hashMap;for(let[l,u]of Object.entries(c)){let h=o[l];if(!h||h!==u){if(s.push(`/${l}`),h&&h!==u)s.push(`/${h}`)}}for(let[l,u]of Object.entries(o))if(!c[l])s.push(`/${l}`),s.push(`/${u}`);if(s.length>100)return["/*"];return[...new Set(s)]}static updateHtmlReferences(n){let{htmlDir:i,manifest:s,basePath:o=""}=n,c=N.collectFiles(i).filter((l)=>l.endsWith(".html")||l.endsWith(".htm"));for(let l of c){let u=st(l,"utf-8");for(let[h,y]of Object.entries(s.hashMap)){if(h===y)continue;let f=[new RegExp(`(src|href)=["']${o}/?${N.escapeRegExp(h)}["']`,"g"),new RegExp(`url\\(["']?${o}/?${N.escapeRegExp(h)}["']?\\)`,"g")];for(let S of f)u=u.replace(S,(b)=>b.replace(h,y))}ot(l,u)}}static updateCssReferences(n){let{cssDir:i,manifest:s,basePath:o=""}=n,c=N.collectFiles(i).filter((l)=>l.endsWith(".css"));for(let l of c){let u=st(l,"utf-8");for(let[h,y]of Object.entries(s.hashMap)){if(h===y)continue;let f=new RegExp(`url\\(["']?${o}/?${N.escapeRegExp(h)}["']?\\)`,"g");u=u.replace(f,`url(${o}/${y})`)}ot(l,u)}}static escapeRegExp(n){return n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}static generateS3DeploymentManifest(n){let{sourceDir:i,keyPrefix:s="",excludePatterns:o=[],cacheControl:c={hashed:"public, max-age=31536000, immutable",unhashed:"public, max-age=3600",html:"public, max-age=0, must-revalidate"}}=n;return N.hashDirectory({sourceDir:i,excludePatterns:o}).assets.map((l)=>{let u=l.hash!=="",h=l.contentType==="text/html",y=c.unhashed||"public, max-age=3600";if(h)y=c.html||"public, max-age=0, must-revalidate";else if(u)y=c.hashed||"public, max-age=31536000, immutable";return{localPath:Je(i,l.originalPath),s3Key:s?`${s}/${l.hashedPath}`:l.hashedPath,contentType:l.contentType,cacheControl:y,hash:l.hash}})}static compareManifests(n,i){let s={added:[],removed:[],changed:[],unchanged:[]},o=new Set(Object.keys(n.hashMap)),c=new Set(Object.keys(i.hashMap));for(let l of c)if(!o.has(l))s.added.push(l);for(let l of o)if(!c.has(l))s.removed.push(l);for(let l of c)if(o.has(l))if(n.hashMap[l]!==i.hashMap[l])s.changed.push(l);else s.unchanged.push(l);return s}static loadManifest(n){if(!Nt(n))return null;try{let i=st(n,"utf-8");return JSON.parse(i)}catch{return null}}static saveManifest(n,i){ot(i,JSON.stringify(n,null,2))}}class Pi{static createSecret(n){let{slug:i,environment:s,secretName:o,description:c,secretString:l,kmsKeyId:u,tags:h}=n,y=o||r({slug:i,environment:s,resourceType:"secret"}),f=t(y),S={Type:"AWS::SecretsManager::Secret",Properties:{Name:y,Description:c,SecretString:l,Tags:[{Key:"Name",Value:y},{Key:"Environment",Value:s},...h?Object.entries(h).map(([b,v])=>({Key:b,Value:v})):[]]}};if(u)S.Properties.KmsKeyId=u;return{secret:S,logicalId:f}}static createGeneratedSecret(n){let{slug:i,environment:s,secretName:o,description:c,excludeCharacters:l,excludeLowercase:u,excludeNumbers:h,excludePunctuation:y,excludeUppercase:f,passwordLength:S,requireEachIncludedType:b,kmsKeyId:v,tags:w}=n,E=o||r({slug:i,environment:s,resourceType:"secret"}),P=t(E),R={Type:"AWS::SecretsManager::Secret",Properties:{Name:E,Description:c,GenerateSecretString:{ExcludeCharacters:l,ExcludeLowercase:u,ExcludeNumbers:h,ExcludePunctuation:y,ExcludeUppercase:f,PasswordLength:S||32,RequireEachIncludedType:b!==!1},Tags:[{Key:"Name",Value:E},{Key:"Environment",Value:s},...w?Object.entries(w).map(([D,x])=>({Key:D,Value:x})):[]]}};if(v)R.Properties.KmsKeyId=v;return{secret:R,logicalId:P}}static createDatabaseSecret(n){let{slug:i,environment:s,secretName:o,username:c,dbname:l,engine:u,host:h,port:y,kmsKeyId:f}=n,S=o||r({slug:i,environment:s,resourceType:"db-secret"}),b=t(S),v={username:c};if(l)v.dbname=l;if(u)v.engine=u;if(h)v.host=h;if(y)v.port=y;let w={Type:"AWS::SecretsManager::Secret",Properties:{Name:S,Description:`Database credentials for ${c}`,GenerateSecretString:{SecretStringTemplate:JSON.stringify(v),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\',RequireEachIncludedType:!0},Tags:[{Key:"Name",Value:S},{Key:"Environment",Value:s},{Key:"Type",Value:"database"}]}};if(f)w.Properties.KmsKeyId=f;return{secret:w,logicalId:b}}static attachToDatabase(n){let{slug:i,environment:s,secretId:o,targetId:c,targetType:l}=n,u=r({slug:i,environment:s,resourceType:"secret-attachment"}),h=t(u);return{attachment:{Type:"AWS::SecretsManager::SecretTargetAttachment",Properties:{SecretId:o,TargetId:c,TargetType:l}},logicalId:h}}static enableRotation(n){let{slug:i,environment:s,secretId:o,rotationLambdaArn:c,automaticallyAfterDays:l,rotationType:u,kmsKeyArn:h,vpcSecurityGroupIds:y,vpcSubnetIds:f}=n,S=r({slug:i,environment:s,resourceType:"secret-rotation"}),b=t(S),v={Type:"AWS::SecretsManager::RotationSchedule",Properties:{SecretId:o,RotationRules:{AutomaticallyAfterDays:l||30}}};if(c)v.Properties.RotationLambdaARN=c;else if(u)v.Properties.HostedRotationLambda={RotationType:u,KmsKeyArn:h,VpcSecurityGroupIds:y,VpcSubnetIds:f};return{rotation:v,logicalId:b}}static SecretTypes={apiKey:(n,i,s)=>Pi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-${s}-api-key`,description:`API key for ${s}`,passwordLength:32,excludePunctuation:!0,excludeLowercase:!1,excludeUppercase:!1,excludeNumbers:!1}),oauthClientSecret:(n,i,s)=>Pi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-${s}-oauth-secret`,description:`OAuth client secret for ${s}`,passwordLength:64,excludeCharacters:"\"'`\\/@",requireEachIncludedType:!0}),jwtSecret:(n,i)=>Pi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-jwt-secret`,description:"JWT signing secret",passwordLength:64,excludePunctuation:!0}),encryptionKey:(n,i)=>Pi.createGeneratedSecret({slug:n,environment:i,secretName:`${n}-${i}-encryption-key`,description:"Data encryption key",passwordLength:64,excludeCharacters:"+/=",excludePunctuation:!0})};static RotationTypes={MySQLSingleUser:"MySQLSingleUser",MySQLMultiUser:"MySQLMultiUser",PostgreSQLSingleUser:"PostgreSQLSingleUser",PostgreSQLMultiUser:"PostgreSQLMultiUser",OracleSingleUser:"OracleSingleUser",OracleMultiUser:"OracleMultiUser",MariaDBSingleUser:"MariaDBSingleUser",MariaDBMultiUser:"MariaDBMultiUser",SQLServerSingleUser:"SQLServerSingleUser",SQLServerMultiUser:"SQLServerMultiUser",RedshiftSingleUser:"RedshiftSingleUser",RedshiftMultiUser:"RedshiftMultiUser",MongoDBSingleUser:"MongoDBSingleUser",MongoDBMultiUser:"MongoDBMultiUser"}}class T{static createParameter(n){let{slug:i,environment:s,parameterName:o,value:c,type:l="String",description:u,tier:h="Standard",tags:y}=n,f=o||r({slug:i,environment:s,resourceType:"parameter"}),S=t(f);return{parameter:{Type:"AWS::SSM::Parameter",Properties:{Name:`/${i}/${s}/${f}`,Type:l,Value:c,Description:u,Tier:h,Tags:{Name:f,Environment:s,...y}}},logicalId:S}}static createString(n,i,s,o,c){return T.createParameter({slug:n,environment:i,parameterName:s,value:o,type:"String",description:c})}static createSecureString(n,i,s,o,c){return T.createParameter({slug:n,environment:i,parameterName:s,value:o,type:"SecureString",description:c})}static createStringList(n,i,s,o,c){return T.createParameter({slug:n,environment:i,parameterName:s,value:o.join(","),type:"StringList",description:c})}static Parameters={databaseUrl:(n,i,s)=>T.createSecureString(n,i,"database-url",s,"Database connection URL"),apiEndpoint:(n,i,s)=>T.createString(n,i,"api-endpoint",s,"API endpoint URL"),appVersion:(n,i,s)=>T.createString(n,i,"app-version",s,"Application version"),featureFlags:(n,i,s)=>T.createStringList(n,i,"feature-flags",s,"Enabled feature flags"),apiKey:(n,i,s,o)=>T.createSecureString(n,i,`${s}-api-key`,o,`API key for ${s}`),oauthCredentials:(n,i,s,o)=>{let c=T.createString(n,i,"oauth-client-id",s,"OAuth client ID"),l=T.createSecureString(n,i,"oauth-client-secret",o,"OAuth client secret");return{clientId:c,clientSecret:l}},smtpCredentials:(n,i,s,o,c,l)=>{let u=T.createString(n,i,"smtp-username",s,"SMTP username"),h=T.createSecureString(n,i,"smtp-password",o,"SMTP password"),y=T.createString(n,i,"smtp-host",c,"SMTP host"),f=T.createString(n,i,"smtp-port",l.toString(),"SMTP port");return{username:u,password:h,host:y,port:f}},redisUrl:(n,i,s)=>T.createSecureString(n,i,"redis-url",s,"Redis connection URL"),s3Bucket:(n,i,s)=>T.createString(n,i,"s3-bucket",s,"S3 bucket name"),cloudFrontDistribution:(n,i,s)=>T.createString(n,i,"cloudfront-distribution-id",s,"CloudFront distribution ID")}}class zt{static createDomain(n){let{slug:i,environment:s,domainName:o,engineVersion:c="OpenSearch_2.11",instanceType:l="t3.small.search",instanceCount:u=1,volumeSize:h=10,volumeType:y="gp3",dedicatedMaster:f=!1,dedicatedMasterType:S,dedicatedMasterCount:b=3,multiAz:v=!1,availabilityZoneCount:w=2,vpc:E,encryption:P,enforceHttps:R=!0,tlsSecurityPolicy:D="Policy-Min-TLS-1-2-2019-07",advancedSecurity:x,autoSnapshotHour:I=0,autoTune:_=!0,tags:B={}}=n,W=o||r({slug:i,environment:s,resourceType:"search"}),J=t(W);return{domain:{Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:W,EngineVersion:c,ClusterConfig:{InstanceType:l,InstanceCount:u,DedicatedMasterEnabled:f,...f&&{DedicatedMasterType:S||l,DedicatedMasterCount:b},ZoneAwarenessEnabled:v,...v&&{ZoneAwarenessConfig:{AvailabilityZoneCount:w}}},EBSOptions:{EBSEnabled:!0,VolumeType:y,VolumeSize:h},DomainEndpointOptions:{EnforceHTTPS:R,TLSSecurityPolicy:D},SnapshotOptions:{AutomatedSnapshotStartHour:I},...E&&{VPCOptions:{SubnetIds:E.subnetIds,SecurityGroupIds:E.securityGroupIds}},...P&&{EncryptionAtRestOptions:{Enabled:P.atRest??!0,...P.kmsKeyId&&{KmsKeyId:P.kmsKeyId}},NodeToNodeEncryptionOptions:{Enabled:P.nodeToNode??!0}},...x&&{AdvancedSecurityOptions:{Enabled:x.enabled,InternalUserDatabaseEnabled:x.internalUserDatabase??!0,...x.masterUserName&&x.masterUserPassword&&{MasterUserOptions:{MasterUserName:x.masterUserName,MasterUserPassword:x.masterUserPassword}},...x.masterUserArn&&{MasterUserOptions:{MasterUserARN:x.masterUserArn}}}},..._&&{AutoTuneOptions:{DesiredState:"ENABLED"}},Tags:[{Key:"Name",Value:W},{Key:"Environment",Value:s},...Object.entries(B).map(([K,Y])=>({Key:K,Value:Y}))]}},logicalId:J}}static createAccessPolicy(n,i){let{ipAddresses:s,iamPrincipalArns:o,allowAll:c,vpcEndpoint:l}=i;if(c)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n}]};let u=[];if(o&&o.length>0)u.push({Effect:"Allow",Principal:{AWS:o},Action:"es:*",Resource:n});if(s&&s.length>0)u.push({Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n,Condition:{IpAddress:{"aws:SourceIp":s}}});if(l)return{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:"*"},Action:"es:*",Resource:n}]};return{Version:"2012-10-17",Statement:u}}static DomainPresets={development:(n,i)=>zt.createDomain({slug:n,environment:i,instanceType:"t3.small.search",instanceCount:1,volumeSize:10,multiAz:!1,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!1}),production:(n,i,s)=>zt.createDomain({slug:n,environment:i,instanceType:"m6g.large.search",instanceCount:3,volumeSize:100,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"m6g.large.search",dedicatedMasterCount:3,vpc:s,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!0},autoTune:!0}),costOptimized:(n,i)=>zt.createDomain({slug:n,environment:i,instanceType:"t3.medium.search",instanceCount:2,volumeSize:20,volumeType:"gp3",multiAz:!0,dedicatedMaster:!1,encryption:{atRest:!0,nodeToNode:!0},autoTune:!0}),highPerformance:(n,i,s)=>zt.createDomain({slug:n,environment:i,instanceType:"r6g.2xlarge.search",instanceCount:6,volumeSize:500,volumeType:"gp3",multiAz:!0,availabilityZoneCount:3,dedicatedMaster:!0,dedicatedMasterType:"c6g.xlarge.search",dedicatedMasterCount:3,vpc:s,encryption:{atRest:!0,nodeToNode:!0},advancedSecurity:{enabled:!0,internalUserDatabase:!1},autoTune:!0})};static InstanceTypes={"t3.small.search":"t3.small.search","t3.medium.search":"t3.medium.search","m6g.large.search":"m6g.large.search","m6g.xlarge.search":"m6g.xlarge.search","m6g.2xlarge.search":"m6g.2xlarge.search","r6g.large.search":"r6g.large.search","r6g.xlarge.search":"r6g.xlarge.search","r6g.2xlarge.search":"r6g.2xlarge.search","r6g.4xlarge.search":"r6g.4xlarge.search","c6g.large.search":"c6g.large.search","c6g.xlarge.search":"c6g.xlarge.search","c6g.2xlarge.search":"c6g.2xlarge.search"};static EngineVersions={"OpenSearch_2.11":"OpenSearch_2.11","OpenSearch_2.9":"OpenSearch_2.9","OpenSearch_2.7":"OpenSearch_2.7","OpenSearch_1.3":"OpenSearch_1.3","Elasticsearch_7.10":"Elasticsearch_7.10"}}class At{static createDomainRedirectBucket(n){let{slug:i,environment:s,sourceDomain:o,targetDomain:c,protocol:l="https"}=n,u=r({slug:i,environment:s,resourceType:"s3",suffix:"redirect"}),h=t(u),y=t(`${u}-policy`),f={Type:"AWS::S3::Bucket",Properties:{BucketName:o,WebsiteConfiguration:{RedirectAllRequestsTo:{HostName:c,Protocol:l}},PublicAccessBlockConfiguration:{BlockPublicAcls:!1,BlockPublicPolicy:!1,IgnorePublicAcls:!1,RestrictPublicBuckets:!1},Tags:[{Key:"Name",Value:u},{Key:"Environment",Value:s},{Key:"Purpose",Value:"Domain Redirect"}]}},S={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:k.Ref(h),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadForRedirect",Effect:"Allow",Principal:"*",Action:["s3:GetObject"],Resource:[k.Join("",[k.GetAtt(h,"Arn"),"/*"])]}]}}};return{bucket:f,bucketPolicy:S,logicalId:h,policyLogicalId:y}}static createPathRedirectFunction(n){let{slug:i,environment:s,rules:o}=n,c=r({slug:i,environment:s,resourceType:"cf-redirect"}),l=t(c),u=At.generateRedirectFunctionCode(o);return{function:{Type:"AWS::CloudFront::Function",Properties:{Name:c,AutoPublish:!0,FunctionConfig:{Comment:`Path redirect function for ${i} (${s})`,Runtime:"cloudfront-js-2.0"},FunctionCode:u}},logicalId:l,functionCode:u}}static generateRedirectFunctionCode(n){return`function handler(event) {
2317
2317
  const request = event.request;
2318
2318
  const uri = request.uri;
2319
2319
  const querystring = request.querystring;
@@ -2367,7 +2367,7 @@ ${n.map((i)=>{let s=i.preserveQueryString!==!1,o=i.statusCode||301;return` '${i
2367
2367
  }
2368
2368
 
2369
2369
  return request;
2370
- }`}static CommonRedirects={wwwToApex:(n,i="https")=>({slug:n.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${n}`,targetDomain:n,protocol:i,preservePath:!0}),apexToWww:(n,i="https")=>({slug:n.replace(/\./g,"-"),environment:"production",sourceDomain:n,targetDomain:`www.${n}`,protocol:i,preservePath:!0}),httpToHttps:(n="/")=>({source:n,target:n,statusCode:301}),addTrailingSlash:(n)=>n.map((i)=>({source:i.endsWith("/")?i.slice(0,-1):i,target:i.endsWith("/")?i:`${i}/`,statusCode:301})),removeTrailingSlash:(n)=>n.map((i)=>({source:i.endsWith("/")&&i!=="/"?i:`${i}/`,target:i.endsWith("/")&&i!=="/"?i.slice(0,-1):i,statusCode:301}))};static Patterns={flattenBlogUrls:(n)=>n.map(({oldPath:i,newPath:s})=>({source:i,target:s,statusCode:301,preserveQueryString:!0})),categoryRename:(n,i)=>[{source:`/${n}`,target:`/${i}`,statusCode:301},{source:`/${n}/`,target:`/${i}/`,statusCode:301}],productSlugChange:(n)=>n.map(({oldSlug:i,newSlug:s})=>({source:`/products/${i}`,target:`/products/${s}`,statusCode:301})),apiVersionRedirect:(n,i,s)=>s.map((o)=>({source:`/api/${n}/${o}`,target:`/api/${i}/${o}`,statusCode:307,preserveQueryString:!0})),gonePages:(n)=>n.map((i)=>({source:i,target:"/410",statusCode:301}))};static createRedirectSetup(n){let{slug:i,environment:s,domainRedirects:o=[],pathRedirects:c=[]}=n,l={},u=[];for(let y of o){let{bucket:f,bucketPolicy:b,logicalId:C,policyLogicalId:T}=At.createDomainRedirectBucket({...y,slug:i,environment:s});l[C]=f,l[T]=b,u.push(C)}let h=null;if(c.length>0){let{function:y,logicalId:f}=At.createPathRedirectFunction({slug:i,environment:s,rules:c});l[f]=y,h=f}return{resources:l,outputs:{domainRedirectBuckets:u,pathRedirectFunctionLogicalId:h}}}static fromMapping(n,i){return Object.entries(n).map(([s,o])=>({source:s,target:o,statusCode:i?.statusCode||301,preserveQueryString:i?.preserveQueryString??!0}))}static validateRules(n){let i=[],s=[],o=new Set;for(let c of n){if(o.has(c.source))i.push(`Duplicate source path: ${c.source}`);if(o.add(c.source),c.source===c.target)i.push(`Redirect loop detected: ${c.source} -> ${c.target}`);if(!c.target.startsWith("/")&&!c.target.startsWith("http"))s.push(`Target URL should start with / or http: ${c.target}`);if(!c.source||c.source.trim()==="")i.push("Source path cannot be empty");if(!c.target||c.target.trim()==="")i.push("Target path cannot be empty")}for(let c of n){let l=n.find((u)=>u.source===c.target);if(l)s.push(`Potential redirect chain: ${c.source} -> ${c.target} -> ${l.target}`)}return{valid:i.length===0,errors:i,warnings:s}}}class q{static generate(n){let i={},{slug:s,environment:o,region:c="us-east-1"}=n,l=q.createLambdaExecutionRole(s,o);if(Object.assign(i,l.resources),n.email?.enabled){let u=q.generateEmailResources(n,l.roleArn);Object.assign(i,u)}if(n.phone?.enabled){let u=q.generatePhoneResources(n,l.roleArn);Object.assign(i,u)}if(n.sms?.enabled){let u=q.generateSmsResources(n,l.roleArn);Object.assign(i,u)}return i}static createLambdaExecutionRole(n,i){let s=`${n}-${i}-communication-role`,o=t(s);return{resources:{[o]:{Type:"AWS::IAM::Role",Properties:{RoleName:s,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:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:k.GetAtt(o,"Arn"),roleName:s}}static generateEmailResources(n,i){let{slug:s,environment:o,email:c}=n;if(!c)return{};let l={},u=`${s}-${o}`,h=`${u}-email-storage`,y=t(h);l[y]={Type:"AWS::S3::Bucket",Properties:{BucketName:h,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:c.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:c.server.storage.archiveAfterDays}]:[],ExpirationInDays:c.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let f=t(`${u}-ses-identity`);if(l[f]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:c.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},c.notifications?.bounces||c.notifications?.complaints){let b=t(`${u}-bounce-topic`);l[b]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-email-bounces`}};let C=t(`${u}-complaint-topic`);l[C]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-email-complaints`}}}if(c.server?.enabled){let b=t(`${u}-inbound-email`);l[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:60,MemorySize:256,Code:{ZipFile:q.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:h,DOMAIN:c.domain}}}};let C=t(`${u}-outbound-email`);l[C]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:q.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:h,DOMAIN:c.domain}}}}}if(c.advanced?.analytics){let b=t(`${u}-email-analytics`);l[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.scheduling){let b=t(`${u}-email-scheduler`);l[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:300,MemorySize:256,Code:{ZipFile:q.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:h}}}};let C=t(`${u}-email-scheduler-rule`);l[C]={Type:"AWS::Events::Rule",Properties:{Name:`${u}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:k.GetAtt(b,"Arn")}]}}}if(c.advanced?.threading){let b=t(`${u}-email-threading`);l[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:60,MemorySize:256,Code:{ZipFile:q.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:h}}}}}if(c.advanced?.rules){let b=t(`${u}-email-rules`);l[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}if(c.advanced?.sharedMailboxes){let b=t(`${u}-shared-mailboxes`);l[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}]}}}if(c.advanced?.search){let b=t(`${u}-email-search`);l[b]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${u}-email-search`.toLowerCase().replace(/[^a-z0-9-]/g,"-").substring(0,28),EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:"t3.small.search",InstanceCount:1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:10},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0}}}}return l}static generatePhoneResources(n,i){let{slug:s,environment:o,phone:c}=n;if(!c)return{};let l={},u=`${s}-${o}`,h=t(`${u}-call-log`);if(l[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},c.voicemail?.enabled){let b=t(`${u}-voicemail`);l[b]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${u}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let y=t(`${u}-phone-notifications`);l[y]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-phone-notifications`}};let f=t(`${u}-incoming-call`);if(l[f]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:q.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${u}-call-log`,NOTIFICATION_TOPIC_ARN:k.Ref(y)}}}},c.voicemail?.enabled){let b=t(`${u}-voicemail-handler`);l[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:q.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${u}-voicemail`,TRANSCRIPTION_ENABLED:String(c.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:k.Ref(y)}}}}}if(c.advanced?.recording){let b=t(`${u}-call-recordings`);l[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.callbacks){let b=t(`${u}-callbacks`);l[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.analytics){let b=t(`${u}-call-metrics`);l[b]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return l}static generateSmsResources(n,i){let{slug:s,environment:o,sms:c}=n;if(!c)return{};let l={},u=`${s}-${o}`,h=t(`${u}-pinpoint-app`);l[h]={Type:"AWS::Pinpoint::App",Properties:{Name:`${u}-sms`}};let y=t(`${u}-sms-channel`);l[y]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:k.Ref(h),Enabled:!0,SenderId:c.senderId}};let f=t(`${u}-sms-log`);if(l[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},c.optOut?.enabled){let w=t(`${u}-sms-optout`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let b=t(`${u}-sms-notifications`);l[b]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-sms-notifications`}};let C=t(`${u}-send-sms`);l[C]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:q.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:k.Ref(h),MESSAGE_LOG_TABLE:`${u}-sms-log`,OPT_OUT_TABLE:c.optOut?.enabled?`${u}-sms-optout`:"",MESSAGE_TYPE:c.messageType||"TRANSACTIONAL"}}}};let T=t(`${u}-receive-sms`);if(l[T]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:q.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${u}-sms-log`,OPT_OUT_TABLE:c.optOut?.enabled?`${u}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:k.Ref(b)}}}},c.advanced?.campaigns){let w=t(`${u}-sms-campaigns`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.analytics){let w=t(`${u}-sms-analytics`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.linkTracking){let w=t(`${u}-short-links`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.chatbot){let w=t(`${u}-chatbot-sessions`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let E=t(`${u}-chatbot-rules`);l[E]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.abTesting){let w=t(`${u}-ab-tests`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.mms){let w=t(`${u}-mms-media`);l[w]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${u}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return l}static InboundEmailCode=`
2370
+ }`}static CommonRedirects={wwwToApex:(n,i="https")=>({slug:n.replace(/\./g,"-"),environment:"production",sourceDomain:`www.${n}`,targetDomain:n,protocol:i,preservePath:!0}),apexToWww:(n,i="https")=>({slug:n.replace(/\./g,"-"),environment:"production",sourceDomain:n,targetDomain:`www.${n}`,protocol:i,preservePath:!0}),httpToHttps:(n="/")=>({source:n,target:n,statusCode:301}),addTrailingSlash:(n)=>n.map((i)=>({source:i.endsWith("/")?i.slice(0,-1):i,target:i.endsWith("/")?i:`${i}/`,statusCode:301})),removeTrailingSlash:(n)=>n.map((i)=>({source:i.endsWith("/")&&i!=="/"?i:`${i}/`,target:i.endsWith("/")&&i!=="/"?i.slice(0,-1):i,statusCode:301}))};static Patterns={flattenBlogUrls:(n)=>n.map(({oldPath:i,newPath:s})=>({source:i,target:s,statusCode:301,preserveQueryString:!0})),categoryRename:(n,i)=>[{source:`/${n}`,target:`/${i}`,statusCode:301},{source:`/${n}/`,target:`/${i}/`,statusCode:301}],productSlugChange:(n)=>n.map(({oldSlug:i,newSlug:s})=>({source:`/products/${i}`,target:`/products/${s}`,statusCode:301})),apiVersionRedirect:(n,i,s)=>s.map((o)=>({source:`/api/${n}/${o}`,target:`/api/${i}/${o}`,statusCode:307,preserveQueryString:!0})),gonePages:(n)=>n.map((i)=>({source:i,target:"/410",statusCode:301}))};static createRedirectSetup(n){let{slug:i,environment:s,domainRedirects:o=[],pathRedirects:c=[]}=n,l={},u=[];for(let y of o){let{bucket:f,bucketPolicy:S,logicalId:b,policyLogicalId:v}=At.createDomainRedirectBucket({...y,slug:i,environment:s});l[b]=f,l[v]=S,u.push(b)}let h=null;if(c.length>0){let{function:y,logicalId:f}=At.createPathRedirectFunction({slug:i,environment:s,rules:c});l[f]=y,h=f}return{resources:l,outputs:{domainRedirectBuckets:u,pathRedirectFunctionLogicalId:h}}}static fromMapping(n,i){return Object.entries(n).map(([s,o])=>({source:s,target:o,statusCode:i?.statusCode||301,preserveQueryString:i?.preserveQueryString??!0}))}static validateRules(n){let i=[],s=[],o=new Set;for(let c of n){if(o.has(c.source))i.push(`Duplicate source path: ${c.source}`);if(o.add(c.source),c.source===c.target)i.push(`Redirect loop detected: ${c.source} -> ${c.target}`);if(!c.target.startsWith("/")&&!c.target.startsWith("http"))s.push(`Target URL should start with / or http: ${c.target}`);if(!c.source||c.source.trim()==="")i.push("Source path cannot be empty");if(!c.target||c.target.trim()==="")i.push("Target path cannot be empty")}for(let c of n){let l=n.find((u)=>u.source===c.target);if(l)s.push(`Potential redirect chain: ${c.source} -> ${c.target} -> ${l.target}`)}return{valid:i.length===0,errors:i,warnings:s}}}class q{static generate(n){let i={},{slug:s,environment:o,region:c="us-east-1"}=n,l=q.createLambdaExecutionRole(s,o);if(Object.assign(i,l.resources),n.email?.enabled){let u=q.generateEmailResources(n,l.roleArn);Object.assign(i,u)}if(n.phone?.enabled){let u=q.generatePhoneResources(n,l.roleArn);Object.assign(i,u)}if(n.sms?.enabled){let u=q.generateSmsResources(n,l.roleArn);Object.assign(i,u)}return i}static createLambdaExecutionRole(n,i){let s=`${n}-${i}-communication-role`,o=t(s);return{resources:{[o]:{Type:"AWS::IAM::Role",Properties:{RoleName:s,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:"CommunicationPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:"*"},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail","ses:GetIdentityVerificationAttributes"],Resource:"*"},{Effect:"Allow",Action:["sns:Publish","sns:Subscribe"],Resource:"*"},{Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchWriteItem","dynamodb:BatchGetItem"],Resource:"*"},{Effect:"Allow",Action:["connect:*"],Resource:"*"},{Effect:"Allow",Action:["mobiletargeting:SendMessages","mobiletargeting:GetEndpoint","mobiletargeting:UpdateEndpoint"],Resource:"*"},{Effect:"Allow",Action:["transcribe:StartTranscriptionJob","transcribe:GetTranscriptionJob"],Resource:"*"},{Effect:"Allow",Action:["bedrock:InvokeModel"],Resource:"*"},{Effect:"Allow",Action:["es:ESHttpGet","es:ESHttpPost","es:ESHttpPut","es:ESHttpDelete"],Resource:"*"}]}}]}}},roleArn:k.GetAtt(o,"Arn"),roleName:s}}static generateEmailResources(n,i){let{slug:s,environment:o,email:c}=n;if(!c)return{};let l={},u=`${s}-${o}`,h=`${u}-email-storage`,y=t(h);l[y]={Type:"AWS::S3::Bucket",Properties:{BucketName:h,LifecycleConfiguration:{Rules:[{Id:"ArchiveOldEmails",Status:"Enabled",Transitions:c.server?.storage?.archiveAfterDays?[{StorageClass:"GLACIER",TransitionInDays:c.server.storage.archiveAfterDays}]:[],ExpirationInDays:c.server?.storage?.retentionDays||365}]},NotificationConfiguration:{LambdaConfigurations:[]}}};let f=t(`${u}-ses-identity`);if(l[f]={Type:"AWS::SES::EmailIdentity",Properties:{EmailIdentity:c.domain,DkimSigningAttributes:{NextSigningKeyLength:"RSA_2048_BIT"},FeedbackAttributes:{EmailForwardingEnabled:!0}}},c.notifications?.bounces||c.notifications?.complaints){let S=t(`${u}-bounce-topic`);l[S]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-email-bounces`}};let b=t(`${u}-complaint-topic`);l[b]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-email-complaints`}}}if(c.server?.enabled){let S=t(`${u}-inbound-email`);l[S]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-inbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:60,MemorySize:256,Code:{ZipFile:q.InboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:h,DOMAIN:c.domain}}}};let b=t(`${u}-outbound-email`);l[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-outbound-email`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:q.OutboundEmailCode},Environment:{Variables:{EMAIL_BUCKET:h,DOMAIN:c.domain}}}}}if(c.advanced?.analytics){let S=t(`${u}-email-analytics`);l[S]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-email-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.scheduling){let S=t(`${u}-email-scheduler`);l[S]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-email-scheduler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:300,MemorySize:256,Code:{ZipFile:q.EmailSchedulerCode},Environment:{Variables:{EMAIL_BUCKET:h}}}};let b=t(`${u}-email-scheduler-rule`);l[b]={Type:"AWS::Events::Rule",Properties:{Name:`${u}-email-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"EmailSchedulerTarget",Arn:k.GetAtt(S,"Arn")}]}}}if(c.advanced?.threading){let S=t(`${u}-email-threading`);l[S]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:60,MemorySize:256,Code:{ZipFile:q.EmailThreadingCode},Environment:{Variables:{EMAIL_BUCKET:h}}}}}if(c.advanced?.rules){let S=t(`${u}-email-rules`);l[S]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-email-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"mailbox",AttributeType:"S"},{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"mailbox",KeyType:"HASH"},{AttributeName:"id",KeyType:"RANGE"}]}}}if(c.advanced?.sharedMailboxes){let S=t(`${u}-shared-mailboxes`);l[S]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-shared-mailboxes`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"},{AttributeName:"type",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],GlobalSecondaryIndexes:[{IndexName:"type-index",KeySchema:[{AttributeName:"type",KeyType:"HASH"}],Projection:{ProjectionType:"ALL"}}]}}}if(c.advanced?.search){let S=t(`${u}-email-search`);l[S]={Type:"AWS::OpenSearchService::Domain",Properties:{DomainName:`${u}-email-search`.toLowerCase().replace(/[^a-z0-9-]/g,"-").substring(0,28),EngineVersion:"OpenSearch_2.11",ClusterConfig:{InstanceType:"t3.small.search",InstanceCount:1},EBSOptions:{EBSEnabled:!0,VolumeType:"gp3",VolumeSize:10},NodeToNodeEncryptionOptions:{Enabled:!0},EncryptionAtRestOptions:{Enabled:!0},DomainEndpointOptions:{EnforceHTTPS:!0}}}}return l}static generatePhoneResources(n,i){let{slug:s,environment:o,phone:c}=n;if(!c)return{};let l={},u=`${s}-${o}`,h=t(`${u}-call-log`);if(l[h]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-call-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"contactId",AttributeType:"S"}],KeySchema:[{AttributeName:"contactId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},c.voicemail?.enabled){let S=t(`${u}-voicemail`);l[S]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${u}-voicemail`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldVoicemails",Status:"Enabled",ExpirationInDays:90}]}}}}let y=t(`${u}-phone-notifications`);l[y]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-phone-notifications`}};let f=t(`${u}-incoming-call`);if(l[f]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-incoming-call`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:q.IncomingCallCode},Environment:{Variables:{CALL_LOG_TABLE:`${u}-call-log`,NOTIFICATION_TOPIC_ARN:k.Ref(y)}}}},c.voicemail?.enabled){let S=t(`${u}-voicemail-handler`);l[S]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-voicemail-handler`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:c.voicemail.transcription?300:60,MemorySize:256,Code:{ZipFile:q.VoicemailCode},Environment:{Variables:{VOICEMAIL_BUCKET:`${u}-voicemail`,TRANSCRIPTION_ENABLED:String(c.voicemail.transcription||!1),NOTIFICATION_TOPIC_ARN:k.Ref(y)}}}}}if(c.advanced?.recording){let S=t(`${u}-call-recordings`);l[S]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-call-recordings`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"recordingId",AttributeType:"S"}],KeySchema:[{AttributeName:"recordingId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.callbacks){let S=t(`${u}-callbacks`);l[S]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-callbacks`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.analytics){let S=t(`${u}-call-metrics`);l[S]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-call-metrics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}return l}static generateSmsResources(n,i){let{slug:s,environment:o,sms:c}=n;if(!c)return{};let l={},u=`${s}-${o}`,h=t(`${u}-pinpoint-app`);l[h]={Type:"AWS::Pinpoint::App",Properties:{Name:`${u}-sms`}};let y=t(`${u}-sms-channel`);l[y]={Type:"AWS::Pinpoint::SMSChannel",Properties:{ApplicationId:k.Ref(h),Enabled:!0,SenderId:c.senderId}};let f=t(`${u}-sms-log`);if(l[f]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-sms-log`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"messageId",AttributeType:"S"}],KeySchema:[{AttributeName:"messageId",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}},c.optOut?.enabled){let w=t(`${u}-sms-optout`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-sms-optout`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}]}}}let S=t(`${u}-sms-notifications`);l[S]={Type:"AWS::SNS::Topic",Properties:{TopicName:`${u}-sms-notifications`}};let b=t(`${u}-send-sms`);l[b]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-send-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:q.SendSmsCode},Environment:{Variables:{PINPOINT_APP_ID:k.Ref(h),MESSAGE_LOG_TABLE:`${u}-sms-log`,OPT_OUT_TABLE:c.optOut?.enabled?`${u}-sms-optout`:"",MESSAGE_TYPE:c.messageType||"TRANSACTIONAL"}}}};let v=t(`${u}-receive-sms`);if(l[v]={Type:"AWS::Lambda::Function",Properties:{FunctionName:`${u}-receive-sms`,Runtime:"nodejs20.x",Handler:"index.handler",Role:i,Timeout:30,MemorySize:256,Code:{ZipFile:q.ReceiveSmsCode},Environment:{Variables:{MESSAGE_LOG_TABLE:`${u}-sms-log`,OPT_OUT_TABLE:c.optOut?.enabled?`${u}-sms-optout`:"",NOTIFICATION_TOPIC_ARN:k.Ref(S)}}}},c.advanced?.campaigns){let w=t(`${u}-sms-campaigns`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-sms-campaigns`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.analytics){let w=t(`${u}-sms-analytics`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-sms-analytics`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"period",AttributeType:"S"}],KeySchema:[{AttributeName:"period",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.linkTracking){let w=t(`${u}-short-links`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-short-links`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}}}if(c.advanced?.chatbot){let w=t(`${u}-chatbot-sessions`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-chatbot-sessions`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"phoneNumber",AttributeType:"S"}],KeySchema:[{AttributeName:"phoneNumber",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"ttl",Enabled:!0}}};let E=t(`${u}-chatbot-rules`);l[E]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-chatbot-rules`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.abTesting){let w=t(`${u}-ab-tests`);l[w]={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${u}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}if(c.advanced?.mms){let w=t(`${u}-mms-media`);l[w]={Type:"AWS::S3::Bucket",Properties:{BucketName:`${u}-mms-media`,LifecycleConfiguration:{Rules:[{Id:"DeleteOldMedia",Status:"Enabled",ExpirationInDays:30}]}}}}return l}static InboundEmailCode=`
2371
2371
  const { S3Client, GetObjectCommand, PutObjectCommand } = require('@aws-sdk/client-s3');
2372
2372
  const s3 = new S3Client({});
2373
2373
  exports.handler = async (event) => {
@@ -2480,19 +2480,19 @@ rpm -U ./amazon-cloudwatch-agent.rpm || true
2480
2480
 
2481
2481
  # Signal completion
2482
2482
  /opt/aws/bin/cfn-signal -e $? --stack \${AWS::StackName} --resource AutoScalingGroup --region \${AWS::Region}
2483
- `;if(n.addResource("LaunchTemplate","AWS::EC2::LaunchTemplate",{LaunchTemplateName:e.sub("${AWS::StackName}-template"),LaunchTemplateData:{ImageId:i.ami||e.findInMap("RegionMap",e.ref("AWS::Region"),"AMI"),InstanceType:i.instanceType,IamInstanceProfile:{Arn:e.getAtt("EC2InstanceProfile","Arn")},SecurityGroupIds:[e.ref("AppSecurityGroup")],UserData:e.base64(e.sub(s)),TagSpecifications:[{ResourceType:"instance",Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-instance")}]}],MetadataOptions:{HttpTokens:"required",HttpPutResponseHopLimit:1}}},{dependsOn:["AppSecurityGroup","EC2InstanceProfile"]}),i.loadBalancer){en(n,i.loadBalancer);let o={LaunchTemplate:{LaunchTemplateId:e.ref("LaunchTemplate"),Version:e.getAtt("LaunchTemplate","LatestVersionNumber")},MinSize:i.autoScaling?.min.toString()||"1",MaxSize:i.autoScaling?.max.toString()||"3",DesiredCapacity:i.autoScaling?.min.toString()||"2",VPCZoneIdentifier:[e.ref("PrivateSubnet1"),e.ref("PrivateSubnet2")],TargetGroupARNs:[e.ref("TargetGroup")],HealthCheckType:"ELB",HealthCheckGracePeriod:300,Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-asg"),PropagateAtLaunch:!0}]};if(n.addResource("AutoScalingGroup","AWS::AutoScaling::AutoScalingGroup",o,{dependsOn:["LaunchTemplate","TargetGroup"]}),i.autoScaling)n.addResource("ScaleUpPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:e.ref("AutoScalingGroup"),Cooldown:i.autoScaling.scaleUpCooldown?.toString()||"300",ScalingAdjustment:"1"},{dependsOn:"AutoScalingGroup"}),n.addResource("ScaleDownPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:e.ref("AutoScalingGroup"),Cooldown:i.autoScaling.scaleDownCooldown?.toString()||"300",ScalingAdjustment:"-1"},{dependsOn:"AutoScalingGroup"}),n.addResource("HighCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale up when CPU exceeds target",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:(i.autoScaling.targetCPU||70).toString(),AlarmActions:[e.ref("ScaleUpPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:e.ref("AutoScalingGroup")}],ComparisonOperator:"GreaterThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleUpPolicy"]}),n.addResource("LowCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale down when CPU is below threshold",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:((i.autoScaling.targetCPU||70)-20).toString(),AlarmActions:[e.ref("ScaleDownPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:e.ref("AutoScalingGroup")}],ComparisonOperator:"LessThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleDownPolicy"]})}}function en(n,i){if(!i)return;n.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for Application Load Balancer",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"}),n.addResource("LoadBalancer","AWS::ElasticLoadBalancingV2::LoadBalancer",{Name:e.sub("${AWS::StackName}-alb"),Type:i.type||"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[e.ref("PublicSubnet1"),e.ref("PublicSubnet2")],SecurityGroups:[e.ref("ALBSecurityGroup")],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-alb")}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]}),n.addResource("TargetGroup","AWS::ElasticLoadBalancingV2::TargetGroup",{Name:e.sub("${AWS::StackName}-tg"),Port:3000,Protocol:"HTTP",VpcId:e.ref("VPC"),HealthCheckEnabled:!0,HealthCheckPath:i.healthCheck?.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:i.healthCheck?.interval||30,HealthCheckTimeoutSeconds:i.healthCheck?.timeout||5,HealthyThresholdCount:i.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:i.healthCheck?.unhealthyThreshold||3,TargetType:"instance",Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-tg")}]},{dependsOn:"VPC"}),n.addResource("LoadBalancerListener","AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:e.ref("LoadBalancer"),Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:e.ref("TargetGroup")}]},{dependsOn:["LoadBalancer","TargetGroup"]}),n.addOutputs({LoadBalancerDNS:{Description:"Load Balancer DNS Name",Value:e.getAtt("LoadBalancer","DNSName"),Export:{Name:e.sub("${AWS::StackName}-alb-dns")}}})}function pa(n,i,s){let o=n.toLogicalId(i),c=s.taskDefinition.containerDefinitions?.[0],l=c?.name||c?.Name||i,u=c?.portMappings?.[0]?.containerPort||c?.PortMappings?.[0]?.ContainerPort||3000,h=(s.taskDefinition.containerDefinitions||[]).flatMap((T)=>(T.secrets||T.Secrets||[]).map((w)=>w.valueFrom||w.ValueFrom)).filter(Boolean);if(!n.hasResource("ECSCluster"))n.addResource("ECSCluster","AWS::ECS::Cluster",{ClusterName:e.sub("${AWS::StackName}-cluster"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-cluster")}]});if(n.addResource(`${o}TaskExecutionRole`,"AWS::IAM::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"],...h.length?{Policies:[{PolicyName:"read-task-secrets",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameters"],Resource:h},{Effect:"Allow",Action:"kms:Decrypt",Resource:"*"}]}}]}:{}}),n.addResource(`${o}TaskRole`,"AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"application-services",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:SendMessage"],Resource:e.sub("arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${AWS::StackName}-*")},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:"*"}]}}]}),!n.hasResource("ALBSecurityGroup"))n.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Public ingress for the application load balancer",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},...s.loadBalancer?.customDomain?.certificateArn?[{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}]:[]],SecurityGroupEgress:[{IpProtocol:"tcp",FromPort:u,ToPort:u,CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"});if(!n.hasResource("AppSecurityGroup"))n.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Only the application load balancer may reach Fargate tasks",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:u,ToPort:u,SourceSecurityGroupId:e.ref("ALBSecurityGroup")}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-app-sg")}]},{dependsOn:["VPC","ALBSecurityGroup"]});let y=(s.taskDefinition.containerDefinitions||[{name:i,image:e.sub(`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${i}:latest`),portMappings:[{containerPort:3000}]}]).map((T)=>({Name:T.Name||T.name,Image:T.Image||T.image,Essential:T.Essential??T.essential??!0,PortMappings:(T.PortMappings||T.portMappings||[]).map((w)=>({ContainerPort:w.ContainerPort??w.containerPort,Protocol:w.Protocol||w.protocol||"tcp"})),Environment:Array.isArray(T.Environment||T.environment)?(T.Environment||T.environment).map((w)=>({Name:w.Name||w.name,Value:w.Value??w.value})):Object.entries(T.Environment||T.environment||{}).map(([w,E])=>({Name:w,Value:E})),Secrets:(T.Secrets||T.secrets||[]).map((w)=>({Name:w.Name||w.name,ValueFrom:w.ValueFrom||w.valueFrom})),HealthCheck:T.HealthCheck||T.healthCheck,Command:T.Command||T.command,EntryPoint:T.EntryPoint||T.entryPoint,LogConfiguration:T.LogConfiguration||T.logConfiguration||{LogDriver:"awslogs",Options:{"awslogs-group":e.ref(`${o}LogGroup`),"awslogs-region":e.ref("AWS::Region"),"awslogs-stream-prefix":i}}}));n.addResource(`${o}TaskDefinition`,"AWS::ECS::TaskDefinition",{Family:e.sub(`\${AWS::StackName}-${i}`),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:s.taskDefinition.cpu,Memory:s.taskDefinition.memory,ExecutionRoleArn:e.getAtt(`${o}TaskExecutionRole`,"Arn"),TaskRoleArn:e.getAtt(`${o}TaskRole`,"Arn"),ContainerDefinitions:y},{dependsOn:[`${o}TaskExecutionRole`,`${o}TaskRole`,`${o}LogGroup`]}),n.addResource(`${o}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:e.sub(`/ecs/\${AWS::StackName}/${i}`),RetentionInDays:14});let f=s.service.healthCheck||{};n.addResource(`${o}TargetGroup`,"AWS::ElasticLoadBalancingV2::TargetGroup",{VpcId:e.ref("VPC"),Port:u,Protocol:"HTTP",TargetType:"ip",HealthCheckEnabled:!0,HealthCheckPath:f.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:f.interval||30,HealthCheckTimeoutSeconds:f.timeout||5,HealthyThresholdCount:f.healthyThreshold||2,UnhealthyThresholdCount:f.unhealthyThreshold||3,Matcher:{HttpCode:"200-399"},TargetGroupAttributes:[{Key:"deregistration_delay.timeout_seconds",Value:"30"}]},{dependsOn:"VPC"}),n.addResource(`${o}LoadBalancer`,"AWS::ElasticLoadBalancingV2::LoadBalancer",{Type:"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[e.ref("PublicSubnet1"),e.ref("PublicSubnet2")],SecurityGroups:[e.ref("ALBSecurityGroup")],LoadBalancerAttributes:[{Key:"routing.http.drop_invalid_header_fields.enabled",Value:"true"},{Key:"deletion_protection.enabled",Value:String(s.loadBalancer?.deletionProtection===!0)}],Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-alb`)}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]});let b=s.loadBalancer?.customDomain?.certificateArn,C=s.loadBalancer?.originVerifyHeader;if(n.addResource(`${o}HttpListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:e.ref(`${o}LoadBalancer`),Port:80,Protocol:"HTTP",DefaultActions:b?[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]:C?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:e.ref(`${o}TargetGroup`)}]},{dependsOn:[`${o}LoadBalancer`,`${o}TargetGroup`]}),b)n.addResource(`${o}HttpsListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:e.ref(`${o}LoadBalancer`),Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:b}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06",DefaultActions:C?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:e.ref(`${o}TargetGroup`)}]},{dependsOn:[`${o}LoadBalancer`,`${o}TargetGroup`]});if(C){let T=b?`${o}HttpsListener`:`${o}HttpListener`;n.addResource(`${o}OriginVerifyRule`,"AWS::ElasticLoadBalancingV2::ListenerRule",{ListenerArn:e.ref(T),Priority:1,Conditions:[{Field:"http-header",HttpHeaderConfig:{HttpHeaderName:C.name,Values:[C.value]}}],Actions:[{Type:"forward",TargetGroupArn:e.ref(`${o}TargetGroup`)}]},{dependsOn:[T,`${o}TargetGroup`]})}if(n.addResource(`${o}Service`,"AWS::ECS::Service",{ServiceName:e.sub(`\${AWS::StackName}-${i}`),Cluster:e.ref("ECSCluster"),TaskDefinition:e.ref(`${o}TaskDefinition`),DesiredCount:s.service.desiredCount,LaunchType:"FARGATE",PlatformVersion:"LATEST",HealthCheckGracePeriodSeconds:60,DeploymentConfiguration:{MinimumHealthyPercent:100,MaximumPercent:200,DeploymentCircuitBreaker:{Enable:!0,Rollback:!0}},LoadBalancers:[{ContainerName:l,ContainerPort:u,TargetGroupArn:e.ref(`${o}TargetGroup`)}],NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"DISABLED",Subnets:[e.ref("PrivateSubnet1"),e.ref("PrivateSubnet2")],SecurityGroups:[e.ref("AppSecurityGroup")]}}},{dependsOn:["ECSCluster",`${o}TaskDefinition`,C?`${o}OriginVerifyRule`:b?`${o}HttpsListener`:`${o}HttpListener`]}),s.service.autoScaling){let T=s.service.autoScaling;n.addResource(`${o}ScalableTarget`,"AWS::ApplicationAutoScaling::ScalableTarget",{MinCapacity:T.min,MaxCapacity:T.max,ResourceId:e.join("/",["service",e.ref("ECSCluster"),e.getAtt(`${o}Service`,"Name")]),RoleARN:e.sub("arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"),ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},{dependsOn:`${o}Service`}),n.addResource(`${o}ScalingPolicy`,"AWS::ApplicationAutoScaling::ScalingPolicy",{PolicyType:"TargetTrackingScaling",ScalingTargetId:e.ref(`${o}ScalableTarget`),TargetTrackingScalingPolicyConfiguration:{TargetValue:T.targetCPU||70,PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},ScaleInCooldown:60,ScaleOutCooldown:30}},{dependsOn:`${o}ScalableTarget`})}n.addOutputs({[`${o}ClusterName`]:{Description:"ECS cluster name",Value:e.ref("ECSCluster")},[`${o}ServiceName`]:{Description:"ECS service name",Value:e.getAtt(`${o}Service`,"Name")},[`${o}LoadBalancerDnsName`]:{Description:"ALB origin hostname",Value:e.getAtt(`${o}LoadBalancer`,"DNSName")},[`${o}LoadBalancerHostedZoneId`]:{Description:"ALB canonical hosted zone ID",Value:e.getAtt(`${o}LoadBalancer`,"CanonicalHostedZoneID")},[`${o}TargetGroupArn`]:{Description:"ECS target group ARN",Value:e.ref(`${o}TargetGroup`)}})}function tn(n,i){if(i.postgres)ga(n,"postgres",i.postgres);if(i.mysql)ga(n,"mysql",i.mysql);if(i.dynamodb?.tables)i.dynamodb.tables.forEach((s)=>{an(n,s)})}function ga(n,i,s){if(!s)return;let o=i==="postgres"?"postgres":"mysql",c=n.toLogicalId(`${o}-db`);n.addResource("DBSubnetGroup","AWS::RDS::DBSubnetGroup",{DBSubnetGroupDescription:"Subnet group for RDS instance",SubnetIds:[e.ref("PrivateSubnet1"),e.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-db-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),n.addResource("DBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for RDS instance",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:i==="postgres"?5432:3306,ToPort:i==="postgres"?5432:3306,SourceSecurityGroupId:e.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-db-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});let l=i==="postgres"?`postgres${s.version.split(".")[0]}`:`mysql${s.version.split(".")[0]}.${s.version.split(".")[1]||"0"}`;if(s.parameters&&Object.keys(s.parameters).length>0)n.addResource("DBParameterGroup","AWS::RDS::DBParameterGroup",{Description:`Parameter group for ${o}`,Family:l,Parameters:s.parameters,Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-db-params")}]});n.addResource("DBSecret","AWS::SecretsManager::Secret",{Description:"Database credentials",GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"admin"}),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\'},Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-db-secret")}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"});let u={Engine:o,EngineVersion:s.version,DBInstanceClass:s.instanceClass,AllocatedStorage:s.allocatedStorage.toString(),MaxAllocatedStorage:s.maxAllocatedStorage?.toString(),StorageType:"gp3",StorageEncrypted:!0,MultiAZ:s.multiAZ!==!1,DBSubnetGroupName:e.ref("DBSubnetGroup"),VPCSecurityGroups:[e.ref("DBSecurityGroup")],MasterUsername:e.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:username}}"),MasterUserPassword:e.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:password}}"),BackupRetentionPeriod:s.backupRetentionDays||7,PreferredBackupWindow:s.preferredBackupWindow||"03:00-04:00",PreferredMaintenanceWindow:s.preferredMaintenanceWindow||"sun:04:00-sun:05:00",EnablePerformanceInsights:s.enablePerformanceInsights!==!1,PerformanceInsightsRetentionPeriod:s.performanceInsightsRetention||7,DeletionProtection:s.deletionProtection!==!1,CopyTagsToSnapshot:!0,EnableCloudwatchLogsExports:i==="postgres"?["postgresql"]:["error","general","slowquery"],Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${o}-db`)}]};if(s.parameters&&Object.keys(s.parameters).length>0)u.DBParameterGroupName=e.ref("DBParameterGroup");n.addResource(c,"AWS::RDS::DBInstance",u,{dependsOn:["DBSubnetGroup","DBSecurityGroup","DBSecret"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),n.addResource("DBSecretAttachment","AWS::SecretsManager::SecretTargetAttachment",{SecretId:e.ref("DBSecret"),TargetId:e.ref(c),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[c,"DBSecret"]}),n.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:e.getAtt(c,"Endpoint.Address"),Export:{Name:e.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:e.getAtt(c,"Endpoint.Port"),Export:{Name:e.sub("${AWS::StackName}-db-port")}},DBSecretArn:{Description:"ARN of the database credentials secret",Value:e.ref("DBSecret"),Export:{Name:e.sub("${AWS::StackName}-db-secret-arn")}}})}function an(n,i){let s=n.toLogicalId(`${i.name}-table`),o={TableName:e.sub(`\${AWS::StackName}-${i.name}`),BillingMode:i.billingMode||"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:i.partitionKey,AttributeType:"S"}],KeySchema:[{AttributeName:i.partitionKey,KeyType:"HASH"}],Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i.name}`)}]};if(i.sortKey)o.AttributeDefinitions.push({AttributeName:i.sortKey,AttributeType:"S"}),o.KeySchema.push({AttributeName:i.sortKey,KeyType:"RANGE"});if(i.billingMode==="PROVISIONED")o.ProvisionedThroughput={ReadCapacityUnits:i.readCapacity||5,WriteCapacityUnits:i.writeCapacity||5};if(i.streamEnabled)o.StreamSpecification={StreamViewType:"NEW_AND_OLD_IMAGES"};if(i.pointInTimeRecovery)o.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(i.ttl?.enabled)o.TimeToLiveSpecification={Enabled:!0,AttributeName:i.ttl.attributeName};if(i.globalSecondaryIndexes&&i.globalSecondaryIndexes.length>0)o.GlobalSecondaryIndexes=i.globalSecondaryIndexes.map((c)=>{let l=new Set(o.AttributeDefinitions.map((h)=>h.AttributeName));if(!l.has(c.partitionKey))o.AttributeDefinitions.push({AttributeName:c.partitionKey,AttributeType:"S"});if(c.sortKey&&!l.has(c.sortKey))o.AttributeDefinitions.push({AttributeName:c.sortKey,AttributeType:"S"});let u={IndexName:c.name,KeySchema:[{AttributeName:c.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:c.projectionType||"ALL"}};if(c.sortKey)u.KeySchema.push({AttributeName:c.sortKey,KeyType:"RANGE"});if(c.projectionType==="INCLUDE"&&c.nonKeyAttributes)u.Projection.NonKeyAttributes=c.nonKeyAttributes;if(i.billingMode==="PROVISIONED")u.ProvisionedThroughput={ReadCapacityUnits:i.readCapacity||5,WriteCapacityUnits:i.writeCapacity||5};return u});if(n.addResource(s,"AWS::DynamoDB::Table",o,{deletionPolicy:"Retain"}),n.addOutputs({[`${s}Name`]:{Description:`${i.name} table name`,Value:e.ref(s),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-table`)}},[`${s}Arn`]:{Description:`${i.name} table ARN`,Value:e.getAtt(s,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-table-arn`)}}}),i.streamEnabled)n.addOutputs({[`${s}StreamArn`]:{Description:`${i.name} stream ARN`,Value:e.getAtt(s,"StreamArn"),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-stream-arn`)}}})}function rn(n,i){for(let[s,o]of Object.entries(i))o.forEach((c)=>{nn(n,c,s)})}function nn(n,i,s){let o=n.toLogicalId(`${s}-${i.name}-function`),c=`${o}Role`;n.addResource(c,"AWS::IAM::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","arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"],Policies:[{PolicyName:"LambdaExecutionPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[...on(i.events||[])]}}],Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i.name}-role`)}]});let l={FunctionName:e.sub(`\${AWS::StackName}-${i.name}`),Runtime:i.runtime,Handler:i.handler,Role:e.getAtt(c,"Arn"),MemorySize:i.memory,Timeout:i.timeout,Code:{ZipFile:`exports.handler = async (event) => {
2483
+ `;if(n.addResource("LaunchTemplate","AWS::EC2::LaunchTemplate",{LaunchTemplateName:e.sub("${AWS::StackName}-template"),LaunchTemplateData:{ImageId:i.ami||e.findInMap("RegionMap",e.ref("AWS::Region"),"AMI"),InstanceType:i.instanceType,IamInstanceProfile:{Arn:e.getAtt("EC2InstanceProfile","Arn")},SecurityGroupIds:[e.ref("AppSecurityGroup")],UserData:e.base64(e.sub(s)),TagSpecifications:[{ResourceType:"instance",Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-instance")}]}],MetadataOptions:{HttpTokens:"required",HttpPutResponseHopLimit:1}}},{dependsOn:["AppSecurityGroup","EC2InstanceProfile"]}),i.loadBalancer){en(n,i.loadBalancer);let o={LaunchTemplate:{LaunchTemplateId:e.ref("LaunchTemplate"),Version:e.getAtt("LaunchTemplate","LatestVersionNumber")},MinSize:i.autoScaling?.min.toString()||"1",MaxSize:i.autoScaling?.max.toString()||"3",DesiredCapacity:i.autoScaling?.min.toString()||"2",VPCZoneIdentifier:[e.ref("PrivateSubnet1"),e.ref("PrivateSubnet2")],TargetGroupARNs:[e.ref("TargetGroup")],HealthCheckType:"ELB",HealthCheckGracePeriod:300,Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-asg"),PropagateAtLaunch:!0}]};if(n.addResource("AutoScalingGroup","AWS::AutoScaling::AutoScalingGroup",o,{dependsOn:["LaunchTemplate","TargetGroup"]}),i.autoScaling)n.addResource("ScaleUpPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:e.ref("AutoScalingGroup"),Cooldown:i.autoScaling.scaleUpCooldown?.toString()||"300",ScalingAdjustment:"1"},{dependsOn:"AutoScalingGroup"}),n.addResource("ScaleDownPolicy","AWS::AutoScaling::ScalingPolicy",{AdjustmentType:"ChangeInCapacity",AutoScalingGroupName:e.ref("AutoScalingGroup"),Cooldown:i.autoScaling.scaleDownCooldown?.toString()||"300",ScalingAdjustment:"-1"},{dependsOn:"AutoScalingGroup"}),n.addResource("HighCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale up when CPU exceeds target",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:(i.autoScaling.targetCPU||70).toString(),AlarmActions:[e.ref("ScaleUpPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:e.ref("AutoScalingGroup")}],ComparisonOperator:"GreaterThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleUpPolicy"]}),n.addResource("LowCPUAlarm","AWS::CloudWatch::Alarm",{AlarmDescription:"Scale down when CPU is below threshold",MetricName:"CPUUtilization",Namespace:"AWS/EC2",Statistic:"Average",Period:"300",EvaluationPeriods:"2",Threshold:((i.autoScaling.targetCPU||70)-20).toString(),AlarmActions:[e.ref("ScaleDownPolicy")],Dimensions:[{Name:"AutoScalingGroupName",Value:e.ref("AutoScalingGroup")}],ComparisonOperator:"LessThanThreshold"},{dependsOn:["AutoScalingGroup","ScaleDownPolicy"]})}}function en(n,i){if(!i)return;n.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for Application Load Balancer",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"}),n.addResource("LoadBalancer","AWS::ElasticLoadBalancingV2::LoadBalancer",{Name:e.sub("${AWS::StackName}-alb"),Type:i.type||"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[e.ref("PublicSubnet1"),e.ref("PublicSubnet2")],SecurityGroups:[e.ref("ALBSecurityGroup")],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-alb")}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]}),n.addResource("TargetGroup","AWS::ElasticLoadBalancingV2::TargetGroup",{Name:e.sub("${AWS::StackName}-tg"),Port:3000,Protocol:"HTTP",VpcId:e.ref("VPC"),HealthCheckEnabled:!0,HealthCheckPath:i.healthCheck?.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:i.healthCheck?.interval||30,HealthCheckTimeoutSeconds:i.healthCheck?.timeout||5,HealthyThresholdCount:i.healthCheck?.healthyThreshold||2,UnhealthyThresholdCount:i.healthCheck?.unhealthyThreshold||3,TargetType:"instance",Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-tg")}]},{dependsOn:"VPC"}),n.addResource("LoadBalancerListener","AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:e.ref("LoadBalancer"),Port:80,Protocol:"HTTP",DefaultActions:[{Type:"forward",TargetGroupArn:e.ref("TargetGroup")}]},{dependsOn:["LoadBalancer","TargetGroup"]}),n.addOutputs({LoadBalancerDNS:{Description:"Load Balancer DNS Name",Value:e.getAtt("LoadBalancer","DNSName"),Export:{Name:e.sub("${AWS::StackName}-alb-dns")}}})}function pa(n,i,s){let o=n.toLogicalId(i),c=s.taskDefinition.containerDefinitions?.[0],l=c?.name||c?.Name||i,u=c?.portMappings?.[0]?.containerPort||c?.PortMappings?.[0]?.ContainerPort||3000,h=(s.taskDefinition.containerDefinitions||[]).flatMap((v)=>(v.secrets||v.Secrets||[]).map((w)=>w.valueFrom||w.ValueFrom)).filter(Boolean);if(!n.hasResource("ECSCluster"))n.addResource("ECSCluster","AWS::ECS::Cluster",{ClusterName:e.sub("${AWS::StackName}-cluster"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-cluster")}]});if(n.addResource(`${o}TaskExecutionRole`,"AWS::IAM::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"],...h.length?{Policies:[{PolicyName:"read-task-secrets",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameters"],Resource:h},{Effect:"Allow",Action:"kms:Decrypt",Resource:"*"}]}}]}:{}}),n.addResource(`${o}TaskRole`,"AWS::IAM::Role",{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"ecs-tasks.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"application-services",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:SendMessage"],Resource:e.sub("arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${AWS::StackName}-*")},{Effect:"Allow",Action:["ses:SendEmail","ses:SendRawEmail"],Resource:"*"}]}}]}),!n.hasResource("ALBSecurityGroup"))n.addResource("ALBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Public ingress for the application load balancer",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:80,ToPort:80,CidrIp:"0.0.0.0/0"},...s.loadBalancer?.customDomain?.certificateArn?[{IpProtocol:"tcp",FromPort:443,ToPort:443,CidrIp:"0.0.0.0/0"}]:[]],SecurityGroupEgress:[{IpProtocol:"tcp",FromPort:u,ToPort:u,CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-alb-sg")}]},{dependsOn:"VPC"});if(!n.hasResource("AppSecurityGroup"))n.addResource("AppSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Only the application load balancer may reach Fargate tasks",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:u,ToPort:u,SourceSecurityGroupId:e.ref("ALBSecurityGroup")}],SecurityGroupEgress:[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-app-sg")}]},{dependsOn:["VPC","ALBSecurityGroup"]});let y=(s.taskDefinition.containerDefinitions||[{name:i,image:e.sub(`\${AWS::AccountId}.dkr.ecr.\${AWS::Region}.amazonaws.com/${i}:latest`),portMappings:[{containerPort:3000}]}]).map((v)=>({Name:v.Name||v.name,Image:v.Image||v.image,Essential:v.Essential??v.essential??!0,PortMappings:(v.PortMappings||v.portMappings||[]).map((w)=>({ContainerPort:w.ContainerPort??w.containerPort,Protocol:w.Protocol||w.protocol||"tcp"})),Environment:Array.isArray(v.Environment||v.environment)?(v.Environment||v.environment).map((w)=>({Name:w.Name||w.name,Value:w.Value??w.value})):Object.entries(v.Environment||v.environment||{}).map(([w,E])=>({Name:w,Value:E})),Secrets:(v.Secrets||v.secrets||[]).map((w)=>({Name:w.Name||w.name,ValueFrom:w.ValueFrom||w.valueFrom})),HealthCheck:v.HealthCheck||v.healthCheck,Command:v.Command||v.command,EntryPoint:v.EntryPoint||v.entryPoint,LogConfiguration:v.LogConfiguration||v.logConfiguration||{LogDriver:"awslogs",Options:{"awslogs-group":e.ref(`${o}LogGroup`),"awslogs-region":e.ref("AWS::Region"),"awslogs-stream-prefix":i}}}));n.addResource(`${o}TaskDefinition`,"AWS::ECS::TaskDefinition",{Family:e.sub(`\${AWS::StackName}-${i}`),NetworkMode:"awsvpc",RequiresCompatibilities:["FARGATE"],Cpu:s.taskDefinition.cpu,Memory:s.taskDefinition.memory,ExecutionRoleArn:e.getAtt(`${o}TaskExecutionRole`,"Arn"),TaskRoleArn:e.getAtt(`${o}TaskRole`,"Arn"),ContainerDefinitions:y},{dependsOn:[`${o}TaskExecutionRole`,`${o}TaskRole`,`${o}LogGroup`]}),n.addResource(`${o}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:e.sub(`/ecs/\${AWS::StackName}/${i}`),RetentionInDays:14});let f=s.service.healthCheck||{};n.addResource(`${o}TargetGroup`,"AWS::ElasticLoadBalancingV2::TargetGroup",{VpcId:e.ref("VPC"),Port:u,Protocol:"HTTP",TargetType:"ip",HealthCheckEnabled:!0,HealthCheckPath:f.path||"/health",HealthCheckProtocol:"HTTP",HealthCheckIntervalSeconds:f.interval||30,HealthCheckTimeoutSeconds:f.timeout||5,HealthyThresholdCount:f.healthyThreshold||2,UnhealthyThresholdCount:f.unhealthyThreshold||3,Matcher:{HttpCode:"200-399"},TargetGroupAttributes:[{Key:"deregistration_delay.timeout_seconds",Value:"30"}]},{dependsOn:"VPC"}),n.addResource(`${o}LoadBalancer`,"AWS::ElasticLoadBalancingV2::LoadBalancer",{Type:"application",Scheme:"internet-facing",IpAddressType:"ipv4",Subnets:[e.ref("PublicSubnet1"),e.ref("PublicSubnet2")],SecurityGroups:[e.ref("ALBSecurityGroup")],LoadBalancerAttributes:[{Key:"routing.http.drop_invalid_header_fields.enabled",Value:"true"},{Key:"deletion_protection.enabled",Value:String(s.loadBalancer?.deletionProtection===!0)}],Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-alb`)}]},{dependsOn:["PublicSubnet1","PublicSubnet2","ALBSecurityGroup"]});let S=s.loadBalancer?.customDomain?.certificateArn,b=s.loadBalancer?.originVerifyHeader;if(n.addResource(`${o}HttpListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:e.ref(`${o}LoadBalancer`),Port:80,Protocol:"HTTP",DefaultActions:S?[{Type:"redirect",RedirectConfig:{Protocol:"HTTPS",Port:"443",StatusCode:"HTTP_301"}}]:b?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:e.ref(`${o}TargetGroup`)}]},{dependsOn:[`${o}LoadBalancer`,`${o}TargetGroup`]}),S)n.addResource(`${o}HttpsListener`,"AWS::ElasticLoadBalancingV2::Listener",{LoadBalancerArn:e.ref(`${o}LoadBalancer`),Port:443,Protocol:"HTTPS",Certificates:[{CertificateArn:S}],SslPolicy:"ELBSecurityPolicy-TLS13-1-2-2021-06",DefaultActions:b?[{Type:"fixed-response",FixedResponseConfig:{StatusCode:"403",ContentType:"text/plain",MessageBody:"Forbidden"}}]:[{Type:"forward",TargetGroupArn:e.ref(`${o}TargetGroup`)}]},{dependsOn:[`${o}LoadBalancer`,`${o}TargetGroup`]});if(b){let v=S?`${o}HttpsListener`:`${o}HttpListener`;n.addResource(`${o}OriginVerifyRule`,"AWS::ElasticLoadBalancingV2::ListenerRule",{ListenerArn:e.ref(v),Priority:1,Conditions:[{Field:"http-header",HttpHeaderConfig:{HttpHeaderName:b.name,Values:[b.value]}}],Actions:[{Type:"forward",TargetGroupArn:e.ref(`${o}TargetGroup`)}]},{dependsOn:[v,`${o}TargetGroup`]})}if(n.addResource(`${o}Service`,"AWS::ECS::Service",{ServiceName:e.sub(`\${AWS::StackName}-${i}`),Cluster:e.ref("ECSCluster"),TaskDefinition:e.ref(`${o}TaskDefinition`),DesiredCount:s.service.desiredCount,LaunchType:"FARGATE",PlatformVersion:"LATEST",HealthCheckGracePeriodSeconds:60,DeploymentConfiguration:{MinimumHealthyPercent:100,MaximumPercent:200,DeploymentCircuitBreaker:{Enable:!0,Rollback:!0}},LoadBalancers:[{ContainerName:l,ContainerPort:u,TargetGroupArn:e.ref(`${o}TargetGroup`)}],NetworkConfiguration:{AwsvpcConfiguration:{AssignPublicIp:"DISABLED",Subnets:[e.ref("PrivateSubnet1"),e.ref("PrivateSubnet2")],SecurityGroups:[e.ref("AppSecurityGroup")]}}},{dependsOn:["ECSCluster",`${o}TaskDefinition`,b?`${o}OriginVerifyRule`:S?`${o}HttpsListener`:`${o}HttpListener`]}),s.service.autoScaling){let v=s.service.autoScaling;n.addResource(`${o}ScalableTarget`,"AWS::ApplicationAutoScaling::ScalableTarget",{MinCapacity:v.min,MaxCapacity:v.max,ResourceId:e.join("/",["service",e.ref("ECSCluster"),e.getAtt(`${o}Service`,"Name")]),RoleARN:e.sub("arn:aws:iam::${AWS::AccountId}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"),ScalableDimension:"ecs:service:DesiredCount",ServiceNamespace:"ecs"},{dependsOn:`${o}Service`}),n.addResource(`${o}ScalingPolicy`,"AWS::ApplicationAutoScaling::ScalingPolicy",{PolicyType:"TargetTrackingScaling",ScalingTargetId:e.ref(`${o}ScalableTarget`),TargetTrackingScalingPolicyConfiguration:{TargetValue:v.targetCPU||70,PredefinedMetricSpecification:{PredefinedMetricType:"ECSServiceAverageCPUUtilization"},ScaleInCooldown:60,ScaleOutCooldown:30}},{dependsOn:`${o}ScalableTarget`})}n.addOutputs({[`${o}ClusterName`]:{Description:"ECS cluster name",Value:e.ref("ECSCluster")},[`${o}ServiceName`]:{Description:"ECS service name",Value:e.getAtt(`${o}Service`,"Name")},[`${o}LoadBalancerDnsName`]:{Description:"ALB origin hostname",Value:e.getAtt(`${o}LoadBalancer`,"DNSName")},[`${o}LoadBalancerHostedZoneId`]:{Description:"ALB canonical hosted zone ID",Value:e.getAtt(`${o}LoadBalancer`,"CanonicalHostedZoneID")},[`${o}TargetGroupArn`]:{Description:"ECS target group ARN",Value:e.ref(`${o}TargetGroup`)}})}function tn(n,i){if(i.postgres)ga(n,"postgres",i.postgres);if(i.mysql)ga(n,"mysql",i.mysql);if(i.dynamodb?.tables)i.dynamodb.tables.forEach((s)=>{an(n,s)})}function ga(n,i,s){if(!s)return;let o=i==="postgres"?"postgres":"mysql",c=n.toLogicalId(`${o}-db`);n.addResource("DBSubnetGroup","AWS::RDS::DBSubnetGroup",{DBSubnetGroupDescription:"Subnet group for RDS instance",SubnetIds:[e.ref("PrivateSubnet1"),e.ref("PrivateSubnet2")],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-db-subnet-group")}]},{dependsOn:["PrivateSubnet1","PrivateSubnet2"]}),n.addResource("DBSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for RDS instance",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:i==="postgres"?5432:3306,ToPort:i==="postgres"?5432:3306,SourceSecurityGroupId:e.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-db-sg")}]},{dependsOn:["VPC","AppSecurityGroup"]});let l=i==="postgres"?`postgres${s.version.split(".")[0]}`:`mysql${s.version.split(".")[0]}.${s.version.split(".")[1]||"0"}`;if(s.parameters&&Object.keys(s.parameters).length>0)n.addResource("DBParameterGroup","AWS::RDS::DBParameterGroup",{Description:`Parameter group for ${o}`,Family:l,Parameters:s.parameters,Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-db-params")}]});n.addResource("DBSecret","AWS::SecretsManager::Secret",{Description:"Database credentials",GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"admin"}),GenerateStringKey:"password",PasswordLength:32,ExcludeCharacters:'"@/\\'},Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-db-secret")}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"});let u={Engine:o,EngineVersion:s.version,DBInstanceClass:s.instanceClass,AllocatedStorage:s.allocatedStorage.toString(),MaxAllocatedStorage:s.maxAllocatedStorage?.toString(),StorageType:"gp3",StorageEncrypted:!0,MultiAZ:s.multiAZ!==!1,DBSubnetGroupName:e.ref("DBSubnetGroup"),VPCSecurityGroups:[e.ref("DBSecurityGroup")],MasterUsername:e.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:username}}"),MasterUserPassword:e.sub("{{resolve:secretsmanager:${DBSecret}:SecretString:password}}"),BackupRetentionPeriod:s.backupRetentionDays||7,PreferredBackupWindow:s.preferredBackupWindow||"03:00-04:00",PreferredMaintenanceWindow:s.preferredMaintenanceWindow||"sun:04:00-sun:05:00",EnablePerformanceInsights:s.enablePerformanceInsights!==!1,PerformanceInsightsRetentionPeriod:s.performanceInsightsRetention||7,DeletionProtection:s.deletionProtection!==!1,CopyTagsToSnapshot:!0,EnableCloudwatchLogsExports:i==="postgres"?["postgresql"]:["error","general","slowquery"],Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${o}-db`)}]};if(s.parameters&&Object.keys(s.parameters).length>0)u.DBParameterGroupName=e.ref("DBParameterGroup");n.addResource(c,"AWS::RDS::DBInstance",u,{dependsOn:["DBSubnetGroup","DBSecurityGroup","DBSecret"],deletionPolicy:"Snapshot",updateReplacePolicy:"Snapshot"}),n.addResource("DBSecretAttachment","AWS::SecretsManager::SecretTargetAttachment",{SecretId:e.ref("DBSecret"),TargetId:e.ref(c),TargetType:"AWS::RDS::DBInstance"},{dependsOn:[c,"DBSecret"]}),n.addOutputs({DBEndpoint:{Description:"Database endpoint",Value:e.getAtt(c,"Endpoint.Address"),Export:{Name:e.sub("${AWS::StackName}-db-endpoint")}},DBPort:{Description:"Database port",Value:e.getAtt(c,"Endpoint.Port"),Export:{Name:e.sub("${AWS::StackName}-db-port")}},DBSecretArn:{Description:"ARN of the database credentials secret",Value:e.ref("DBSecret"),Export:{Name:e.sub("${AWS::StackName}-db-secret-arn")}}})}function an(n,i){let s=n.toLogicalId(`${i.name}-table`),o={TableName:e.sub(`\${AWS::StackName}-${i.name}`),BillingMode:i.billingMode||"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:i.partitionKey,AttributeType:"S"}],KeySchema:[{AttributeName:i.partitionKey,KeyType:"HASH"}],Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i.name}`)}]};if(i.sortKey)o.AttributeDefinitions.push({AttributeName:i.sortKey,AttributeType:"S"}),o.KeySchema.push({AttributeName:i.sortKey,KeyType:"RANGE"});if(i.billingMode==="PROVISIONED")o.ProvisionedThroughput={ReadCapacityUnits:i.readCapacity||5,WriteCapacityUnits:i.writeCapacity||5};if(i.streamEnabled)o.StreamSpecification={StreamViewType:"NEW_AND_OLD_IMAGES"};if(i.pointInTimeRecovery)o.PointInTimeRecoverySpecification={PointInTimeRecoveryEnabled:!0};if(i.ttl?.enabled)o.TimeToLiveSpecification={Enabled:!0,AttributeName:i.ttl.attributeName};if(i.globalSecondaryIndexes&&i.globalSecondaryIndexes.length>0)o.GlobalSecondaryIndexes=i.globalSecondaryIndexes.map((c)=>{let l=new Set(o.AttributeDefinitions.map((h)=>h.AttributeName));if(!l.has(c.partitionKey))o.AttributeDefinitions.push({AttributeName:c.partitionKey,AttributeType:"S"});if(c.sortKey&&!l.has(c.sortKey))o.AttributeDefinitions.push({AttributeName:c.sortKey,AttributeType:"S"});let u={IndexName:c.name,KeySchema:[{AttributeName:c.partitionKey,KeyType:"HASH"}],Projection:{ProjectionType:c.projectionType||"ALL"}};if(c.sortKey)u.KeySchema.push({AttributeName:c.sortKey,KeyType:"RANGE"});if(c.projectionType==="INCLUDE"&&c.nonKeyAttributes)u.Projection.NonKeyAttributes=c.nonKeyAttributes;if(i.billingMode==="PROVISIONED")u.ProvisionedThroughput={ReadCapacityUnits:i.readCapacity||5,WriteCapacityUnits:i.writeCapacity||5};return u});if(n.addResource(s,"AWS::DynamoDB::Table",o,{deletionPolicy:"Retain"}),n.addOutputs({[`${s}Name`]:{Description:`${i.name} table name`,Value:e.ref(s),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-table`)}},[`${s}Arn`]:{Description:`${i.name} table ARN`,Value:e.getAtt(s,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-table-arn`)}}}),i.streamEnabled)n.addOutputs({[`${s}StreamArn`]:{Description:`${i.name} stream ARN`,Value:e.getAtt(s,"StreamArn"),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-stream-arn`)}}})}function rn(n,i){for(let[s,o]of Object.entries(i))o.forEach((c)=>{nn(n,c,s)})}function nn(n,i,s){let o=n.toLogicalId(`${s}-${i.name}-function`),c=`${o}Role`;n.addResource(c,"AWS::IAM::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","arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"],Policies:[{PolicyName:"LambdaExecutionPolicy",PolicyDocument:{Version:"2012-10-17",Statement:[...on(i.events||[])]}}],Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i.name}-role`)}]});let l={FunctionName:e.sub(`\${AWS::StackName}-${i.name}`),Runtime:i.runtime,Handler:i.handler,Role:e.getAtt(c,"Arn"),MemorySize:i.memory,Timeout:i.timeout,Code:{ZipFile:`exports.handler = async (event) => {
2484
2484
  console.log('Event:', JSON.stringify(event, null, 2));
2485
2485
  return { statusCode: 200, body: 'Function not yet implemented' };
2486
2486
  };`},Environment:i.environment?{Variables:i.environment}:void 0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i.name}`)}]};if(s!=="edge")l.VpcConfig={SubnetIds:[e.ref("PrivateSubnet1"),e.ref("PrivateSubnet2")],SecurityGroupIds:[e.ref("AppSecurityGroup")]};if(n.addResource(o,"AWS::Lambda::Function",l,{dependsOn:c}),n.addResource(`${o}LogGroup`,"AWS::Logs::LogGroup",{LogGroupName:e.sub(`/aws/lambda/\${AWS::StackName}-${i.name}`),RetentionInDays:14}),i.events)i.events.forEach((u,h)=>{sn(n,o,u,h)});n.addOutputs({[`${o}Arn`]:{Description:`${i.name} function ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-function-arn`)}}})}function sn(n,i,s,o){let c=`${i}EventSource${o}`;switch(s.type){case"http":break;case"s3":if(s.bucket){let l=n.toLogicalId(`${s.bucket}-bucket`);n.addResource(`${c}Permission`,"AWS::Lambda::Permission",{FunctionName:e.ref(i),Action:"lambda:InvokeFunction",Principal:"s3.amazonaws.com",SourceArn:ho.s3Bucket(e.ref(l))},{dependsOn:[i,l]})}break;case"sqs":if(s.queueName){let l=n.toLogicalId(`${s.queueName}-queue`);n.addResource(c,"AWS::Lambda::EventSourceMapping",{EventSourceArn:e.getAtt(l,"Arn"),FunctionName:e.ref(i),BatchSize:s.batchSize||10},{dependsOn:[i,l]})}break;case"kinesis":if(s.streamName){let l=n.toLogicalId(`${s.streamName}-stream`);n.addResource(c,"AWS::Lambda::EventSourceMapping",{EventSourceArn:e.getAtt(l,"Arn"),FunctionName:e.ref(i),BatchSize:s.batchSize||100,StartingPosition:s.startingPosition||"LATEST",ParallelizationFactor:s.parallelizationFactor||1},{dependsOn:[i,l]})}break;case"dynamodb-stream":if(s.tableName){let l=n.toLogicalId(`${s.tableName}-table`);n.addResource(c,"AWS::Lambda::EventSourceMapping",{EventSourceArn:e.getAtt(l,"StreamArn"),FunctionName:e.ref(i),BatchSize:s.batchSize||100,StartingPosition:s.startingPosition||"LATEST"},{dependsOn:[i,l]})}break;case"schedule":if(s.expression)n.addResource(`${c}Rule`,"AWS::Events::Rule",{ScheduleExpression:s.expression,State:"ENABLED",Targets:[{Arn:e.getAtt(i,"Arn"),Id:`${i}Target`}]},{dependsOn:i}),n.addResource(`${c}Permission`,"AWS::Lambda::Permission",{FunctionName:e.ref(i),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.getAtt(`${c}Rule`,"Arn")},{dependsOn:[i,`${c}Rule`]});break}}function on(n){let i=[];if(!n)return i;if(n.forEach((s)=>{switch(s.type){case"s3":i.push({Effect:"Allow",Action:["s3:GetObject","s3:GetObjectVersion"],Resource:s.bucket?`arn:aws:s3:::${s.bucket}/*`:"arn:aws:s3:::*/*"});break;case"sqs":i.push({Effect:"Allow",Action:["sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes"],Resource:s.queueName?ho.sqs(s.queueName):"arn:aws:sqs:*:*:*"});break;case"kinesis":i.push({Effect:"Allow",Action:["kinesis:GetRecords","kinesis:GetShardIterator","kinesis:DescribeStream","kinesis:ListStreams"],Resource:s.streamName?ho.kinesis(s.streamName):"arn:aws:kinesis:*:*:stream/*"});break;case"dynamodb-stream":i.push({Effect:"Allow",Action:["dynamodb:GetRecords","dynamodb:GetShardIterator","dynamodb:DescribeStream","dynamodb:ListStreams"],Resource:s.tableName?e.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${s.tableName}/stream/*`):"arn:aws:dynamodb:*:*:table/*/stream/*"});break}}),i.length===0)i.push({Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:"arn:aws:logs:*:*:*"});return i}function cn(n,i){if(i.topics)i.topics.forEach((s)=>{ln(n,s)})}function ln(n,i){let s=n.toLogicalId(`${i.name}-topic`);if(n.addResource(s,"AWS::SNS::Topic",{TopicName:e.sub(`\${AWS::StackName}-${i.name}`),DisplayName:i.displayName||i.name,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i.name}`)}]}),n.addResource(`${s}Policy`,"AWS::SNS::TopicPolicy",{Topics:[e.ref(s)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["events.amazonaws.com","cloudwatch.amazonaws.com","s3.amazonaws.com"]},Action:"sns:Publish",Resource:e.ref(s)},{Effect:"Allow",Principal:{AWS:e.sub("arn:aws:iam::${AWS::AccountId}:root")},Action:["sns:Subscribe","sns:Publish","sns:Receive"],Resource:e.ref(s)}]}},{dependsOn:s}),i.subscriptions)i.subscriptions.forEach((o,c)=>{let l=`${s}Subscription${c+1}`,u={Protocol:o.protocol,TopicArn:e.ref(s),Endpoint:o.endpoint};if(o.filterPolicy)u.FilterPolicy=o.filterPolicy;if(o.protocol==="sqs"){let h=n.toLogicalId(`${o.endpoint}-queue`);u.Endpoint=e.getAtt(h,"Arn")}if(o.protocol==="lambda"){let h=n.toLogicalId(o.endpoint);u.Endpoint=e.getAtt(h,"Arn"),n.addResource(`${l}Permission`,"AWS::Lambda::Permission",{FunctionName:e.ref(h),Action:"lambda:InvokeFunction",Principal:"sns.amazonaws.com",SourceArn:e.ref(s)},{dependsOn:[h,s]})}n.addResource(l,"AWS::SNS::Subscription",u,{dependsOn:s})});n.addOutputs({[`${s}Arn`]:{Description:`${i.name} topic ARN`,Value:e.ref(s),Export:{Name:e.sub(`\${AWS::StackName}-${i.name}-topic-arn`)}}})}function un(n,i){if(i.alarms&&i.alarms.length>0)n.addResource("AlarmTopic","AWS::SNS::Topic",{TopicName:e.sub("${AWS::StackName}-alarms"),DisplayName:"CloudWatch Alarms",Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-alarms")}]}),i.alarms.forEach((s,o)=>{dn(n,s,o)});if(i.dashboard)mn(n,i.dashboard);if(i.logs?.groups)i.logs.groups.forEach((s)=>{pn(n,s,i.logs?.retention)})}function dn(n,i,s){let o=n.toLogicalId(`alarm-${i.name||i.metric}-${s}`),c={AlarmName:i.name||e.sub(`\${AWS::StackName}-${i.metric}`),AlarmDescription:`Alarm for ${i.metric}`,MetricName:i.metric,Namespace:i.namespace||Bt(i.metric,i.service),Statistic:i.statistic||"Average",Period:i.period||300,EvaluationPeriods:i.evaluationPeriods||1,Threshold:i.threshold,ComparisonOperator:i.comparisonOperator||"GreaterThanThreshold",TreatMissingData:i.treatMissingData||"notBreaching",AlarmActions:[e.ref("AlarmTopic")],OKActions:[e.ref("AlarmTopic")]};if(i.dimensions)c.Dimensions=Object.entries(i.dimensions).map(([l,u])=>({Name:l,Value:u}));else if(i.service)c.Dimensions=gn(i.service);n.addResource(o,"AWS::CloudWatch::Alarm",c,{dependsOn:"AlarmTopic"})}function mn(n,i){if(!i)return;let s=[],o=0,c=0;i.widgets?.forEach((l)=>{let u=l.width||12,h=l.height||6;if(l.type==="metric"&&l.metrics){let y=l.metrics.map((f)=>{if(typeof f==="string")return[Bt(f),f];else return[Bt(f.metric,f.service),f.metric]});s.push({type:"metric",x:o,y:c,width:u,height:h,properties:{metrics:y,period:300,stat:"Average",region:e.ref("AWS::Region"),title:l.metrics.length>1?"Multiple Metrics":typeof l.metrics[0]==="string"?l.metrics[0]:l.metrics[0].metric}})}else if(l.type==="log"&&l.logGroup)s.push({type:"log",x:o,y:c,width:u,height:h,properties:{query:`SOURCE '${l.logGroup}'
2487
2487
  | fields @timestamp, @message
2488
2488
  | sort @timestamp desc
2489
- | limit 20`,region:e.ref("AWS::Region"),title:`Logs: ${l.logGroup}`}});else if(l.type==="text"&&l.text)s.push({type:"text",x:o,y:c,width:u,height:h,properties:{markdown:l.text}});if(o+=u,o>=24)o=0,c+=h}),n.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:e.sub(`\${AWS::StackName}-${i.name}`),DashboardBody:JSON.stringify({widgets:s})}),n.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:e.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function pn(n,i,s){let o=n.toLogicalId(`${i}-log-group`);n.addResource(o,"AWS::Logs::LogGroup",{LogGroupName:e.sub(`/aws/\${AWS::StackName}/${i}`),RetentionInDays:s||14,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]})}function Bt(n,i){if(i)return{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",dynamodb:"AWS/DynamoDB",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apigateway:"AWS/ApiGateway",sqs:"AWS/SQS",sns:"AWS/SNS",kinesis:"AWS/Kinesis",elasticache:"AWS/ElastiCache"}[i.toLowerCase()]||"AWS/CloudWatch";let s=n.toLowerCase();if(s.includes("cpu")||s.includes("memory")||s.includes("network"))return"AWS/EC2";if(s.includes("lambda")||s.includes("invocation")||s.includes("duration"))return"AWS/Lambda";if(s.includes("request")||s.includes("latency")||s.includes("target"))return"AWS/ApplicationELB";if(s.includes("database")||s.includes("connection"))return"AWS/RDS";if(s.includes("read")||s.includes("write")||s.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function gn(n){return{ec2:[{Name:"InstanceId",Value:e.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:e.ref("ECSCluster")},{Name:"ServiceName",Value:e.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:e.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:e.ref("Database")}],dynamodb:[{Name:"TableName",Value:e.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:e.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:e.ref("HttpApi")}]}[n.toLowerCase()]||[]}function hn(n,i){if(!i.vpc)return;let{cidr:s="10.0.0.0/16",availabilityZones:o=2,natGateways:c=1,enableDnsHostnames:l=!0,enableDnsSupport:u=!0}=i.vpc;n.addResource("VPC","AWS::EC2::VPC",{CidrBlock:s,EnableDnsHostnames:l,EnableDnsSupport:u,Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-vpc")}]}),n.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-igw")}]}),n.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:e.ref("VPC"),InternetGatewayId:e.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let h=[];for(let C=0;C<o;C++){let T=`PublicSubnet${C+1}`;h.push(T),n.addResource(T,"AWS::EC2::Subnet",{VpcId:e.ref("VPC"),CidrBlock:e.select(C,e.cidr(e.getAtt("VPC","CidrBlock"),o*2,8)),AvailabilityZone:e.select(C,e.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-public-${C+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let y=[];for(let C=0;C<o;C++){let T=`PrivateSubnet${C+1}`;y.push(T),n.addResource(T,"AWS::EC2::Subnet",{VpcId:e.ref("VPC"),CidrBlock:e.select(C+o,e.cidr(e.getAtt("VPC","CidrBlock"),o*2,8)),AvailabilityZone:e.select(C,e.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-private-${C+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let f=[];for(let C=0;C<c;C++){let T=`NatEIP${C+1}`;f.push(T),n.addResource(T,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-nat-eip-${C+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let b=[];for(let C=0;C<c;C++){let T=`NatGateway${C+1}`;b.push(T);let w=C%o;n.addResource(T,"AWS::EC2::NatGateway",{AllocationId:e.getAtt(f[C],"AllocationId"),SubnetId:e.ref(h[w]),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-nat-${C+1}`)}]},{dependsOn:[f[C],h[w]]})}n.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),n.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:e.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:e.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),h.forEach((C,T)=>{n.addResource(`PublicSubnetRouteTableAssociation${T+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:e.ref(C),RouteTableId:e.ref("PublicRouteTable")},{dependsOn:[C,"PublicRouteTable"]})}),y.forEach((C,T)=>{let w=`PrivateRouteTable${T+1}`,E=T%c;n.addResource(w,"AWS::EC2::RouteTable",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-private-rt-${T+1}`)}]},{dependsOn:"VPC"}),n.addResource(`PrivateRoute${T+1}`,"AWS::EC2::Route",{RouteTableId:e.ref(w),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:e.ref(b[E])},{dependsOn:[w,b[E]]}),n.addResource(`PrivateSubnetRouteTableAssociation${T+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:e.ref(C),RouteTableId:e.ref(w)},{dependsOn:[C,w]})}),n.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:e.ref("VPC"),ServiceName:e.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[e.ref("PublicRouteTable"),...Array.from({length:o},(C,T)=>e.ref(`PrivateRouteTable${T+1}`))]},{dependsOn:"VPC"}),n.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),n.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:e.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),n.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:e.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,Egress:!0,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),n.addOutputs({VPCId:{Description:"VPC ID",Value:e.ref("VPC"),Export:{Name:e.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:e.join(",",h.map((C)=>e.ref(C))),Export:{Name:e.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:e.join(",",y.map((C)=>e.ref(C))),Export:{Name:e.sub("${AWS::StackName}-PrivateSubnets")}}})}function yn(n,i){for(let[s,o]of Object.entries(i))fn(n,s,o)}function fn(n,i,s){let o=n.toLogicalId(`${i}-queue`),c=s.fifo||!1,l;if(s.deadLetterQueue){let h=`${o}DLQ`;n.addResource(h,"AWS::SQS::Queue",{QueueName:c?e.sub(`\${AWS::StackName}-${i}-dlq.fifo`):e.sub(`\${AWS::StackName}-${i}-dlq`),FifoQueue:c,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),l=e.getAtt(h,"Arn")}let u={QueueName:c?e.sub(`\${AWS::StackName}-${i}.fifo`):e.sub(`\${AWS::StackName}-${i}`),FifoQueue:c,VisibilityTimeout:s.visibilityTimeout||30,MessageRetentionPeriod:s.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:s.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(c&&s.contentBasedDeduplication)u.ContentBasedDeduplication=!0;if(s.deadLetterQueue&&l)u.RedrivePolicy={deadLetterTargetArn:l,maxReceiveCount:s.maxReceiveCount||3};if(n.addResource(o,"AWS::SQS::Queue",u,{dependsOn:s.deadLetterQueue?`${o}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),n.addResource(`${o}Policy`,"AWS::SQS::QueuePolicy",{Queues:[e.ref(o)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:e.getAtt(o,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":e.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:o}),n.addOutputs({[`${o}Url`]:{Description:`${i} queue URL`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-queue-url`)}},[`${o}Arn`]:{Description:`${i} queue ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i}-queue-arn`)}}}),s.deadLetterQueue)n.addOutputs({[`${o}DLQUrl`]:{Description:`${i} dead letter queue URL`,Value:e.ref(`${o}DLQ`),Export:{Name:e.sub(`\${AWS::StackName}-${i}-dlq-url`)}}})}function Sn(n,i){if(i.certificate)bn(n,i.certificate);if(i.waf?.enabled)An(n,i.waf);if(i.securityGroups)for(let[s,o]of Object.entries(i.securityGroups))Cn(n,s,o)}function bn(n,i){if(!i)return;let s=[i.domain];if(i.subdomains)s.push(...i.subdomains);n.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:i.domain,SubjectAlternativeNames:i.subdomains,ValidationMethod:i.validationMethod||"DNS",DomainValidationOptions:s.map((o)=>({DomainName:o,HostedZoneId:e.ref("HostedZone")})),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-certificate")}]}),n.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:e.ref("Certificate"),Export:{Name:e.sub("${AWS::StackName}-certificate-arn")}}})}function An(n,i){if(!i)return;let s=[],o=i.rules||["rateLimit","sqlInjection","xss"];if(o.includes("rateLimit"))s.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:i.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let c=s.length+1;if(o.includes("sqlInjection"))s.push({Name:"AWSManagedRulesSQLi",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(o.includes("xss"))s.push({Name:"AWSManagedRulesXSS",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(o.includes("knownBadInputs"))s.push({Name:"AWSManagedRulesKnownBadInputs",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(o.includes("coreRuleSet"))s.push({Name:"AWSManagedRulesCoreRuleSet",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(o.includes("linuxRuleSet"))s.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(o.includes("apiProtection"))s.push({Name:"AWSManagedRulesAPIProtection",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(o.includes("geoBlock"))s.push({Name:"GeoBlockRule",Priority:c++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(o.includes("connectionLimit"))s.push({Name:"ConnectionLimitRule",Priority:c++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(n.addResource("WebACL","AWS::WAFv2::WebACL",{Name:e.sub("${AWS::StackName}-waf"),Scope:i.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:s,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:e.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-waf")}]}),n.hasResource("LoadBalancer"))n.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:e.ref("LoadBalancer"),WebACLArn:e.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});n.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:e.ref("WebACL"),Export:{Name:e.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:e.getAtt("WebACL","Arn"),Export:{Name:e.sub("${AWS::StackName}-waf-arn")}}})}function Cn(n,i,s){if(!s)return;let o=n.toLogicalId(`${i}-security-group`),c=s.ingress?.map((u)=>({IpProtocol:u.protocol,FromPort:u.port,ToPort:u.port,CidrIp:u.cidr,SourceSecurityGroupId:u.source?e.ref(u.source):void 0}))||[],l=s.egress?.map((u)=>({IpProtocol:u.protocol,FromPort:u.port,ToPort:u.port,CidrIp:u.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];n.addResource(o,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${i}`,VpcId:e.ref("VPC"),SecurityGroupIngress:c,SecurityGroupEgress:l,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-sg`)}]},{dependsOn:"VPC"}),n.addOutputs({[`${o}Id`]:{Description:`${i} security group ID`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-sg-id`)}}})}function vn(n,i){for(let[s,o]of Object.entries(i)){if(o.type==="efs"){wn(n,s,o);continue}Tn(n,s,o)}}function Tn(n,i,s){let o=n.toLogicalId(`${i}-bucket`),c={BucketName:e.sub(`\${AWS::StackName}-${i}`),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(s.versioning)c.VersioningConfiguration={Status:"Enabled"};if(s.encryption)c.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!s.public)c.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(s.website)c.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(s.cors&&s.cors.length>0)c.CorsConfiguration={CorsRules:s.cors.map((l)=>({AllowedOrigins:l.allowedOrigins,AllowedMethods:l.allowedMethods,AllowedHeaders:l.allowedHeaders||["*"],MaxAge:l.maxAge||3600}))};if(s.lifecycleRules&&s.lifecycleRules.length>0)c.LifecycleConfiguration={Rules:s.lifecycleRules.map((l)=>({Id:l.id,Status:l.enabled?"Enabled":"Disabled",ExpirationInDays:l.expirationDays,Transitions:l.transitions?.map((u)=>({TransitionInDays:u.days,StorageClass:u.storageClass}))}))};if(s.intelligentTiering)c.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(n.addResource(o,"AWS::S3::Bucket",c,{deletionPolicy:s.versioning?"Retain":"Delete"}),s.public)n.addResource(`${o}Policy`,"AWS::S3::BucketPolicy",{Bucket:e.ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:e.join("",[ho.s3Bucket(e.ref(o)),"/*"])}]}},{dependsOn:o});if(n.addOutputs({[`${o}Name`]:{Description:`${i} bucket name`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-bucket`)}},[`${o}Arn`]:{Description:`${i} bucket ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i}-bucket-arn`)}}}),s.website)n.addOutputs({[`${o}WebsiteURL`]:{Description:`${i} website URL`,Value:e.getAtt(o,"WebsiteURL")}})}function wn(n,i,s){let o=n.toLogicalId(`${i}-efs`),c={Encrypted:s.encryption!==!1,PerformanceMode:s.performanceMode||"generalPurpose",ThroughputMode:s.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(s.lifecyclePolicy){if(c.LifecyclePolicies=[],s.lifecyclePolicy.transitionToIA)c.LifecyclePolicies.push({TransitionToIA:`AFTER_${s.lifecyclePolicy.transitionToIA}_DAYS`});if(s.lifecyclePolicy.transitionToPrimaryStorageClass)c.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}n.addResource(o,"AWS::EFS::FileSystem",c,{deletionPolicy:"Retain"});let l=2;for(let u=0;u<l;u++)n.addResource(`${o}MountTarget${u+1}`,"AWS::EFS::MountTarget",{FileSystemId:e.ref(o),SubnetId:e.ref(`PrivateSubnet${u+1}`),SecurityGroups:[e.ref("EFSSecurityGroup")]},{dependsOn:[o,`PrivateSubnet${u+1}`]});n.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:e.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),n.addOutputs({[`${o}Id`]:{Description:`${i} EFS file system ID`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-efs`)}}})}class bg{template;config;resourceDependencies;constructor(n){this.config=n,this.resourceDependencies=new Map,this.template={AWSTemplateFormatVersion:"2010-09-09",Description:`Infrastructure for ${n.project.name} (${n.project.slug})`,Resources:{}}}build(){return this.addParameters(),this.addMappings(),this.addConditions(),this.addResources(),this.initializeOutputs(),this.resolveDependencies(),this.template}addParameters(){this.template.Parameters={Environment:{Type:"String",Default:"production",AllowedValues:["development","staging","production"],Description:"Environment name"}}}addMappings(){this.template.Mappings={RegionMap:{"us-east-1":{AMI:"ami-0f3caa1cf4417e51b"},"us-west-2":{AMI:"ami-0d1cd67c26f5fca19"},"eu-west-1":{AMI:"ami-0bbc25e23a7640b9b"}}}}addConditions(){this.template.Conditions={IsProduction:e.equals(e.ref("Environment"),"production"),HasDomain:e.not([e.equals(this.config.environments?.production?.domain||"","")])}}addResources(){let{infrastructure:n}=this.config;if(!n)return;if(n.network)this.addNetworkResources(n.network);if(n.storage)this.addStorageResources(n.storage);if(n.compute)this.addComputeResources(n.compute);if(n.databases)this.addDatabaseResources(n.databases);if(n.cache)this.addCacheResources(n.cache);if(n.cdn)this.addCDNResources(n.cdn);if(n.apiGateway)this.addApiGatewayResources(n.apiGateway);if(n.functions)this.addFunctionResources(n.functions);if(n.queues)this.addQueueResources(n.queues);if(n.messaging)this.addMessagingResources(n.messaging);if(n.monitoring)this.addMonitoringResources(n.monitoring);if(n.security)this.addSecurityResources(n.security)}initializeOutputs(){let n=this.template.Outputs||{};if(this.template.Outputs={StackName:{Description:"Stack name",Value:e.ref("AWS::StackName"),Export:{Name:e.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:e.ref("AWS::Region"),Export:{Name:e.sub("${AWS::StackName}-Region")}},...n},this.config.environments?.production?.domain)this.template.Outputs.Domain={Description:"Production domain",Value:this.config.environments.production.domain,Condition:"HasDomain"}}addResource(n,i,s,o){let c={Type:i,Properties:s};if(o?.dependsOn)c.DependsOn=o.dependsOn,this.trackDependency(n,o.dependsOn);if(o?.condition)c.Condition=o.condition;if(o?.deletionPolicy)c.DeletionPolicy=o.deletionPolicy;if(o?.updateReplacePolicy)c.UpdateReplacePolicy=o.updateReplacePolicy;this.template.Resources[n]=c}addOutputs(n){this.template.Outputs={...this.template.Outputs,...n}}getOutputs(){return this.template.Outputs||{}}hasResource(n){return n in this.template.Resources}getResource(n){return this.template.Resources[n]}trackDependency(n,i){if(!this.resourceDependencies.has(n))this.resourceDependencies.set(n,new Set);(Array.isArray(i)?i:[i]).forEach((s)=>this.resourceDependencies.get(n).add(s))}resolveDependencies(){let n=new Set,i=new Set,s=(o)=>{if(i.has(o))throw Error(`Circular dependency detected involving resource: ${o}`);if(n.has(o))return!0;n.add(o),i.add(o);let c=this.resourceDependencies.get(o);if(c)for(let l of c)s(l);return i.delete(o),!0};for(let o of this.resourceDependencies.keys())s(o)}toLogicalId(n){return n.split(/[-_\s]/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1).toLowerCase()).join("")}addNetworkResources(n){hn(this,n)}addStorageResources(n){vn(this,n)}addComputeResources(n){Zr(this,n)}addDatabaseResources(n){tn(this,n)}addFunctionResources(n){rn(this,n)}addCacheResources(n){Fr(this,n)}addQueueResources(n){yn(this,n)}addMessagingResources(n){cn(this,n)}addCDNResources(n){Jr(this,n)}addApiGatewayResources(n){Mr(this,n)}addMonitoringResources(n){un(this,n)}addSecurityResources(n){Sn(this,n)}}function Ld(n){return new bg(n).build()}function MI(n){let{name:i,slug:s,domain:o,subdomain:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:c&&o?`${c}.${o}`:o}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:o?{domain:c&&o?`${c}.${o}`:o,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/index.html",403:"/index.html"}}}}}function FI(n){let{name:i,slug:s,domain:o,instanceType:c="t3.small",minInstances:l=2,maxInstances:u=10}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",keyPair:`${s}-key`,autoScaling:{min:l,max:u,desired:l,targetCPU:70},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3}},userData:{packages:["nodejs","npm","nginx"],commands:["curl -fsSL https://bun.sh/install | bash","npm install -g pm2"]}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.micro",allocatedStorage:20,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:o?{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"}:void 0}}}}function UI(n){let{name:i,slug:s,domain:o,taskCpu:c="256",taskMemory:l="512",desiredCount:u=2}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:c,memory:l,containerDefinitions:[{name:"app",image:`${s}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:u,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:u,max:u*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${s}-main`]:{partitionKey:{name:"id",type:"S"},sortKey:{name:"createdAt",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}}}},functions:{"process-queue":{runtime:"nodejs20.x",handler:"dist/workers/queue.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${s}-queue`}]}},security:{certificate:o?{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"}:void 0}}}}function QI(n){let{name:i,slug:s,entry:o,domain:c,runtime:l="nodejs20.x",memory:u=1024,build:h,deploy:y,assets:f,queues:b=!0,scheduler:C="on",region:T="us-east-1"}=n;return{project:{name:i,slug:s,region:T},mode:"serverless",environments:{production:{type:"production",domain:c,app:{kind:"node",runtime:l,entry:o,memory:u,build:h,deploy:y,assets:f,queues:b,scheduler:C,domain:c}}}}}function $d(n){let i=n.database!==!1,s=n.cache!==!1,o=n.queue!==!1;return{project:{name:n.name,slug:n.slug,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:n.domain}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{fargate:{taskDefinition:{cpu:"256",memory:"512",containerDefinitions:[{name:"api",image:n.imageUri,portMappings:[{containerPort:3000}],environment:[{name:"NODE_ENV",value:"production"},{name:"PORT",value:"3000"},{name:"AWS_REGION",value:e.ref("AWS::Region")},...i?[{name:"DB_HOST",value:e.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:e.getAtt("PostgresDb","Endpoint.Port")}]:[],...s?[{name:"REDIS_HOST",value:e.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:e.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...o?[{name:"QUEUE_URL",value:e.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:i?[{name:"DB_USERNAME",valueFrom:e.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:e.sub("${DBSecret}:password::")}]:[]}]},service:{desiredCount:n.desiredCount||1,healthCheck:{path:"/api/health",interval:30,timeout:5},autoScaling:{min:n.desiredCount||1,max:6,targetCPU:70}},loadBalancer:{type:"application",...n.certificateArn?{customDomain:{domain:n.domain,certificateArn:n.certificateArn}}:{},...n.originVerifySecret?{originVerifyHeader:{name:"X-Origin-Verify",value:n.originVerifySecret}}:{}}}},...i?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...s?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...o?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function HI(n){let{name:i,slug:s,domain:o,apiSubdomain:c="api"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},storage:{frontend:{public:!0,versioning:!0,website:!0,encryption:!1}},cdn:{enabled:!0,customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/index.html"}},compute:{fargate:{taskDefinition:{cpu:"512",memory:"1024",containerDefinitions:[{name:"api",image:`${s}-api:latest`,portMappings:[{containerPort:3000}]}]},service:{desiredCount:2,healthCheck:{path:"/api/health",interval:30},autoScaling:{min:2,max:10,targetCPU:70}},loadBalancer:{type:"application",customDomain:{domain:`${c}.${o}`,certificateArn:"TO_BE_GENERATED"}}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.small",allocatedStorage:50,multiAZ:!0,backupRetentionDays:14,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.small",numCacheNodes:2,engine:"redis",engineVersion:"7.0"}},queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},security:{certificate:{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function GI(n){let{name:i,slug:s,domain:o}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,throttling:{rateLimit:1e4,burstLimit:5000},authorizer:{type:"JWT",identitySource:"$request.header.Authorization"}},functions:{users:{runtime:"nodejs20.x",handler:"dist/api/users.handler",memory:512,timeout:30,events:[{type:"http",path:"/users",method:"GET"},{type:"http",path:"/users",method:"POST"}]},products:{runtime:"nodejs20.x",handler:"dist/api/products.handler",memory:512,timeout:30,events:[{type:"http",path:"/products",method:"GET"}]}},databases:{dynamodb:{tables:{[`${s}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${s}-products`]:{partitionKey:{name:"productId",type:"S"},sortKey:{name:"category",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!1}}}},cache:{elasticache:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}},monitoring:{alarms:[{metric:"Errors",threshold:10,period:300,evaluationPeriods:1},{metric:"Duration",threshold:3000,period:300,evaluationPeriods:2}]}}}}function qI(n){let{name:i,slug:s,domain:o,instanceType:c="t3.small"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",keyPair:`${s}-key`,autoScaling:{min:2,max:6,desired:2,targetCPU:75},loadBalancer:{type:"application",healthCheck:{path:"/wp-admin/install.php",interval:30}},userData:{packages:["nginx","php8.1-fpm","php8.1-mysql","php8.1-curl","php8.1-gd","php8.1-mbstring","php8.1-xml","php8.1-zip"],commands:["cd /var/www","wget https://wordpress.org/latest.tar.gz","tar -xzf latest.tar.gz","chown -R www-data:www-data wordpress","rm /etc/nginx/sites-enabled/default","systemctl restart nginx","systemctl restart php8.1-fpm"]}}},fileSystem:{uploads:{performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30},mountPath:"/var/www/wordpress/wp-content/uploads"}},databases:{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.small",allocatedStorage:50,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0,databaseName:"wordpress"}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},cdn:{enabled:!0,customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:o,subdomains:[`www.${o}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function VI(n){let{name:i,slug:s,domain:o,apiDomain:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{storage:{static:{public:!0,versioning:!0,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"]}],lifecycleRules:[{id:"DeleteOldVersions",enabled:!0,expirationDays:90}]}},cdn:{enabled:!0,customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:0,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/404.html",500:"/500.html"},edgeFunctions:[{eventType:"origin-request",functionArn:"TO_BE_CREATED",name:"ssr-handler"}]},functions:{ssr:{runtime:"nodejs20.x",handler:"dist/edge/ssr.handler",memory:512,timeout:5},...c?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:c?{type:"HTTP",customDomain:{domain:c,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[o],allowMethods:["GET","POST","PUT","DELETE"],allowHeaders:["Content-Type","Authorization"]}}:void 0,databases:{dynamodb:{tables:{content:{partitionKey:{name:"id",type:"S"},sortKey:{name:"type",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!1}}}},security:{certificate:{domain:o,subdomains:c?[c]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function jI(n){let{name:i,slug:s,domain:o,services:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:c.map((l)=>({name:l.name,type:"fargate",taskDefinition:{cpu:l.cpu||"256",memory:l.memory||"512",containerDefinitions:[{name:l.name,image:`${s}-${l.name}:latest`,portMappings:[{containerPort:l.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${l.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:l.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${s}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:c.map((l)=>({path:`/${l.name}/{proxy+}`,integration:{type:"vpc-link",service:l.name}}))},databases:{dynamodb:{tables:Object.fromEntries(c.map((l)=>[`${s}-${l.name}`,{partitionKey:{name:"id",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}]))}},queues:{events:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},messaging:{topics:{events:{name:`${s}-events`,subscriptions:c.map((l)=>({protocol:"sqs",endpoint:`${s}-${l.name}-queue`,filterPolicy:{service:[l.name]}}))}}},monitoring:{dashboard:{name:`${s}-microservices`,widgets:c.map((l)=>({type:"metric",metrics:[{service:l.name,metric:"CPUUtilization"},{service:l.name,metric:"MemoryUtilization"},{service:l.name,metric:"RequestCount"}]}))},alarms:c.flatMap((l)=>[{name:`${l.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:l.name},{name:`${l.name}-errors`,metric:"Errors",threshold:10,service:l.name}])},security:{certificate:{domain:o,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function zI(n){let{name:i,slug:s,domain:o}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{apiGateway:{type:"websocket",customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,routes:[{path:"$connect",method:"WEBSOCKET",integration:"websocket-connect"},{path:"$disconnect",method:"WEBSOCKET",integration:"websocket-disconnect"},{path:"$default",method:"WEBSOCKET",integration:"websocket-default"},{path:"sendMessage",method:"WEBSOCKET",integration:"websocket-send-message"},{path:"joinRoom",method:"WEBSOCKET",integration:"websocket-join-room"}]},functions:{connect:{runtime:"nodejs20.x",handler:"dist/websocket/connect.handler",memory:512,timeout:30},disconnect:{runtime:"nodejs20.x",handler:"dist/websocket/disconnect.handler",memory:512,timeout:30},default:{runtime:"nodejs20.x",handler:"dist/websocket/default.handler",memory:512,timeout:30},"send-message":{runtime:"nodejs20.x",handler:"dist/websocket/sendMessage.handler",memory:512,timeout:30},"join-room":{runtime:"nodejs20.x",handler:"dist/websocket/joinRoom.handler",memory:512,timeout:30},broadcast:{runtime:"nodejs20.x",handler:"dist/streams/broadcast.handler",memory:1024,timeout:60,events:[{type:"dynamodb-stream",tableName:`${s}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${s}-connections`]:{partitionKey:{name:"connectionId",type:"S"},billingMode:"PAY_PER_REQUEST",globalSecondaryIndexes:[{name:"RoomIndex",partitionKey:{name:"roomId",type:"S"},sortKey:{name:"connectionId",type:"S"},projection:"ALL"}]},[`${s}-messages`]:{partitionKey:{name:"roomId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"UserIndex",partitionKey:{name:"userId",type:"S"},sortKey:{name:"timestamp",type:"S"},projection:"ALL"}]},[`${s}-rooms`]:{partitionKey:{name:"roomId",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},cache:{elasticache:{nodeType:"cache.t3.small",numCacheNodes:2,engine:"redis",engineVersion:"7.0"}},monitoring:{alarms:[{metric:"WebSocketConnections",threshold:1e4,evaluationPeriods:1},{metric:"IntegrationLatency",threshold:1000,evaluationPeriods:2}],dashboard:{name:`${s}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function KI(n){let{name:i,slug:s,retentionDays:o=7}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${s}-stream`,shardCount:2,retentionPeriod:o*24,encryption:!0}},storage:{raw:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0,lifecycleRules:[{id:"ArchiveOldData",enabled:!0,transitions:[{days:30,storageClass:"GLACIER"},{days:90,storageClass:"DEEP_ARCHIVE"}]}]},processed:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0}},functions:{"stream-processor":{runtime:"nodejs20.x",handler:"dist/processors/stream.handler",memory:2048,timeout:300,events:[{type:"kinesis",streamName:`${s}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${s}-raw`,prefix:"incoming/"}]},aggregator:{runtime:"nodejs20.x",handler:"dist/processors/aggregate.handler",memory:2048,timeout:600,events:[{type:"schedule",expression:"cron(0 * * * ? *)"}]}},analytics:{athena:{database:`${s}_analytics`,workgroup:`${s}-workgroup`,outputBucket:`${s}-query-results`,tables:[{name:"raw_events",location:`s3://${s}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${s}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${s}-crawler`,databaseName:`${s}_analytics`,s3Targets:[`s3://${s}-raw/`,`s3://${s}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${s}-etl-job`,scriptLocation:`s3://${s}-scripts/etl.py`,role:`${s}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${s}-metadata`]:{partitionKey:{name:"pipelineId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},queues:{failedJobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:1209600,deadLetterQueue:!0,maxReceiveCount:3}},workflow:{pipelines:[{name:`${s}-daily-pipeline`,type:"stepFunctions",definition:{StartAt:"ExtractData",States:{ExtractData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Next:"TransformData"},TransformData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Next:"LoadData"},LoadData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",End:!0}}},schedule:"cron(0 0 * * ? *)"}]},monitoring:{dashboard:{name:`${s}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function WI(n){let{name:i,slug:s,domain:o,modelS3Path:c=`s3://${s}-models/`,instanceType:l="ml.t3.medium"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{storage:{models:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0},datasets:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldDatasets",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},predictions:{public:!1,versioning:!1,encryption:!0,lifecycleRules:[{id:"DeleteOldPredictions",enabled:!0,expirationDays:30}]}},machineLearning:{sagemaker:{endpoints:[{name:`${s}-inference`,modelS3Path:c,instanceType:l,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${s}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,cors:{allowOrigins:["*"],allowMethods:["POST"],allowHeaders:["Content-Type","Authorization"]},throttling:{rateLimit:1000,burstLimit:500}},functions:{predict:{runtime:"python3.11",handler:"handlers/predict.handler",memory:2048,timeout:60,events:[{type:"http",path:"/predict",method:"POST"}],environment:{SAGEMAKER_ENDPOINT:`${s}-inference`,MODEL_BUCKET:`${s}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${s}-datasets`,suffix:".csv"}]},"trigger-training":{runtime:"python3.11",handler:"handlers/training.handler",memory:1024,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},databases:{dynamodb:{tables:{[`${s}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${s}-models`]:{partitionKey:{name:"modelId",type:"S"},sortKey:{name:"version",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},queues:{predictions:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},monitoring:{dashboard:{name:`${s}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function JI(n){let{name:i,slug:s,domain:o,instanceType:c="t3.medium",minInstances:l=2,maxInstances:u=10,databaseEngine:h="mysql",sessionStore:y="redis"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",autoScaling:{min:l,max:u,targetCPU:70,scaleUpCooldown:300,scaleDownCooldown:300},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},stickySession:{enabled:!0,duration:86400}},userData:`#!/bin/bash
2489
+ | limit 20`,region:e.ref("AWS::Region"),title:`Logs: ${l.logGroup}`}});else if(l.type==="text"&&l.text)s.push({type:"text",x:o,y:c,width:u,height:h,properties:{markdown:l.text}});if(o+=u,o>=24)o=0,c+=h}),n.addResource("CloudWatchDashboard","AWS::CloudWatch::Dashboard",{DashboardName:e.sub(`\${AWS::StackName}-${i.name}`),DashboardBody:JSON.stringify({widgets:s})}),n.addOutputs({DashboardURL:{Description:"CloudWatch Dashboard URL",Value:e.sub("https://console.aws.amazon.com/cloudwatch/home?region=${AWS::Region}#dashboards:name=${CloudWatchDashboard}")}})}function pn(n,i,s){let o=n.toLogicalId(`${i}-log-group`);n.addResource(o,"AWS::Logs::LogGroup",{LogGroupName:e.sub(`/aws/\${AWS::StackName}/${i}`),RetentionInDays:s||14,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]})}function Bt(n,i){if(i)return{ec2:"AWS/EC2",ecs:"AWS/ECS",lambda:"AWS/Lambda",rds:"AWS/RDS",dynamodb:"AWS/DynamoDB",s3:"AWS/S3",cloudfront:"AWS/CloudFront",alb:"AWS/ApplicationELB",nlb:"AWS/NetworkELB",apigateway:"AWS/ApiGateway",sqs:"AWS/SQS",sns:"AWS/SNS",kinesis:"AWS/Kinesis",elasticache:"AWS/ElastiCache"}[i.toLowerCase()]||"AWS/CloudWatch";let s=n.toLowerCase();if(s.includes("cpu")||s.includes("memory")||s.includes("network"))return"AWS/EC2";if(s.includes("lambda")||s.includes("invocation")||s.includes("duration"))return"AWS/Lambda";if(s.includes("request")||s.includes("latency")||s.includes("target"))return"AWS/ApplicationELB";if(s.includes("database")||s.includes("connection"))return"AWS/RDS";if(s.includes("read")||s.includes("write")||s.includes("consumed"))return"AWS/DynamoDB";return"AWS/CloudWatch"}function gn(n){return{ec2:[{Name:"InstanceId",Value:e.ref("EC2Instance")}],ecs:[{Name:"ClusterName",Value:e.ref("ECSCluster")},{Name:"ServiceName",Value:e.getAtt("ECSService","Name")}],lambda:[{Name:"FunctionName",Value:e.ref("LambdaFunction")}],rds:[{Name:"DBInstanceIdentifier",Value:e.ref("Database")}],dynamodb:[{Name:"TableName",Value:e.ref("DynamoDBTable")}],alb:[{Name:"LoadBalancer",Value:e.getAtt("LoadBalancer","LoadBalancerFullName")}],apigateway:[{Name:"ApiName",Value:e.ref("HttpApi")}]}[n.toLowerCase()]||[]}function hn(n,i){if(!i.vpc)return;let{cidr:s="10.0.0.0/16",availabilityZones:o=2,natGateways:c=1,enableDnsHostnames:l=!0,enableDnsSupport:u=!0}=i.vpc;n.addResource("VPC","AWS::EC2::VPC",{CidrBlock:s,EnableDnsHostnames:l,EnableDnsSupport:u,Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-vpc")}]}),n.addResource("InternetGateway","AWS::EC2::InternetGateway",{Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-igw")}]}),n.addResource("VPCGatewayAttachment","AWS::EC2::VPCGatewayAttachment",{VpcId:e.ref("VPC"),InternetGatewayId:e.ref("InternetGateway")},{dependsOn:["VPC","InternetGateway"]});let h=[];for(let b=0;b<o;b++){let v=`PublicSubnet${b+1}`;h.push(v),n.addResource(v,"AWS::EC2::Subnet",{VpcId:e.ref("VPC"),CidrBlock:e.select(b,e.cidr(e.getAtt("VPC","CidrBlock"),o*2,8)),AvailabilityZone:e.select(b,e.getAZs()),MapPublicIpOnLaunch:!0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-public-${b+1}`)},{Key:"Type",Value:"public"}]},{dependsOn:"VPC"})}let y=[];for(let b=0;b<o;b++){let v=`PrivateSubnet${b+1}`;y.push(v),n.addResource(v,"AWS::EC2::Subnet",{VpcId:e.ref("VPC"),CidrBlock:e.select(b+o,e.cidr(e.getAtt("VPC","CidrBlock"),o*2,8)),AvailabilityZone:e.select(b,e.getAZs()),MapPublicIpOnLaunch:!1,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-private-${b+1}`)},{Key:"Type",Value:"private"}]},{dependsOn:"VPC"})}let f=[];for(let b=0;b<c;b++){let v=`NatEIP${b+1}`;f.push(v),n.addResource(v,"AWS::EC2::EIP",{Domain:"vpc",Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-nat-eip-${b+1}`)}]},{dependsOn:"VPCGatewayAttachment"})}let S=[];for(let b=0;b<c;b++){let v=`NatGateway${b+1}`;S.push(v);let w=b%o;n.addResource(v,"AWS::EC2::NatGateway",{AllocationId:e.getAtt(f[b],"AllocationId"),SubnetId:e.ref(h[w]),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-nat-${b+1}`)}]},{dependsOn:[f[b],h[w]]})}n.addResource("PublicRouteTable","AWS::EC2::RouteTable",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-public-rt")}]},{dependsOn:"VPC"}),n.addResource("PublicRoute","AWS::EC2::Route",{RouteTableId:e.ref("PublicRouteTable"),DestinationCidrBlock:"0.0.0.0/0",GatewayId:e.ref("InternetGateway")},{dependsOn:["PublicRouteTable","VPCGatewayAttachment"]}),h.forEach((b,v)=>{n.addResource(`PublicSubnetRouteTableAssociation${v+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:e.ref(b),RouteTableId:e.ref("PublicRouteTable")},{dependsOn:[b,"PublicRouteTable"]})}),y.forEach((b,v)=>{let w=`PrivateRouteTable${v+1}`,E=v%c;n.addResource(w,"AWS::EC2::RouteTable",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-private-rt-${v+1}`)}]},{dependsOn:"VPC"}),n.addResource(`PrivateRoute${v+1}`,"AWS::EC2::Route",{RouteTableId:e.ref(w),DestinationCidrBlock:"0.0.0.0/0",NatGatewayId:e.ref(S[E])},{dependsOn:[w,S[E]]}),n.addResource(`PrivateSubnetRouteTableAssociation${v+1}`,"AWS::EC2::SubnetRouteTableAssociation",{SubnetId:e.ref(b),RouteTableId:e.ref(w)},{dependsOn:[b,w]})}),n.addResource("S3VPCEndpoint","AWS::EC2::VPCEndpoint",{VpcId:e.ref("VPC"),ServiceName:e.sub("com.amazonaws.${AWS::Region}.s3"),VpcEndpointType:"Gateway",RouteTableIds:[e.ref("PublicRouteTable"),...Array.from({length:o},(b,v)=>e.ref(`PrivateRouteTable${v+1}`))]},{dependsOn:"VPC"}),n.addResource("NetworkAcl","AWS::EC2::NetworkAcl",{VpcId:e.ref("VPC"),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-nacl")}]},{dependsOn:"VPC"}),n.addResource("NetworkAclEntryInbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:e.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),n.addResource("NetworkAclEntryOutbound","AWS::EC2::NetworkAclEntry",{NetworkAclId:e.ref("NetworkAcl"),RuleNumber:100,Protocol:-1,Egress:!0,RuleAction:"allow",CidrBlock:"0.0.0.0/0"},{dependsOn:"NetworkAcl"}),n.addOutputs({VPCId:{Description:"VPC ID",Value:e.ref("VPC"),Export:{Name:e.sub("${AWS::StackName}-VPC")}},PublicSubnets:{Description:"Public subnet IDs",Value:e.join(",",h.map((b)=>e.ref(b))),Export:{Name:e.sub("${AWS::StackName}-PublicSubnets")}},PrivateSubnets:{Description:"Private subnet IDs",Value:e.join(",",y.map((b)=>e.ref(b))),Export:{Name:e.sub("${AWS::StackName}-PrivateSubnets")}}})}function yn(n,i){for(let[s,o]of Object.entries(i))fn(n,s,o)}function fn(n,i,s){let o=n.toLogicalId(`${i}-queue`),c=s.fifo||!1,l;if(s.deadLetterQueue){let h=`${o}DLQ`;n.addResource(h,"AWS::SQS::Queue",{QueueName:c?e.sub(`\${AWS::StackName}-${i}-dlq.fifo`):e.sub(`\${AWS::StackName}-${i}-dlq`),FifoQueue:c,MessageRetentionPeriod:1209600,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-dlq`)}]},{deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),l=e.getAtt(h,"Arn")}let u={QueueName:c?e.sub(`\${AWS::StackName}-${i}.fifo`):e.sub(`\${AWS::StackName}-${i}`),FifoQueue:c,VisibilityTimeout:s.visibilityTimeout||30,MessageRetentionPeriod:s.messageRetentionPeriod||345600,ReceiveMessageWaitTimeSeconds:s.receiveMessageWaitTime||0,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(c&&s.contentBasedDeduplication)u.ContentBasedDeduplication=!0;if(s.deadLetterQueue&&l)u.RedrivePolicy={deadLetterTargetArn:l,maxReceiveCount:s.maxReceiveCount||3};if(n.addResource(o,"AWS::SQS::Queue",u,{dependsOn:s.deadLetterQueue?`${o}DLQ`:void 0,deletionPolicy:"Retain",updateReplacePolicy:"Retain"}),n.addResource(`${o}Policy`,"AWS::SQS::QueuePolicy",{Queues:[e.ref(o)],PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:["lambda.amazonaws.com","events.amazonaws.com","sns.amazonaws.com"]},Action:"sqs:SendMessage",Resource:e.getAtt(o,"Arn"),Condition:{ArnEquals:{"aws:SourceArn":e.sub("arn:aws:*:${AWS::Region}:${AWS::AccountId}:*")}}}]}},{dependsOn:o}),n.addOutputs({[`${o}Url`]:{Description:`${i} queue URL`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-queue-url`)}},[`${o}Arn`]:{Description:`${i} queue ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i}-queue-arn`)}}}),s.deadLetterQueue)n.addOutputs({[`${o}DLQUrl`]:{Description:`${i} dead letter queue URL`,Value:e.ref(`${o}DLQ`),Export:{Name:e.sub(`\${AWS::StackName}-${i}-dlq-url`)}}})}function Sn(n,i){if(i.certificate)bn(n,i.certificate);if(i.waf?.enabled)An(n,i.waf);if(i.securityGroups)for(let[s,o]of Object.entries(i.securityGroups))Cn(n,s,o)}function bn(n,i){if(!i)return;let s=[i.domain];if(i.subdomains)s.push(...i.subdomains);n.addResource("Certificate","AWS::CertificateManager::Certificate",{DomainName:i.domain,SubjectAlternativeNames:i.subdomains,ValidationMethod:i.validationMethod||"DNS",DomainValidationOptions:s.map((o)=>({DomainName:o,HostedZoneId:e.ref("HostedZone")})),Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-certificate")}]}),n.addOutputs({CertificateArn:{Description:"ACM Certificate ARN",Value:e.ref("Certificate"),Export:{Name:e.sub("${AWS::StackName}-certificate-arn")}}})}function An(n,i){if(!i)return;let s=[],o=i.rules||["rateLimit","sqlInjection","xss"];if(o.includes("rateLimit"))s.push({Name:"RateLimitRule",Priority:1,Statement:{RateBasedStatement:{Limit:i.rateLimit||2000,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"RateLimitRule"}});let c=s.length+1;if(o.includes("sqlInjection"))s.push({Name:"AWSManagedRulesSQLi",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesSQLiRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesSQLi"}});if(o.includes("xss"))s.push({Name:"AWSManagedRulesXSS",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesXSS"}});if(o.includes("knownBadInputs"))s.push({Name:"AWSManagedRulesKnownBadInputs",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesKnownBadInputsRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesKnownBadInputs"}});if(o.includes("coreRuleSet"))s.push({Name:"AWSManagedRulesCoreRuleSet",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesCommonRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesCoreRuleSet"}});if(o.includes("linuxRuleSet"))s.push({Name:"AWSManagedRulesLinuxRuleSet",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesLinuxRuleSet"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesLinuxRuleSet"}});if(o.includes("apiProtection"))s.push({Name:"AWSManagedRulesAPIProtection",Priority:c++,Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:"AWSManagedRulesAmazonIpReputationList"}},OverrideAction:{None:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"AWSManagedRulesAPIProtection"}});if(o.includes("geoBlock"))s.push({Name:"GeoBlockRule",Priority:c++,Statement:{GeoMatchStatement:{CountryCodes:["CN","RU"]}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"GeoBlockRule"}});if(o.includes("connectionLimit"))s.push({Name:"ConnectionLimitRule",Priority:c++,Statement:{RateBasedStatement:{Limit:100,AggregateKeyType:"IP"}},Action:{Block:{}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:"ConnectionLimitRule"}});if(n.addResource("WebACL","AWS::WAFv2::WebACL",{Name:e.sub("${AWS::StackName}-waf"),Scope:i.scope||"REGIONAL",DefaultAction:{Allow:{}},Rules:s,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:e.sub("${AWS::StackName}-waf")},Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-waf")}]}),n.hasResource("LoadBalancer"))n.addResource("WebACLAssociation","AWS::WAFv2::WebACLAssociation",{ResourceArn:e.ref("LoadBalancer"),WebACLArn:e.getAtt("WebACL","Arn")},{dependsOn:["WebACL","LoadBalancer"]});n.addOutputs({WebACLId:{Description:"WAF Web ACL ID",Value:e.ref("WebACL"),Export:{Name:e.sub("${AWS::StackName}-waf-id")}},WebACLArn:{Description:"WAF Web ACL ARN",Value:e.getAtt("WebACL","Arn"),Export:{Name:e.sub("${AWS::StackName}-waf-arn")}}})}function Cn(n,i,s){if(!s)return;let o=n.toLogicalId(`${i}-security-group`),c=s.ingress?.map((u)=>({IpProtocol:u.protocol,FromPort:u.port,ToPort:u.port,CidrIp:u.cidr,SourceSecurityGroupId:u.source?e.ref(u.source):void 0}))||[],l=s.egress?.map((u)=>({IpProtocol:u.protocol,FromPort:u.port,ToPort:u.port,CidrIp:u.cidr||"0.0.0.0/0"}))||[{IpProtocol:"-1",CidrIp:"0.0.0.0/0"}];n.addResource(o,"AWS::EC2::SecurityGroup",{GroupDescription:`Security group for ${i}`,VpcId:e.ref("VPC"),SecurityGroupIngress:c,SecurityGroupEgress:l,Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}-sg`)}]},{dependsOn:"VPC"}),n.addOutputs({[`${o}Id`]:{Description:`${i} security group ID`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-sg-id`)}}})}function vn(n,i){for(let[s,o]of Object.entries(i)){if(o.type==="efs"){wn(n,s,o);continue}Tn(n,s,o)}}function Tn(n,i,s){let o=n.toLogicalId(`${i}-bucket`),c={BucketName:e.sub(`\${AWS::StackName}-${i}`),Tags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(s.versioning)c.VersioningConfiguration={Status:"Enabled"};if(s.encryption)c.BucketEncryption={ServerSideEncryptionConfiguration:[{ServerSideEncryptionByDefault:{SSEAlgorithm:"AES256"}}]};if(!s.public)c.PublicAccessBlockConfiguration={BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0};if(s.website)c.WebsiteConfiguration={IndexDocument:"index.html",ErrorDocument:"index.html"};if(s.cors&&s.cors.length>0)c.CorsConfiguration={CorsRules:s.cors.map((l)=>({AllowedOrigins:l.allowedOrigins,AllowedMethods:l.allowedMethods,AllowedHeaders:l.allowedHeaders||["*"],MaxAge:l.maxAge||3600}))};if(s.lifecycleRules&&s.lifecycleRules.length>0)c.LifecycleConfiguration={Rules:s.lifecycleRules.map((l)=>({Id:l.id,Status:l.enabled?"Enabled":"Disabled",ExpirationInDays:l.expirationDays,Transitions:l.transitions?.map((u)=>({TransitionInDays:u.days,StorageClass:u.storageClass}))}))};if(s.intelligentTiering)c.IntelligentTieringConfigurations=[{Id:"EntireBucket",Status:"Enabled",Tierings:[{AccessTier:"ARCHIVE_ACCESS",Days:90},{AccessTier:"DEEP_ARCHIVE_ACCESS",Days:180}]}];if(n.addResource(o,"AWS::S3::Bucket",c,{deletionPolicy:s.versioning?"Retain":"Delete"}),s.public)n.addResource(`${o}Policy`,"AWS::S3::BucketPolicy",{Bucket:e.ref(o),PolicyDocument:{Version:"2012-10-17",Statement:[{Sid:"PublicReadGetObject",Effect:"Allow",Principal:"*",Action:"s3:GetObject",Resource:e.join("",[ho.s3Bucket(e.ref(o)),"/*"])}]}},{dependsOn:o});if(n.addOutputs({[`${o}Name`]:{Description:`${i} bucket name`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-bucket`)}},[`${o}Arn`]:{Description:`${i} bucket ARN`,Value:e.getAtt(o,"Arn"),Export:{Name:e.sub(`\${AWS::StackName}-${i}-bucket-arn`)}}}),s.website)n.addOutputs({[`${o}WebsiteURL`]:{Description:`${i} website URL`,Value:e.getAtt(o,"WebsiteURL")}})}function wn(n,i,s){let o=n.toLogicalId(`${i}-efs`),c={Encrypted:s.encryption!==!1,PerformanceMode:s.performanceMode||"generalPurpose",ThroughputMode:s.throughputMode||"bursting",FileSystemTags:[{Key:"Name",Value:e.sub(`\${AWS::StackName}-${i}`)}]};if(s.lifecyclePolicy){if(c.LifecyclePolicies=[],s.lifecyclePolicy.transitionToIA)c.LifecyclePolicies.push({TransitionToIA:`AFTER_${s.lifecyclePolicy.transitionToIA}_DAYS`});if(s.lifecyclePolicy.transitionToPrimaryStorageClass)c.LifecyclePolicies.push({TransitionToPrimaryStorageClass:"AFTER_1_ACCESS"})}n.addResource(o,"AWS::EFS::FileSystem",c,{deletionPolicy:"Retain"});let l=2;for(let u=0;u<l;u++)n.addResource(`${o}MountTarget${u+1}`,"AWS::EFS::MountTarget",{FileSystemId:e.ref(o),SubnetId:e.ref(`PrivateSubnet${u+1}`),SecurityGroups:[e.ref("EFSSecurityGroup")]},{dependsOn:[o,`PrivateSubnet${u+1}`]});n.addResource("EFSSecurityGroup","AWS::EC2::SecurityGroup",{GroupDescription:"Security group for EFS mount targets",VpcId:e.ref("VPC"),SecurityGroupIngress:[{IpProtocol:"tcp",FromPort:2049,ToPort:2049,SourceSecurityGroupId:e.ref("AppSecurityGroup")}],Tags:[{Key:"Name",Value:e.sub("${AWS::StackName}-efs-sg")}]},{dependsOn:"VPC"}),n.addOutputs({[`${o}Id`]:{Description:`${i} EFS file system ID`,Value:e.ref(o),Export:{Name:e.sub(`\${AWS::StackName}-${i}-efs`)}}})}class bg{template;config;resourceDependencies;constructor(n){this.config=n,this.resourceDependencies=new Map,this.template={AWSTemplateFormatVersion:"2010-09-09",Description:`Infrastructure for ${n.project.name} (${n.project.slug})`,Resources:{}}}build(){return this.addParameters(),this.addMappings(),this.addConditions(),this.addResources(),this.initializeOutputs(),this.resolveDependencies(),this.template}addParameters(){this.template.Parameters={Environment:{Type:"String",Default:"production",AllowedValues:["development","staging","production"],Description:"Environment name"}}}addMappings(){this.template.Mappings={RegionMap:{"us-east-1":{AMI:"ami-0f3caa1cf4417e51b"},"us-west-2":{AMI:"ami-0d1cd67c26f5fca19"},"eu-west-1":{AMI:"ami-0bbc25e23a7640b9b"}}}}addConditions(){this.template.Conditions={IsProduction:e.equals(e.ref("Environment"),"production"),HasDomain:e.not([e.equals(this.config.environments?.production?.domain||"","")])}}addResources(){let{infrastructure:n}=this.config;if(!n)return;if(n.network)this.addNetworkResources(n.network);if(n.storage)this.addStorageResources(n.storage);if(n.compute)this.addComputeResources(n.compute);if(n.databases)this.addDatabaseResources(n.databases);if(n.cache)this.addCacheResources(n.cache);if(n.cdn)this.addCDNResources(n.cdn);if(n.apiGateway)this.addApiGatewayResources(n.apiGateway);if(n.functions)this.addFunctionResources(n.functions);if(n.queues)this.addQueueResources(n.queues);if(n.messaging)this.addMessagingResources(n.messaging);if(n.monitoring)this.addMonitoringResources(n.monitoring);if(n.security)this.addSecurityResources(n.security)}initializeOutputs(){let n=this.template.Outputs||{};if(this.template.Outputs={StackName:{Description:"Stack name",Value:e.ref("AWS::StackName"),Export:{Name:e.sub("${AWS::StackName}-Name")}},Region:{Description:"AWS Region",Value:e.ref("AWS::Region"),Export:{Name:e.sub("${AWS::StackName}-Region")}},...n},this.config.environments?.production?.domain)this.template.Outputs.Domain={Description:"Production domain",Value:this.config.environments.production.domain,Condition:"HasDomain"}}addResource(n,i,s,o){let c={Type:i,Properties:s};if(o?.dependsOn)c.DependsOn=o.dependsOn,this.trackDependency(n,o.dependsOn);if(o?.condition)c.Condition=o.condition;if(o?.deletionPolicy)c.DeletionPolicy=o.deletionPolicy;if(o?.updateReplacePolicy)c.UpdateReplacePolicy=o.updateReplacePolicy;this.template.Resources[n]=c}addOutputs(n){this.template.Outputs={...this.template.Outputs,...n}}getOutputs(){return this.template.Outputs||{}}hasResource(n){return n in this.template.Resources}getResource(n){return this.template.Resources[n]}trackDependency(n,i){if(!this.resourceDependencies.has(n))this.resourceDependencies.set(n,new Set);(Array.isArray(i)?i:[i]).forEach((s)=>this.resourceDependencies.get(n).add(s))}resolveDependencies(){let n=new Set,i=new Set,s=(o)=>{if(i.has(o))throw Error(`Circular dependency detected involving resource: ${o}`);if(n.has(o))return!0;n.add(o),i.add(o);let c=this.resourceDependencies.get(o);if(c)for(let l of c)s(l);return i.delete(o),!0};for(let o of this.resourceDependencies.keys())s(o)}toLogicalId(n){return n.split(/[-_\s]/).map((i)=>i.charAt(0).toUpperCase()+i.slice(1).toLowerCase()).join("")}addNetworkResources(n){hn(this,n)}addStorageResources(n){vn(this,n)}addComputeResources(n){Zr(this,n)}addDatabaseResources(n){tn(this,n)}addFunctionResources(n){rn(this,n)}addCacheResources(n){Fr(this,n)}addQueueResources(n){yn(this,n)}addMessagingResources(n){cn(this,n)}addCDNResources(n){Jr(this,n)}addApiGatewayResources(n){Mr(this,n)}addMonitoringResources(n){un(this,n)}addSecurityResources(n){Sn(this,n)}}function Ld(n){return new bg(n).build()}function MI(n){let{name:i,slug:s,domain:o,subdomain:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:c&&o?`${c}.${o}`:o}},infrastructure:{storage:{assets:{public:!0,versioning:!1,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"],allowedHeaders:["*"],maxAge:3600}]}},cdn:{enabled:!0,customDomain:o?{domain:c&&o?`${c}.${o}`:o,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/index.html",403:"/index.html"}}}}}function FI(n){let{name:i,slug:s,domain:o,instanceType:c="t3.small",minInstances:l=2,maxInstances:u=10}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",keyPair:`${s}-key`,autoScaling:{min:l,max:u,desired:l,targetCPU:70},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3}},userData:{packages:["nodejs","npm","nginx"],commands:["curl -fsSL https://bun.sh/install | bash","npm install -g pm2"]}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.micro",allocatedStorage:20,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:o?{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"}:void 0}}}}function UI(n){let{name:i,slug:s,domain:o,taskCpu:c="256",taskMemory:l="512",desiredCount:u=2}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:0}},compute:{fargate:{taskDefinition:{cpu:c,memory:l,containerDefinitions:[{name:"app",image:`${s}-app:latest`,portMappings:[{containerPort:3000}],environment:[],secrets:[]}]},service:{desiredCount:u,healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},autoScaling:{min:u,max:u*5,targetCPU:70,targetMemory:80}},loadBalancer:{type:"application"}}},databases:{dynamodb:{tables:{[`${s}-main`]:{partitionKey:{name:"id",type:"S"},sortKey:{name:"createdAt",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}}}},functions:{"process-queue":{runtime:"nodejs20.x",handler:"dist/workers/queue.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${s}-queue`}]}},security:{certificate:o?{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"}:void 0}}}}function QI(n){let{name:i,slug:s,entry:o,domain:c,runtime:l="nodejs20.x",memory:u=1024,build:h,deploy:y,assets:f,queues:S=!0,scheduler:b="on",region:v="us-east-1"}=n;return{project:{name:i,slug:s,region:v},mode:"serverless",environments:{production:{type:"production",domain:c,app:{kind:"node",runtime:l,entry:o,memory:u,build:h,deploy:y,assets:f,queues:S,scheduler:b,domain:c}}}}}function $d(n){let i=n.database!==!1,s=n.cache!==!1,o=n.queue!==!1;return{project:{name:n.name,slug:n.slug,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:n.domain}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{fargate:{taskDefinition:{cpu:"256",memory:"512",containerDefinitions:[{name:"api",image:n.imageUri,portMappings:[{containerPort:3000}],environment:[{name:"NODE_ENV",value:"production"},{name:"PORT",value:"3000"},{name:"AWS_REGION",value:e.ref("AWS::Region")},...i?[{name:"DB_HOST",value:e.getAtt("PostgresDb","Endpoint.Address")},{name:"DB_PORT",value:e.getAtt("PostgresDb","Endpoint.Port")}]:[],...s?[{name:"REDIS_HOST",value:e.getAtt("RedisReplicationGroup","PrimaryEndPoint.Address")},{name:"REDIS_PORT",value:e.getAtt("RedisReplicationGroup","PrimaryEndPoint.Port")},{name:"REDIS_TLS",value:"true"}]:[],...o?[{name:"QUEUE_URL",value:e.ref("JobsQueue")}]:[],{name:"MAIL_TRANSPORT",value:"ses"}],secrets:i?[{name:"DB_USERNAME",valueFrom:e.sub("${DBSecret}:username::")},{name:"DB_PASSWORD",valueFrom:e.sub("${DBSecret}:password::")}]:[]}]},service:{desiredCount:n.desiredCount||1,healthCheck:{path:"/api/health",interval:30,timeout:5},autoScaling:{min:n.desiredCount||1,max:6,targetCPU:70}},loadBalancer:{type:"application",...n.certificateArn?{customDomain:{domain:n.domain,certificateArn:n.certificateArn}}:{},...n.originVerifySecret?{originVerifyHeader:{name:"X-Origin-Verify",value:n.originVerifySecret}}:{}}}},...i?{databases:{postgres:{engine:"postgres",version:"16",instanceClass:"db.t4g.micro",allocatedStorage:20,maxAllocatedStorage:100,multiAZ:!1,backupRetentionDays:7,deletionProtection:!0}}}:{},...s?{cache:{redis:{nodeType:"cache.t4g.micro",numCacheNodes:2,engine:"redis",engineVersion:"7.1",automaticFailoverEnabled:!0,snapshotRetentionLimit:5}}}:{},...o?{queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0,maxReceiveCount:3,receiveMessageWaitTime:20}}}:{}}}}function HI(n){let{name:i,slug:s,domain:o,apiSubdomain:c="api"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},storage:{frontend:{public:!0,versioning:!0,website:!0,encryption:!1}},cdn:{enabled:!0,customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/index.html"}},compute:{fargate:{taskDefinition:{cpu:"512",memory:"1024",containerDefinitions:[{name:"api",image:`${s}-api:latest`,portMappings:[{containerPort:3000}]}]},service:{desiredCount:2,healthCheck:{path:"/api/health",interval:30},autoScaling:{min:2,max:10,targetCPU:70}},loadBalancer:{type:"application",customDomain:{domain:`${c}.${o}`,certificateArn:"TO_BE_GENERATED"}}}},databases:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.small",allocatedStorage:50,multiAZ:!0,backupRetentionDays:14,deletionProtection:!0}},cache:{redis:{nodeType:"cache.t3.small",numCacheNodes:2,engine:"redis",engineVersion:"7.0"}},queues:{jobs:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},security:{certificate:{domain:o,subdomains:[`*.${o}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss"]}}}}}function GI(n){let{name:i,slug:s,domain:o}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{apiGateway:{type:"HTTP",cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"],allowHeaders:["Content-Type","Authorization"],maxAge:3600},customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,throttling:{rateLimit:1e4,burstLimit:5000},authorizer:{type:"JWT",identitySource:"$request.header.Authorization"}},functions:{users:{runtime:"nodejs20.x",handler:"dist/api/users.handler",memory:512,timeout:30,events:[{type:"http",path:"/users",method:"GET"},{type:"http",path:"/users",method:"POST"}]},products:{runtime:"nodejs20.x",handler:"dist/api/products.handler",memory:512,timeout:30,events:[{type:"http",path:"/products",method:"GET"}]}},databases:{dynamodb:{tables:{[`${s}-users`]:{partitionKey:{name:"userId",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"EmailIndex",partitionKey:{name:"email",type:"S"},projection:"ALL"}]},[`${s}-products`]:{partitionKey:{name:"productId",type:"S"},sortKey:{name:"category",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!1}}}},cache:{elasticache:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}},monitoring:{alarms:[{metric:"Errors",threshold:10,period:300,evaluationPeriods:1},{metric:"Duration",threshold:3000,period:300,evaluationPeriods:2}]}}}}function qI(n){let{name:i,slug:s,domain:o,instanceType:c="t3.small"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:1}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",keyPair:`${s}-key`,autoScaling:{min:2,max:6,desired:2,targetCPU:75},loadBalancer:{type:"application",healthCheck:{path:"/wp-admin/install.php",interval:30}},userData:{packages:["nginx","php8.1-fpm","php8.1-mysql","php8.1-curl","php8.1-gd","php8.1-mbstring","php8.1-xml","php8.1-zip"],commands:["cd /var/www","wget https://wordpress.org/latest.tar.gz","tar -xzf latest.tar.gz","chown -R www-data:www-data wordpress","rm /etc/nginx/sites-enabled/default","systemctl restart nginx","systemctl restart php8.1-fpm"]}}},fileSystem:{uploads:{performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30},mountPath:"/var/www/wordpress/wp-content/uploads"}},databases:{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.small",allocatedStorage:50,multiAZ:!0,backupRetentionDays:7,deletionProtection:!0,databaseName:"wordpress"}},cache:{redis:{nodeType:"cache.t3.micro",numCacheNodes:1,engine:"redis",engineVersion:"7.0"}},cdn:{enabled:!0,customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,origins:[{type:"alb",pathPattern:"/wp-content/*"}]},security:{certificate:{domain:o,subdomains:[`www.${o}`],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","wordpressRules"]}}}}}function VI(n){let{name:i,slug:s,domain:o,apiDomain:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{storage:{static:{public:!0,versioning:!0,website:!0,encryption:!1,cors:[{allowedOrigins:["*"],allowedMethods:["GET","HEAD"]}],lifecycleRules:[{id:"DeleteOldVersions",enabled:!0,expirationDays:90}]}},cdn:{enabled:!0,customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cachePolicy:{minTTL:0,defaultTTL:0,maxTTL:31536000},compress:!0,http3:!0,errorPages:{404:"/404.html",500:"/500.html"},edgeFunctions:[{eventType:"origin-request",functionArn:"TO_BE_CREATED",name:"ssr-handler"}]},functions:{ssr:{runtime:"nodejs20.x",handler:"dist/edge/ssr.handler",memory:512,timeout:5},...c?{api:{runtime:"nodejs20.x",handler:"dist/api/index.handler",memory:1024,timeout:30,events:[{type:"http",path:"/{proxy+}",method:"ANY"}]}}:{}},apiGateway:c?{type:"HTTP",customDomain:{domain:c,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:[o],allowMethods:["GET","POST","PUT","DELETE"],allowHeaders:["Content-Type","Authorization"]}}:void 0,databases:{dynamodb:{tables:{content:{partitionKey:{name:"id",type:"S"},sortKey:{name:"type",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!1}}}},security:{certificate:{domain:o,subdomains:c?[c]:[],validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","geoBlock"]}}}}}function jI(n){let{name:i,slug:s,domain:o,services:c}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:3,natGateways:2}},compute:{services:c.map((l)=>({name:l.name,type:"fargate",taskDefinition:{cpu:l.cpu||"256",memory:l.memory||"512",containerDefinitions:[{name:l.name,image:`${s}-${l.name}:latest`,portMappings:[{containerPort:l.port}],healthCheck:{command:["CMD-SHELL",`curl -f http://localhost:${l.port}/health || exit 1`],interval:30,timeout:5,retries:3}}]},service:{desiredCount:l.desiredCount||2,serviceDiscovery:{enabled:!0,namespace:`${s}.local`},autoScaling:{min:2,max:10,targetCPU:70}}}))},apiGateway:{type:"HTTP",customDomain:{domain:o,certificateArn:"TO_BE_GENERATED"},cors:{allowOrigins:["*"],allowMethods:["GET","POST","PUT","DELETE","PATCH"]},routes:c.map((l)=>({path:`/${l.name}/{proxy+}`,integration:{type:"vpc-link",service:l.name}}))},databases:{dynamodb:{tables:Object.fromEntries(c.map((l)=>[`${s}-${l.name}`,{partitionKey:{name:"id",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0}]))}},queues:{events:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:345600,deadLetterQueue:!0}},messaging:{topics:{events:{name:`${s}-events`,subscriptions:c.map((l)=>({protocol:"sqs",endpoint:`${s}-${l.name}-queue`,filterPolicy:{service:[l.name]}}))}}},monitoring:{dashboard:{name:`${s}-microservices`,widgets:c.map((l)=>({type:"metric",metrics:[{service:l.name,metric:"CPUUtilization"},{service:l.name,metric:"MemoryUtilization"},{service:l.name,metric:"RequestCount"}]}))},alarms:c.flatMap((l)=>[{name:`${l.name}-high-cpu`,metric:"CPUUtilization",threshold:80,service:l.name},{name:`${l.name}-errors`,metric:"Errors",threshold:10,service:l.name}])},security:{certificate:{domain:o,validationMethod:"DNS"},waf:{enabled:!0,rules:["rateLimit","sqlInjection"]}}}}}function zI(n){let{name:i,slug:s,domain:o}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{apiGateway:{type:"websocket",customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,routes:[{path:"$connect",method:"WEBSOCKET",integration:"websocket-connect"},{path:"$disconnect",method:"WEBSOCKET",integration:"websocket-disconnect"},{path:"$default",method:"WEBSOCKET",integration:"websocket-default"},{path:"sendMessage",method:"WEBSOCKET",integration:"websocket-send-message"},{path:"joinRoom",method:"WEBSOCKET",integration:"websocket-join-room"}]},functions:{connect:{runtime:"nodejs20.x",handler:"dist/websocket/connect.handler",memory:512,timeout:30},disconnect:{runtime:"nodejs20.x",handler:"dist/websocket/disconnect.handler",memory:512,timeout:30},default:{runtime:"nodejs20.x",handler:"dist/websocket/default.handler",memory:512,timeout:30},"send-message":{runtime:"nodejs20.x",handler:"dist/websocket/sendMessage.handler",memory:512,timeout:30},"join-room":{runtime:"nodejs20.x",handler:"dist/websocket/joinRoom.handler",memory:512,timeout:30},broadcast:{runtime:"nodejs20.x",handler:"dist/streams/broadcast.handler",memory:1024,timeout:60,events:[{type:"dynamodb-stream",tableName:`${s}-messages`,startingPosition:"LATEST",batchSize:100}]}},databases:{dynamodb:{tables:{[`${s}-connections`]:{partitionKey:{name:"connectionId",type:"S"},billingMode:"PAY_PER_REQUEST",globalSecondaryIndexes:[{name:"RoomIndex",partitionKey:{name:"roomId",type:"S"},sortKey:{name:"connectionId",type:"S"},projection:"ALL"}]},[`${s}-messages`]:{partitionKey:{name:"roomId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0,pointInTimeRecovery:!0,globalSecondaryIndexes:[{name:"UserIndex",partitionKey:{name:"userId",type:"S"},sortKey:{name:"timestamp",type:"S"},projection:"ALL"}]},[`${s}-rooms`]:{partitionKey:{name:"roomId",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},cache:{elasticache:{nodeType:"cache.t3.small",numCacheNodes:2,engine:"redis",engineVersion:"7.0"}},monitoring:{alarms:[{metric:"WebSocketConnections",threshold:1e4,evaluationPeriods:1},{metric:"IntegrationLatency",threshold:1000,evaluationPeriods:2}],dashboard:{name:`${s}-realtime`,widgets:[{type:"metric",metrics:["WebSocketConnections","MessagesSent","IntegrationLatency"]}]}},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","connectionLimit"]}}}}}function KI(n){let{name:i,slug:s,retentionDays:o=7}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",infrastructure:{streaming:{dataStream:{name:`${s}-stream`,shardCount:2,retentionPeriod:o*24,encryption:!0}},storage:{raw:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0,lifecycleRules:[{id:"ArchiveOldData",enabled:!0,transitions:[{days:30,storageClass:"GLACIER"},{days:90,storageClass:"DEEP_ARCHIVE"}]}]},processed:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0}},functions:{"stream-processor":{runtime:"nodejs20.x",handler:"dist/processors/stream.handler",memory:2048,timeout:300,events:[{type:"kinesis",streamName:`${s}-stream`,batchSize:1000,startingPosition:"LATEST",parallelizationFactor:10}]},transformer:{runtime:"nodejs20.x",handler:"dist/processors/transform.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${s}-raw`,prefix:"incoming/"}]},aggregator:{runtime:"nodejs20.x",handler:"dist/processors/aggregate.handler",memory:2048,timeout:600,events:[{type:"schedule",expression:"cron(0 * * * ? *)"}]}},analytics:{athena:{database:`${s}_analytics`,workgroup:`${s}-workgroup`,outputBucket:`${s}-query-results`,tables:[{name:"raw_events",location:`s3://${s}-raw/events/`,format:"parquet",partitionKeys:["year","month","day"]},{name:"processed_events",location:`s3://${s}-processed/events/`,format:"parquet",partitionKeys:["year","month","day"]}]},glue:{crawlers:[{name:`${s}-crawler`,databaseName:`${s}_analytics`,s3Targets:[`s3://${s}-raw/`,`s3://${s}-processed/`],schedule:"cron(0 2 * * ? *)"}],jobs:[{name:`${s}-etl-job`,scriptLocation:`s3://${s}-scripts/etl.py`,role:`${s}-glue-role`,maxCapacity:10,timeout:120}]}},databases:{dynamodb:{tables:{[`${s}-metadata`]:{partitionKey:{name:"pipelineId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},queues:{failedJobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:1209600,deadLetterQueue:!0,maxReceiveCount:3}},workflow:{pipelines:[{name:`${s}-daily-pipeline`,type:"stepFunctions",definition:{StartAt:"ExtractData",States:{ExtractData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Next:"TransformData"},TransformData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",Next:"LoadData"},LoadData:{Type:"Task",Resource:"arn:aws:states:::lambda:invoke",End:!0}}},schedule:"cron(0 0 * * ? *)"}]},monitoring:{dashboard:{name:`${s}-pipeline`,widgets:[{type:"metric",metrics:["KinesisIncomingRecords","LambdaInvocations","S3ObjectsCreated","GlueJobsSucceeded"]}]},alarms:[{metric:"LambdaErrors",threshold:10,evaluationPeriods:1},{metric:"KinesisIteratorAge",threshold:60000,evaluationPeriods:2}]}}}}function WI(n){let{name:i,slug:s,domain:o,modelS3Path:c=`s3://${s}-models/`,instanceType:l="ml.t3.medium"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"serverless",environments:{production:{type:"production",domain:o}},infrastructure:{storage:{models:{public:!1,versioning:!0,encryption:!0,intelligentTiering:!0},datasets:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldDatasets",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},predictions:{public:!1,versioning:!1,encryption:!0,lifecycleRules:[{id:"DeleteOldPredictions",enabled:!0,expirationDays:30}]}},machineLearning:{sagemaker:{endpoints:[{name:`${s}-inference`,modelS3Path:c,instanceType:l,initialInstanceCount:1,autoScaling:{minInstances:1,maxInstances:5,targetInvocationsPerInstance:1000}}],trainingJobs:[{name:`${s}-training`,algorithmSpecification:{trainingImage:"TO_BE_SPECIFIED",trainingInputMode:"File"},instanceType:"ml.p3.2xlarge",instanceCount:1,volumeSizeInGB:50,maxRuntimeInSeconds:86400}]}},apiGateway:{type:"HTTP",customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,cors:{allowOrigins:["*"],allowMethods:["POST"],allowHeaders:["Content-Type","Authorization"]},throttling:{rateLimit:1000,burstLimit:500}},functions:{predict:{runtime:"python3.11",handler:"handlers/predict.handler",memory:2048,timeout:60,events:[{type:"http",path:"/predict",method:"POST"}],environment:{SAGEMAKER_ENDPOINT:`${s}-inference`,MODEL_BUCKET:`${s}-models`}},"batch-predict":{runtime:"python3.11",handler:"handlers/batchPredict.handler",memory:3008,timeout:900,events:[{type:"s3",bucket:`${s}-datasets`,suffix:".csv"}]},"trigger-training":{runtime:"python3.11",handler:"handlers/training.handler",memory:1024,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},databases:{dynamodb:{tables:{[`${s}-predictions`]:{partitionKey:{name:"requestId",type:"S"},sortKey:{name:"timestamp",type:"S"},billingMode:"PAY_PER_REQUEST",streamEnabled:!0},[`${s}-models`]:{partitionKey:{name:"modelId",type:"S"},sortKey:{name:"version",type:"S"},billingMode:"PAY_PER_REQUEST"}}}},queues:{predictions:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},monitoring:{dashboard:{name:`${s}-ml`,widgets:[{type:"metric",metrics:["SageMakerInvocations","SageMakerModelLatency","APIGatewayRequests","LambdaErrors"]}]},alarms:[{metric:"SageMakerModelLatency",threshold:1000,evaluationPeriods:2},{metric:"SageMakerInvocationErrors",threshold:10,evaluationPeriods:1}]},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","apiProtection"]}}}}}function JI(n){let{name:i,slug:s,domain:o,instanceType:c="t3.medium",minInstances:l=2,maxInstances:u=10,databaseEngine:h="mysql",sessionStore:y="redis"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",environments:{production:{type:"production",domain:o}},infrastructure:{network:{vpc:{cidr:"10.0.0.0/16",availabilityZones:2,natGateways:2}},compute:{server:{instanceType:c,ami:"ubuntu-22.04",autoScaling:{min:l,max:u,targetCPU:70,scaleUpCooldown:300,scaleDownCooldown:300},loadBalancer:{type:"application",healthCheck:{path:"/health",interval:30,timeout:5,healthyThreshold:2,unhealthyThreshold:3},stickySession:{enabled:!0,duration:86400}},userData:`#!/bin/bash
2490
2490
  # Install Node.js or PHP/Python based on app needs
2491
2491
  # Configure application server (PM2, Nginx, Apache)
2492
2492
  # Mount EFS for shared file storage
2493
- `}},storage:{uploads:{type:"efs",performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30}},backups:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldBackups",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},static:{public:!0,versioning:!1,encryption:!1,cors:[{allowedOrigins:[o||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${s}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:h==="mysql"?{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",innodb_buffer_pool_size:"{DBInstanceClassMemory*3/4}",slow_query_log:"1",long_query_time:"2"}}}:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",shared_buffers:"{DBInstanceClassMemory/4}",log_min_duration_statement:"2000"}}},cache:y==="redis"?{redis:{nodeType:"cache.t3.medium",numCacheNodes:2,engine:"redis",engineVersion:"7.0",port:6379,parameterGroup:{maxmemoryPolicy:"allkeys-lru",timeout:"300"},snapshotRetentionLimit:5,snapshotWindow:"03:00-05:00",automaticFailoverEnabled:!0}}:void 0,queues:{jobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:345600,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3},emails:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},functions:{"job-worker":{runtime:"nodejs20.x",handler:"dist/workers/jobs.handler",memory:2048,timeout:900,events:[{type:"sqs",queueName:`${s}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${s}-emails`,batchSize:10}]},cleanup:{runtime:"nodejs20.x",handler:"dist/tasks/cleanup.handler",memory:512,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},monitoring:{dashboard:{name:`${s}-web-app`,widgets:[{type:"metric",metrics:["EC2CPUUtilization","ALBRequestCount","ALBTargetResponseTime","RDSCPUUtilization","RDSDatabaseConnections","RDSReadLatency","RDSWriteLatency"]}]},alarms:[{metric:"EC2CPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSCPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSDatabaseConnections",threshold:400,evaluationPeriods:1},{metric:"ALBTargetResponseTime",threshold:2000,evaluationPeriods:2},{metric:"ALBUnhealthyHostCount",threshold:1,evaluationPeriods:1}],logs:{retention:14,groups:[`${s}-app`,`${s}-nginx`,`${s}-workers`]}},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","knownBadInputs"]},securityGroups:{alb:{ingress:[{port:80,protocol:"tcp",cidr:"0.0.0.0/0"},{port:443,protocol:"tcp",cidr:"0.0.0.0/0"}]},app:{ingress:[{port:3000,protocol:"tcp",source:"alb-sg"}]},database:{ingress:[{port:h==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...y==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function XI(n){let{name:i,slug:s,domain:o,repository:c,phpVersion:l="8.3",size:u="small",database:h=s.replace(/-/g,"_"),databasePassword:y,sslEmail:f,deployStrategy:b="push",provider:C="hetzner"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",cloud:{provider:C},environments:{production:{type:"production",domain:o}},infrastructure:{compute:{mode:"server",size:u,runtime:"php",webServer:"nginx",php:{versions:[l],default:l},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:h,username:h,password:y}},sites:{main:{root:".",type:"laravel",domain:o,phpVersion:l,repository:{...c,strategy:b},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:f}}}}}function YI(n){let{name:i,slug:s,domain:o,layers:c,phpVersion:l="8.3",architecture:u="x86_64",memory:h=1024,build:y,deploy:f=["migrate --force"],cache:b="dynamodb",scheduler:C="on",region:T="us-east-1"}=n;return{project:{name:i,slug:s,region:T},mode:"serverless",environments:{production:{type:"production",domain:o,app:{kind:"php",runtime:"provided.al2023",phpVersion:l,architecture:u,layers:c,memory:h,build:y,deploy:f,assets:"public",queues:!0,scheduler:C,cache:{driver:b},domain:o}}}}}function ZI(n){return{root:n.root??"packages/ui/dist",deploy:"server",type:"static",domain:n.domain,build:n.build??"cd packages/ui && bun install && bun run build",ssl:{provider:"letsencrypt"},auth:{username:n.username??"admin",password:n.password}}}var uA=lg,pA="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function En(n){let i=n.split(".").filter(Boolean);return i.length<=2?n:i.slice(-2).join(".")}function Pn(n){let i=2166136261;for(let s=0;s<n.length;s++)i^=n.charCodeAt(s),i=Math.imul(i,16777619);return i>>>0}var gA=20000,mA=12000;function hA(n){return gA+Pn(n)%mA}function $a(n,i){let s=En(n);if(s===n)return`dashboard.${s}`;for(let o of i)if(o===s)return`dashboard.${s}`;return`dashboard.${n}`}function La(n,i){let s=[],o=n.infrastructure?.dns?.domain;if(o&&!n.cloud?.attachTo)s.push(o);if(i&&n.environments?.[i]?.domain)s.push(n.environments[i].domain);for(let c of Object.values(n.sites??{})){let l=c;if(!l||l.redirect)continue;let u=l.domain;if(typeof u==="string")s.push(u);else if(Array.isArray(u))s.push(...u.filter((h)=>typeof h==="string"))}return s.filter((c)=>c&&!c.startsWith("dashboard."))}function fA(n,i,s){if(s)return s;let o=La(n,i),c=o[0];if(!c)return null;return $a(c,o)}function AA(n,i,s){if(s)return[s];let o=La(n,i),c=[];for(let l of o){let u=$a(l,o);if(!c.includes(u))c.push(u)}return c}function Kt(n){return Object.entries(n.sites??{}).some(([i,s])=>{if(!s)return!1;let o=s.root??"";return qr(i)||o==="ui/dist"||o.endsWith("/ui/dist")||o.endsWith("/dist/ui")})}var vg="dashboard-";function Tg(n){return vg+n.replace(/^dashboard\./,"").replace(/\./g,"-")}function qr(n){return n==="dashboard"||n.startsWith(vg)}function Ni(n,i,s){if(Kt(n))return[];if(n.cloud?.attachTo)return[];let o=s.password?{auth:{username:s.username||"admin",password:s.password,realm:s.realm}}:{},c=s.build===!1||s.build===void 0?{}:{build:s.build};if(s.live!==!1){let l=fA(n,i,s.domain);if(!l)return[];let u=s.port??hA(l),h=n.infrastructure?.appDatabase??n.infrastructure?.compute?.database,y={root:s.uiRoot,deploy:"server",domain:l,preStart:["bun install --production --no-save"],start:`bun ${pA} --box --host 127.0.0.1 --port ${u}`,port:u,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...h?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:h.password}:{}},zeroDowntime:!1,sharedPaths:[uA],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Tg(l),site:y}]}return AA(n,i,s.domain).map((l)=>({name:Tg(l),site:{root:s.uiRoot,deploy:"server",type:"static",domain:l,ssl:{provider:"letsencrypt"},...c,...o}}))}function eS(n,i,s){return Ni(n,i,s)[0]??null}function Ht(n,i){let s={...n};for(let o in i){let c=i[o],l=s[o];if(c===void 0)continue;if(Array.isArray(c)&&Array.isArray(l))s[o]=[...l,...c];else if(typeof c==="object"&&c!==null&&!Array.isArray(c)&&typeof l==="object"&&l!==null&&!Array.isArray(l))s[o]=Ht(l,c);else s[o]=c}return s}function wg(n,i){return Ht(n,i)}function tS(...n){return n.reduce((i,s)=>Ht(i,s),{})}function rS(n,i){return(s)=>{let o=n(s);if(typeof i==="function")return wg(o,i(o,s));return wg(o,i)}}function Vr(n){return{infrastructure:n}}function nS(n){return Vr({monitoring:n})}function iS(n){return Vr({security:n})}function sS(n){return Vr({databases:n})}function oS(n){return Vr({cache:n})}function aS(n){return Vr({cdn:n})}function cS(n){return Vr({queues:n})}rt();function yA(){let n=process.env.AWS_ACCESS_KEY_ID,i=process.env.AWS_SECRET_ACCESS_KEY;if(!n||!i)return null;return{accessKeyId:n,secretAccessKey:i,sessionToken:process.env.AWS_SESSION_TOKEN}}function IA(n){let i=n?.profile||process.env.AWS_PROFILE||"default",s=n?.credentialsFile||xa(Oa(),".aws","credentials");if(!Ma(s))return null;try{let o=Qt(s,"utf-8");return In(o,i)}catch{return null}}function In(n,i){let s=n.split(`
2494
- `),o=null,c,l,u;for(let h of s){let y=h.trim();if(!y||y.startsWith("#")||y.startsWith(";"))continue;let f=y.match(/^\[([^\]]+)\]$/);if(f){if(o===i&&c&&l)return{accessKeyId:c,secretAccessKey:l,sessionToken:u};o=f[1],c=void 0,l=void 0,u=void 0;continue}if(o===i){let[b,...C]=y.split("="),T=C.join("=").trim();switch(b.trim().toLowerCase()){case"aws_access_key_id":c=T;break;case"aws_secret_access_key":l=T;break;case"aws_session_token":u=T;break}}}if(o===i&&c&&l)return{accessKeyId:c,secretAccessKey:l,sessionToken:u};return null}async function SA(n){let i=n?.timeout??1000,s="http://169.254.169.254";try{let o=await et("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},i);if(!o.ok)return null;let c=await o.text(),l=await et("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":c}},i);if(!l.ok)return null;let u=(await l.text()).trim(),h=await et(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${u}`,{headers:{"X-aws-ec2-metadata-token":c}},i);if(!h.ok)return null;let y=await h.json();return{accessKeyId:y.AccessKeyId,secretAccessKey:y.SecretAccessKey,sessionToken:y.Token,expiration:new Date(y.Expiration)}}catch{return null}}async function CA(n){let i=n?.timeout??1000,s=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,o=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,c=null;if(s)c=`http://169.254.170.2${s}`;else if(o)c=o;if(!c)return null;try{let l={},u=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(u)l.Authorization=u;let h=await et(c,{headers:l},i);if(!h.ok)return null;let y=await h.json();return{accessKeyId:y.AccessKeyId,secretAccessKey:y.SecretAccessKey,sessionToken:y.Token,expiration:new Date(y.Expiration)}}catch{return null}}async function EA(n){let i=n?.timeout??5000,s=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,o=process.env.AWS_ROLE_ARN,c=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!s||!o)return null;try{let l=Qt(s,"utf-8").trim(),u=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",h=u.startsWith("us-gov")?`https://sts.${u}.amazonaws.com`:u==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${u}.amazonaws.com`,y=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:o,RoleSessionName:c,WebIdentityToken:l}),f=await et(`${h}/?${y.toString()}`,{method:"POST"},i);if(!f.ok)return null;let b=await f.text(),C=Ze(b,"AccessKeyId"),T=Ze(b,"SecretAccessKey"),w=Ze(b,"SessionToken"),E=Ze(b,"Expiration");if(!C||!T)return null;return{accessKeyId:C,secretAccessKey:T,sessionToken:w??void 0,expiration:E?new Date(E):void 0}}catch{return null}}async function fo(n){let i=yA();if(i)return i;let s=IA(n);if(s)return s;let o=await EA(n);if(o)return o;let c=await CA(n);if(c)return c;let l=await SA(n);if(l)return l;throw Error("Could not find AWS credentials. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, or configure ~/.aws/credentials, or run on an EC2 instance with an IAM role.")}function dS(n){let i=null,s=null;return async()=>{if(i){if(!i.expiration)return i;let o=300000;if(i.expiration.getTime()-Date.now()>o)return i}if(s)return s;return s=fo(n).then((o)=>(i=o,s=null,o)).catch((o)=>{throw s=null,o}),s}}async function et(n,i,s){let o=new AbortController,c=setTimeout(()=>o.abort(),s);try{let l=await fetch(n,{...i,signal:o.signal});return clearTimeout(c),l}catch(l){throw clearTimeout(c),l}}function Ze(n,i){let s=new RegExp(`<${i}>([^<]+)</${i}>`),o=n.match(s);return o?o[1]:null}async function bA(n){return fo({profile:n})}function vA(n){let i=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(i)return i;let s=xa(Oa(),".aws","config");if(Ma(s))try{let o=Qt(s,"utf-8"),c=n||process.env.AWS_PROFILE||"default",l=c==="default"?"[default]":`[profile ${c}]`,u=o.split(`
2495
- `),h=!1;for(let y of u){let f=y.trim();if(f.startsWith("[")){h=f===l;continue}if(h&&f.startsWith("region")){let[,b]=f.split("=");if(b)return b.trim()}}}catch{}return"us-east-1"}async function TA(n){let i=n||await fo(),s=vA();await rt();let o=s.startsWith("us-gov")?`https://sts.${s}.amazonaws.com`:s==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${s}.amazonaws.com`,c="Action=GetCallerIdentity&Version=2011-06-15",l=O({method:"POST",url:o,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...i,service:"sts",region:s}),u=await fetch(l.url,{method:l.method,headers:l.headers,body:l.body});if(!u.ok)throw Error(`Failed to get account ID: ${await u.text()}`);let h=await u.text(),y=Ze(h,"Account");if(!y)throw Error("Failed to parse account ID from response");return y}await rt();await rt();var Rn=5242880,Dt=5242880,Nn=5242880;class Ba{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(n={}){this.region=n.region||process.env.AWS_REGION||"us-east-1",this.endpoint=n.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=n.forcePathStyle||!1,this.credentials=n.credentials,this.credentialOptions=n.credentialOptions,this.retryOptions=n.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return fo(this.credentialOptions)}buildUrl(n,i){let s=i?encodeURIComponent(i).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return i?`${this.endpoint}/${n}/${s}`:`${this.endpoint}/${n}`;let o=new URL(this.endpoint);return o.hostname=`${n}.${o.hostname}`,i?`${o.origin}/${s}`:o.origin}async get(n,i,s={}){let o=await this.getCredentials(),c=this.buildUrl(n,i),l={};if(s.range)l.Range=s.range;if(s.ifModifiedSince)l["If-Modified-Since"]=s.ifModifiedSince.toUTCString();if(s.ifMatch)l["If-Match"]=s.ifMatch;if(s.ifNoneMatch)l["If-None-Match"]=s.ifNoneMatch;let u=new URL(c);if(s.responseContentType)u.searchParams.set("response-content-type",s.responseContentType);if(s.responseContentDisposition)u.searchParams.set("response-content-disposition",s.responseContentDisposition);let h=O({method:"GET",url:u.toString(),headers:l,...o,service:"s3",region:this.region}),y=await fetch(h.url,{method:h.method,headers:h.headers});if(!y.ok&&y.status!==304){let f=await y.text();throw new V(`Failed to get object: ${f}`,y.status,n,i)}return y}async getText(n,i,s={}){return(await this.get(n,i,s)).text()}async getJSON(n,i,s={}){return(await this.get(n,i,s)).json()}async getBuffer(n,i,s={}){return(await this.get(n,i,s)).arrayBuffer()}async put(n,i,s,o={}){let c,l;if(typeof s==="string")c=new TextEncoder().encode(s).length,l=s;else if(s instanceof ArrayBuffer)c=s.byteLength,l=s;else if(s instanceof Uint8Array)c=s.byteLength,l=s;else if(s instanceof Blob)c=s.size,l=s;else return this.uploadMultipart(n,i,s,{...o,partSize:Dt});if(c>Nn){let u=$n(l).stream();return this.uploadMultipart(n,i,u,{...o,partSize:Dt})}return this.putSimple(n,i,l,c,o)}async putSimple(n,i,s,o,c){let l=await this.getCredentials(),u=this.buildUrl(n,i),h={"Content-Length":String(o),"Content-Type":c.contentType||ha(i)};if(c.contentEncoding)h["Content-Encoding"]=c.contentEncoding;if(c.cacheControl)h["Cache-Control"]=c.cacheControl;if(c.contentDisposition)h["Content-Disposition"]=c.contentDisposition;if(c.storageClass)h["x-amz-storage-class"]=c.storageClass;if(c.serverSideEncryption)h["x-amz-server-side-encryption"]=c.serverSideEncryption;if(c.acl)h["x-amz-acl"]=c.acl;if(c.tagging)h["x-amz-tagging"]=c.tagging;if(c.metadata)for(let[C,T]of Object.entries(c.metadata))h[`x-amz-meta-${C.toLowerCase()}`]=T;let y;if(typeof s==="string")y=s;else if(s instanceof Blob)y=await s.text();else y=new TextDecoder().decode(s instanceof ArrayBuffer?new Uint8Array(s):s);let f=O({method:"PUT",url:u,headers:h,body:y,...l,service:"s3",region:this.region}),b=await fetch(f.url,{method:f.method,headers:f.headers,body:s});if(!b.ok){let C=await b.text();throw new V(`Failed to put object: ${C}`,b.status,n,i)}return{etag:(b.headers.get("ETag")||"").replace(/"/g,"")}}async delete(n,i){let s=await this.getCredentials(),o=this.buildUrl(n,i),c=O({method:"DELETE",url:o,...s,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(!l.ok&&l.status!==204){let u=await l.text();throw new V(`Failed to delete object: ${u}`,l.status,n,i)}}async deleteMany(n,i){let s=await this.getCredentials(),o=`${this.buildUrl(n)}?delete`,c=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${i.map((w)=>`<Object><Key>${kn(w)}</Key></Object>`).join("")}</Delete>`,l=O({method:"POST",url:o,headers:{"Content-Type":"application/xml"},body:c,...s,service:"s3",region:this.region}),u=await fetch(l.url,{method:l.method,headers:l.headers,body:c});if(!u.ok){let w=await u.text();throw new V(`Failed to delete objects: ${w}`,u.status,n)}let h=await u.text(),y=[],f=[],b=/<Deleted><Key>([^<]+)<\/Key>/g,C;while((C=b.exec(h))!==null)y.push(C[1]);let T=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((C=T.exec(h))!==null)f.push({key:C[1],error:`${C[2]}: ${C[3]}`});return{deleted:y,errors:f}}async list(n,i={}){let s=await this.getCredentials(),o=new URL(this.buildUrl(n));if(o.searchParams.set("list-type","2"),i.prefix)o.searchParams.set("prefix",i.prefix);if(i.delimiter)o.searchParams.set("delimiter",i.delimiter);if(i.maxKeys)o.searchParams.set("max-keys",String(i.maxKeys));if(i.continuationToken)o.searchParams.set("continuation-token",i.continuationToken);if(i.startAfter)o.searchParams.set("start-after",i.startAfter);let c=O({method:"GET",url:o.toString(),...s,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(!l.ok){let h=await l.text();throw new V(`Failed to list objects: ${h}`,l.status,n)}let u=await l.text();return Dn(u)}async*listAll(n,i={}){let s;do{let o=await this.list(n,{...i,continuationToken:s});for(let c of o.contents)yield c;s=o.nextContinuationToken}while(s)}async head(n,i){let s=await this.getCredentials(),o=this.buildUrl(n,i),c=O({method:"HEAD",url:o,...s,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(l.status===404)return null;if(!l.ok){let h=await l.text();throw new V(`Failed to head object: ${h}`,l.status,n,i)}let u={};return l.headers.forEach((h,y)=>{if(y.toLowerCase().startsWith("x-amz-meta-"))u[y.slice(11)]=h}),{contentLength:Number(l.headers.get("Content-Length")||0),contentType:l.headers.get("Content-Type")||"application/octet-stream",etag:(l.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(l.headers.get("Last-Modified")||0),metadata:u,storageClass:l.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:l.headers.get("x-amz-server-side-encryption")||void 0}}async exists(n,i){return await this.head(n,i)!==null}async copy(n,i,s,o,c={}){let l=await this.getCredentials(),u=this.buildUrl(s,o),h={"x-amz-copy-source":`/${n}/${encodeURIComponent(i)}`};if(c.metadataDirective)h["x-amz-metadata-directive"]=c.metadataDirective;if(c.contentType)h["Content-Type"]=c.contentType;if(c.storageClass)h["x-amz-storage-class"]=c.storageClass;if(c.acl)h["x-amz-acl"]=c.acl;if(c.metadata)for(let[C,T]of Object.entries(c.metadata))h[`x-amz-meta-${C.toLowerCase()}`]=T;let y=O({method:"PUT",url:u,headers:h,...l,service:"s3",region:this.region}),f=await fetch(y.url,{method:y.method,headers:y.headers});if(!f.ok){let C=await f.text();throw new V(`Failed to copy object: ${C}`,f.status,s,o)}let b=(await f.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:b?b[1]:""}}async getPresignedUrl(n,i,s={}){let o=await this.getCredentials(),c=this.buildUrl(n,i);return nA({url:c,method:s.method||"GET",expiresIn:s.expiresIn||3600,...o,service:"s3",region:this.region})}async uploadMultipart(n,i,s,o={}){let c=await this.getCredentials(),l=Math.max(o.partSize||Dt,Rn),u,h;if(s instanceof ReadableStream)u=s;else if(s instanceof Blob)u=s.stream(),h=s.size;else{let b=new Blob([s]);u=b.stream(),h=b.size}let{uploadId:y,baseUrl:f}=await this.initiateMultipartUpload(n,i,o);try{let b=await this.uploadParts(n,i,f,y,u,l,c,h,o.concurrency||4,o.onProgress);return await this.completeMultipartUpload(n,i,f,y,b)}catch(b){throw await this.abortMultipartUpload(n,i,y,f).catch(()=>{}),b}}async initiateMultipartUpload(n,i,s){let o=await this.getCredentials(),c=this.buildUrl(n,i),l=`${c}?uploads`,u={"Content-Type":s.contentType||ha(i)};if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.serverSideEncryption)u["x-amz-server-side-encryption"]=s.serverSideEncryption;if(s.acl)u["x-amz-acl"]=s.acl;if(s.metadata)for(let[C,T]of Object.entries(s.metadata))u[`x-amz-meta-${C.toLowerCase()}`]=T;let h=O({method:"POST",url:l,headers:u,...o,service:"s3",region:this.region}),y=await fetch(h.url,{method:h.method,headers:h.headers});if(!y.ok){let C=await y.text();throw new V(`Failed to initiate multipart upload: ${C}`,y.status,n,i)}let f=(await y.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!f)throw new V("Failed to parse upload ID from response",0,n,i);let b=c;if(y.url)try{let C=new URL(y.url);C.search="",b=C.toString()}catch{}return{uploadId:f[1],baseUrl:b}}async uploadParts(n,i,s,o,c,l,u,h,y,f){let b=[],C=c.getReader(),T=1,w=new Uint8Array(0),E=0,I=h?Math.ceil(h/l):void 0,N=new Map,D=async(R,_)=>{let B=`${s}?partNumber=${_}&uploadId=${encodeURIComponent(o)}`,W={"Content-Length":String(R.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},J=O({method:"PUT",url:B,headers:W,...u,service:"s3",region:this.region}),K=await fetch(J.url,{method:J.method,headers:J.headers,body:R,redirect:"error"});if(!K.ok){let Z=await K.text();throw new V(`Failed to upload part ${_}: ${Z}`,K.status,n,i)}let Y=(K.headers.get("ETag")||"").replace(/"/g,"");if(!Y)throw new V(`Missing ETag for part ${_}`,K.status,n,i);return{partNumber:_,etag:Y}},x=async()=>{let R=await Promise.race(N.values());N.delete(R.partNumber),b.push(R)};while(!0){let{done:R,value:_}=await C.read();if(_){let B=new Uint8Array(w.length+_.length);B.set(w),B.set(_,w.length),w=B}while(w.length>=l||R&&w.length>0){let B=w.slice(0,l);w=w.slice(l);let W=T++;if(N.size>=y)await x();if(N.set(W,D(B,W)),E+=B.byteLength,f)f({loaded:E,total:h||E,part:W,totalParts:I||W})}if(R)break}while(N.size>0)await x();return b.sort((R,_)=>R.partNumber-_.partNumber),b}async completeMultipartUpload(n,i,s,o,c){let l=await this.getCredentials(),u=`${s}?uploadId=${encodeURIComponent(o)}`,h=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${c.map((C)=>`<Part><PartNumber>${C.partNumber}</PartNumber><ETag>"${C.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,y=O({method:"POST",url:u,headers:{"Content-Type":"application/xml"},body:h,...l,service:"s3",region:this.region}),f=await fetch(y.url,{method:y.method,headers:y.headers,body:h});if(!f.ok){let C=await f.text();throw new V(`Failed to complete multipart upload: ${C}`,f.status,n,i)}let b=(await f.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:b?b[1]:""}}async abortMultipartUpload(n,i,s,o){let c=await this.getCredentials(),l=`${o??this.buildUrl(n,i)}?uploadId=${encodeURIComponent(s)}`,u=O({method:"DELETE",url:l,...c,service:"s3",region:this.region});await fetch(u.url,{method:u.method,headers:u.headers})}async emptyAndDeleteBucket(n){let i=[];for await(let l of this.listAll(n,{}))if(i.push(l.key),i.length>=1000)await this.deleteMany(n,i),i=[];if(i.length>0)await this.deleteMany(n,i);let s=await this.getCredentials(),o=this.buildUrl(n),c=O({method:"DELETE",url:o,...s,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}}class V extends Error{statusCode;bucket;key;constructor(n,i,s,o){super(n);this.statusCode=i,this.bucket=s,this.key=o,this.name="S3Error"}}function Dn(n){let i=[],s=[],o=/<Contents>([\s\S]*?)<\/Contents>/g,c;while((c=o.exec(n))!==null){let u=c[1];i.push({key:ce(u,"Key")||"",lastModified:new Date(ce(u,"LastModified")||0),etag:(ce(u,"ETag")||"").replace(/"/g,""),size:Number(ce(u,"Size")||0),storageClass:ce(u,"StorageClass")||"STANDARD"})}let l=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((c=l.exec(n))!==null)s.push(c[1]);return{contents:i,commonPrefixes:s,isTruncated:ce(n,"IsTruncated")==="true",continuationToken:ce(n,"ContinuationToken")||void 0,nextContinuationToken:ce(n,"NextContinuationToken")||void 0,keyCount:Number(ce(n,"KeyCount")||0),maxKeys:Number(ce(n,"MaxKeys")||1000),prefix:ce(n,"Prefix")||void 0,delimiter:ce(n,"Delimiter")||void 0}}function ce(n,i){let s=new RegExp(`<${i}>([^<]*)</${i}>`),o=n.match(s);return o?o[1]:null}function kn(n){return n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function ha(n){let i=n.split(".").pop()?.toLowerCase();return{html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",mjs:"application/javascript",json:"application/json",xml:"application/xml",txt:"text/plain",md:"text/markdown",csv:"text/csv",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",ico:"image/x-icon",avif:"image/avif",mp4:"video/mp4",webm:"video/webm",mov:"video/quicktime",avi:"video/x-msvideo",mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar",rar:"application/vnd.rar","7z":"application/x-7z-compressed",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",eot:"application/vnd.ms-fontobject",wasm:"application/wasm"}[i||""]||"application/octet-stream"}function $n(n){if(n instanceof Blob)return n;if(typeof n==="string")return new Blob([n],{type:"text/plain"});return new Blob([n])}function lS(n){return new Ba(n)}await rt();class We extends Error{code;solution;details;constructor(n,i,s,o){super(n);this.code=i,this.solution=s,this.details=o,this.name="CloudError",Error.captureStackTrace?.(this,We)}toString(){let n=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)n+=`
2493
+ `}},storage:{uploads:{type:"efs",performanceMode:"generalPurpose",throughputMode:"bursting",encrypted:!0,lifecyclePolicy:{transitionToIA:30}},backups:{public:!1,versioning:!0,encryption:!0,lifecycleRules:[{id:"ArchiveOldBackups",enabled:!0,transitions:[{days:90,storageClass:"GLACIER"}]}]},static:{public:!0,versioning:!1,encryption:!1,cors:[{allowedOrigins:[o||"*"],allowedMethods:["GET","HEAD"]}]}},cdn:{enabled:!0,origins:[{originId:"static-assets",domainName:`${s}-static.s3.amazonaws.com`,pathPattern:"/static/*"}],customDomain:o?{domain:o,certificateArn:"TO_BE_GENERATED"}:void 0,cachePolicy:{minTTL:0,defaultTTL:86400,maxTTL:31536000},compress:!0,http3:!0},databases:h==="mysql"?{mysql:{engine:"mysql",version:"8.0",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",innodb_buffer_pool_size:"{DBInstanceClassMemory*3/4}",slow_query_log:"1",long_query_time:"2"}}}:{postgres:{engine:"postgres",version:"15",instanceClass:"db.t3.medium",allocatedStorage:100,maxAllocatedStorage:500,multiAZ:!0,backupRetentionDays:14,preferredBackupWindow:"03:00-04:00",preferredMaintenanceWindow:"sun:04:00-sun:05:00",enablePerformanceInsights:!0,performanceInsightsRetention:7,deletionProtection:!0,parameters:{max_connections:"500",shared_buffers:"{DBInstanceClassMemory/4}",log_min_duration_statement:"2000"}}},cache:y==="redis"?{redis:{nodeType:"cache.t3.medium",numCacheNodes:2,engine:"redis",engineVersion:"7.0",port:6379,parameterGroup:{maxmemoryPolicy:"allkeys-lru",timeout:"300"},snapshotRetentionLimit:5,snapshotWindow:"03:00-05:00",automaticFailoverEnabled:!0}}:void 0,queues:{jobs:{fifo:!1,visibilityTimeout:900,messageRetentionPeriod:345600,receiveMessageWaitTime:20,deadLetterQueue:!0,maxReceiveCount:3},emails:{fifo:!1,visibilityTimeout:300,messageRetentionPeriod:86400,deadLetterQueue:!0}},functions:{"job-worker":{runtime:"nodejs20.x",handler:"dist/workers/jobs.handler",memory:2048,timeout:900,events:[{type:"sqs",queueName:`${s}-jobs`,batchSize:10}]},"email-sender":{runtime:"nodejs20.x",handler:"dist/workers/email.handler",memory:512,timeout:60,events:[{type:"sqs",queueName:`${s}-emails`,batchSize:10}]},cleanup:{runtime:"nodejs20.x",handler:"dist/tasks/cleanup.handler",memory:512,timeout:300,events:[{type:"schedule",expression:"cron(0 2 * * ? *)"}]}},monitoring:{dashboard:{name:`${s}-web-app`,widgets:[{type:"metric",metrics:["EC2CPUUtilization","ALBRequestCount","ALBTargetResponseTime","RDSCPUUtilization","RDSDatabaseConnections","RDSReadLatency","RDSWriteLatency"]}]},alarms:[{metric:"EC2CPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSCPUUtilization",threshold:80,evaluationPeriods:2},{metric:"RDSDatabaseConnections",threshold:400,evaluationPeriods:1},{metric:"ALBTargetResponseTime",threshold:2000,evaluationPeriods:2},{metric:"ALBUnhealthyHostCount",threshold:1,evaluationPeriods:1}],logs:{retention:14,groups:[`${s}-app`,`${s}-nginx`,`${s}-workers`]}},security:{certificate:o?{domain:o,validationMethod:"DNS"}:void 0,waf:{enabled:!0,rules:["rateLimit","sqlInjection","xss","knownBadInputs"]},securityGroups:{alb:{ingress:[{port:80,protocol:"tcp",cidr:"0.0.0.0/0"},{port:443,protocol:"tcp",cidr:"0.0.0.0/0"}]},app:{ingress:[{port:3000,protocol:"tcp",source:"alb-sg"}]},database:{ingress:[{port:h==="mysql"?3306:5432,protocol:"tcp",source:"app-sg"}]},...y==="redis"&&{cache:{ingress:[{port:6379,protocol:"tcp",source:"app-sg"}]}}}}}}}function XI(n){let{name:i,slug:s,domain:o,repository:c,phpVersion:l="8.3",size:u="small",database:h=s.replace(/-/g,"_"),databasePassword:y,sslEmail:f,deployStrategy:S="push",provider:b="hetzner"}=n;return{project:{name:i,slug:s,region:"us-east-1"},mode:"server",cloud:{provider:b},environments:{production:{type:"production",domain:o}},infrastructure:{compute:{mode:"server",size:u,runtime:"php",webServer:"nginx",php:{versions:[l],default:l},managedServices:{mysql:!0,redis:!0},firewall:{enabled:!0},autoUpdates:!0,monitoring:!0,backups:{enabled:!0,schedule:"0 2 * * *",retentionCount:7}},appDatabase:{engine:"mysql",name:h,username:h,password:y}},sites:{main:{root:".",type:"laravel",domain:o,phpVersion:l,repository:{...c,strategy:S},scheduler:!0,queues:[{connection:"redis",queue:"default",processes:1}],ssl:{provider:"letsencrypt",email:f}}}}}function YI(n){let{name:i,slug:s,domain:o,layers:c,phpVersion:l="8.3",architecture:u="x86_64",memory:h=1024,build:y,deploy:f=["migrate --force"],cache:S="dynamodb",scheduler:b="on",region:v="us-east-1"}=n;return{project:{name:i,slug:s,region:v},mode:"serverless",environments:{production:{type:"production",domain:o,app:{kind:"php",runtime:"provided.al2023",phpVersion:l,architecture:u,layers:c,memory:h,build:y,deploy:f,assets:"public",queues:!0,scheduler:b,cache:{driver:S},domain:o}}}}}function ZI(n){return{root:n.root??"packages/ui/dist",deploy:"server",type:"static",domain:n.domain,build:n.build??"cd packages/ui && bun install && bun run build",ssl:{provider:"letsencrypt"},auth:{username:n.username??"admin",password:n.password}}}var uA=lg,pA="./node_modules/@stacksjs/ts-cloud/dist/bin/dashboard-server.js";function En(n){let i=n.split(".").filter(Boolean);return i.length<=2?n:i.slice(-2).join(".")}function Pn(n){let i=2166136261;for(let s=0;s<n.length;s++)i^=n.charCodeAt(s),i=Math.imul(i,16777619);return i>>>0}var gA=20000,mA=12000;function hA(n){return gA+Pn(n)%mA}function $a(n,i){let s=En(n);if(s===n)return`dashboard.${s}`;for(let o of i)if(o===s)return`dashboard.${s}`;return`dashboard.${n}`}function La(n,i){let s=[],o=n.infrastructure?.dns?.domain;if(o&&!n.cloud?.attachTo)s.push(o);if(i&&n.environments?.[i]?.domain)s.push(n.environments[i].domain);for(let c of Object.values(n.sites??{})){let l=c;if(!l||l.redirect)continue;let u=l.domain;if(typeof u==="string")s.push(u);else if(Array.isArray(u))s.push(...u.filter((h)=>typeof h==="string"))}return s.filter((c)=>c&&!c.startsWith("dashboard."))}function fA(n,i,s){if(s)return s;let o=La(n,i),c=o[0];if(!c)return null;return $a(c,o)}function AA(n,i,s){if(s)return[s];let o=La(n,i),c=[];for(let l of o){let u=$a(l,o);if(!c.includes(u))c.push(u)}return c}function Kt(n){return Object.entries(n.sites??{}).some(([i,s])=>{if(!s)return!1;let o=s.root??"";return qr(i)||o==="ui/dist"||o.endsWith("/ui/dist")||o.endsWith("/dist/ui")})}var vg="dashboard-";function Tg(n){return vg+n.replace(/^dashboard\./,"").replace(/\./g,"-")}function qr(n){return n==="dashboard"||n.startsWith(vg)}function Ni(n,i,s){if(Kt(n))return[];if(n.cloud?.attachTo)return[];let o=s.password?{auth:{username:s.username||"admin",password:s.password,realm:s.realm}}:{},c=s.build===!1||s.build===void 0?{}:{build:s.build};if(s.live!==!1){let l=fA(n,i,s.domain);if(!l)return[];let u=s.port??hA(l),h=n.infrastructure?.appDatabase??n.infrastructure?.compute?.database,y={root:s.uiRoot,deploy:"server",domain:l,preStart:["bun install --production --no-save"],start:`bun ${pA} --box --host 127.0.0.1 --port ${u}`,port:u,cpuWeight:10,ioWeight:10,tasksMax:128,env:{APP_ENV:"production",NODE_ENV:"production",TS_CLOUD_DASHBOARD_TELEMETRY:"1",...h?.password?{TS_CLOUD_DASHBOARD_DB_PASSWORD:h.password}:{}},zeroDowntime:!1,sharedPaths:[uA],healthCheck:{path:"/login"},ssl:{provider:"letsencrypt"}};return[{name:Tg(l),site:y}]}return AA(n,i,s.domain).map((l)=>({name:Tg(l),site:{root:s.uiRoot,deploy:"server",type:"static",domain:l,ssl:{provider:"letsencrypt"},...c,...o}}))}function eS(n,i,s){return Ni(n,i,s)[0]??null}function Ht(n,i){let s={...n};for(let o in i){let c=i[o],l=s[o];if(c===void 0)continue;if(Array.isArray(c)&&Array.isArray(l))s[o]=[...l,...c];else if(typeof c==="object"&&c!==null&&!Array.isArray(c)&&typeof l==="object"&&l!==null&&!Array.isArray(l))s[o]=Ht(l,c);else s[o]=c}return s}function wg(n,i){return Ht(n,i)}function tS(...n){return n.reduce((i,s)=>Ht(i,s),{})}function rS(n,i){return(s)=>{let o=n(s);if(typeof i==="function")return wg(o,i(o,s));return wg(o,i)}}function Vr(n){return{infrastructure:n}}function nS(n){return Vr({monitoring:n})}function iS(n){return Vr({security:n})}function sS(n){return Vr({databases:n})}function oS(n){return Vr({cache:n})}function aS(n){return Vr({cdn:n})}function cS(n){return Vr({queues:n})}rt();function yA(){let n=process.env.AWS_ACCESS_KEY_ID,i=process.env.AWS_SECRET_ACCESS_KEY;if(!n||!i)return null;return{accessKeyId:n,secretAccessKey:i,sessionToken:process.env.AWS_SESSION_TOKEN}}function IA(n){let i=n?.profile||process.env.AWS_PROFILE||"default",s=n?.credentialsFile||xa(Oa(),".aws","credentials");if(!Ma(s))return null;try{let o=Qt(s,"utf-8");return In(o,i)}catch{return null}}function In(n,i){let s=n.split(`
2494
+ `),o=null,c,l,u;for(let h of s){let y=h.trim();if(!y||y.startsWith("#")||y.startsWith(";"))continue;let f=y.match(/^\[([^\]]+)\]$/);if(f){if(o===i&&c&&l)return{accessKeyId:c,secretAccessKey:l,sessionToken:u};o=f[1],c=void 0,l=void 0,u=void 0;continue}if(o===i){let[S,...b]=y.split("="),v=b.join("=").trim();switch(S.trim().toLowerCase()){case"aws_access_key_id":c=v;break;case"aws_secret_access_key":l=v;break;case"aws_session_token":u=v;break}}}if(o===i&&c&&l)return{accessKeyId:c,secretAccessKey:l,sessionToken:u};return null}async function SA(n){let i=n?.timeout??1000,s="http://169.254.169.254";try{let o=await et("http://169.254.169.254/latest/api/token",{method:"PUT",headers:{"X-aws-ec2-metadata-token-ttl-seconds":"21600"}},i);if(!o.ok)return null;let c=await o.text(),l=await et("http://169.254.169.254/latest/meta-data/iam/security-credentials/",{headers:{"X-aws-ec2-metadata-token":c}},i);if(!l.ok)return null;let u=(await l.text()).trim(),h=await et(`http://169.254.169.254/latest/meta-data/iam/security-credentials/${u}`,{headers:{"X-aws-ec2-metadata-token":c}},i);if(!h.ok)return null;let y=await h.json();return{accessKeyId:y.AccessKeyId,secretAccessKey:y.SecretAccessKey,sessionToken:y.Token,expiration:new Date(y.Expiration)}}catch{return null}}async function CA(n){let i=n?.timeout??1000,s=process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI,o=process.env.AWS_CONTAINER_CREDENTIALS_FULL_URI,c=null;if(s)c=`http://169.254.170.2${s}`;else if(o)c=o;if(!c)return null;try{let l={},u=process.env.AWS_CONTAINER_AUTHORIZATION_TOKEN;if(u)l.Authorization=u;let h=await et(c,{headers:l},i);if(!h.ok)return null;let y=await h.json();return{accessKeyId:y.AccessKeyId,secretAccessKey:y.SecretAccessKey,sessionToken:y.Token,expiration:new Date(y.Expiration)}}catch{return null}}async function EA(n){let i=n?.timeout??5000,s=process.env.AWS_WEB_IDENTITY_TOKEN_FILE,o=process.env.AWS_ROLE_ARN,c=process.env.AWS_ROLE_SESSION_NAME||"ts-cloud-session";if(!s||!o)return null;try{let l=Qt(s,"utf-8").trim(),u=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION||"us-east-1",h=u.startsWith("us-gov")?`https://sts.${u}.amazonaws.com`:u==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${u}.amazonaws.com`,y=new URLSearchParams({Action:"AssumeRoleWithWebIdentity",Version:"2011-06-15",RoleArn:o,RoleSessionName:c,WebIdentityToken:l}),f=await et(`${h}/?${y.toString()}`,{method:"POST"},i);if(!f.ok)return null;let S=await f.text(),b=Ze(S,"AccessKeyId"),v=Ze(S,"SecretAccessKey"),w=Ze(S,"SessionToken"),E=Ze(S,"Expiration");if(!b||!v)return null;return{accessKeyId:b,secretAccessKey:v,sessionToken:w??void 0,expiration:E?new Date(E):void 0}}catch{return null}}async function fo(n){let i=yA();if(i)return i;let s=IA(n);if(s)return s;let o=await EA(n);if(o)return o;let c=await CA(n);if(c)return c;let l=await SA(n);if(l)return l;throw Error("Could not find AWS credentials. Set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables, or configure ~/.aws/credentials, or run on an EC2 instance with an IAM role.")}function dS(n){let i=null,s=null;return async()=>{if(i){if(!i.expiration)return i;let o=300000;if(i.expiration.getTime()-Date.now()>o)return i}if(s)return s;return s=fo(n).then((o)=>(i=o,s=null,o)).catch((o)=>{throw s=null,o}),s}}async function et(n,i,s){let o=new AbortController,c=setTimeout(()=>o.abort(),s);try{let l=await fetch(n,{...i,signal:o.signal});return clearTimeout(c),l}catch(l){throw clearTimeout(c),l}}function Ze(n,i){let s=new RegExp(`<${i}>([^<]+)</${i}>`),o=n.match(s);return o?o[1]:null}async function bA(n){return fo({profile:n})}function vA(n){let i=process.env.AWS_REGION||process.env.AWS_DEFAULT_REGION;if(i)return i;let s=xa(Oa(),".aws","config");if(Ma(s))try{let o=Qt(s,"utf-8"),c=n||process.env.AWS_PROFILE||"default",l=c==="default"?"[default]":`[profile ${c}]`,u=o.split(`
2495
+ `),h=!1;for(let y of u){let f=y.trim();if(f.startsWith("[")){h=f===l;continue}if(h&&f.startsWith("region")){let[,S]=f.split("=");if(S)return S.trim()}}}catch{}return"us-east-1"}async function TA(n){let i=n||await fo(),s=vA();await rt();let o=s.startsWith("us-gov")?`https://sts.${s}.amazonaws.com`:s==="us-east-1"?"https://sts.amazonaws.com":`https://sts.${s}.amazonaws.com`,c="Action=GetCallerIdentity&Version=2011-06-15",l=O({method:"POST",url:o,body:"Action=GetCallerIdentity&Version=2011-06-15",headers:{"Content-Type":"application/x-www-form-urlencoded"},...i,service:"sts",region:s}),u=await fetch(l.url,{method:l.method,headers:l.headers,body:l.body});if(!u.ok)throw Error(`Failed to get account ID: ${await u.text()}`);let h=await u.text(),y=Ze(h,"Account");if(!y)throw Error("Failed to parse account ID from response");return y}await rt();await rt();var Rn=5242880,Dt=5242880,Nn=5242880;class Ba{region;endpoint;forcePathStyle;credentials;credentialOptions;retryOptions;constructor(n={}){this.region=n.region||process.env.AWS_REGION||"us-east-1",this.endpoint=n.endpoint||`https://s3.${this.region}.amazonaws.com`,this.forcePathStyle=n.forcePathStyle||!1,this.credentials=n.credentials,this.credentialOptions=n.credentialOptions,this.retryOptions=n.retryOptions||{}}async getCredentials(){if(this.credentials)return this.credentials;return fo(this.credentialOptions)}buildUrl(n,i){let s=i?encodeURIComponent(i).replace(/%2F/g,"/"):"";if(this.forcePathStyle)return i?`${this.endpoint}/${n}/${s}`:`${this.endpoint}/${n}`;let o=new URL(this.endpoint);return o.hostname=`${n}.${o.hostname}`,i?`${o.origin}/${s}`:o.origin}async get(n,i,s={}){let o=await this.getCredentials(),c=this.buildUrl(n,i),l={};if(s.range)l.Range=s.range;if(s.ifModifiedSince)l["If-Modified-Since"]=s.ifModifiedSince.toUTCString();if(s.ifMatch)l["If-Match"]=s.ifMatch;if(s.ifNoneMatch)l["If-None-Match"]=s.ifNoneMatch;let u=new URL(c);if(s.responseContentType)u.searchParams.set("response-content-type",s.responseContentType);if(s.responseContentDisposition)u.searchParams.set("response-content-disposition",s.responseContentDisposition);let h=O({method:"GET",url:u.toString(),headers:l,...o,service:"s3",region:this.region}),y=await fetch(h.url,{method:h.method,headers:h.headers});if(!y.ok&&y.status!==304){let f=await y.text();throw new V(`Failed to get object: ${f}`,y.status,n,i)}return y}async getText(n,i,s={}){return(await this.get(n,i,s)).text()}async getJSON(n,i,s={}){return(await this.get(n,i,s)).json()}async getBuffer(n,i,s={}){return(await this.get(n,i,s)).arrayBuffer()}async put(n,i,s,o={}){let c,l;if(typeof s==="string")c=new TextEncoder().encode(s).length,l=s;else if(s instanceof ArrayBuffer)c=s.byteLength,l=s;else if(s instanceof Uint8Array)c=s.byteLength,l=s;else if(s instanceof Blob)c=s.size,l=s;else return this.uploadMultipart(n,i,s,{...o,partSize:Dt});if(c>Nn){let u=$n(l).stream();return this.uploadMultipart(n,i,u,{...o,partSize:Dt})}return this.putSimple(n,i,l,c,o)}async putSimple(n,i,s,o,c){let l=await this.getCredentials(),u=this.buildUrl(n,i),h={"Content-Length":String(o),"Content-Type":c.contentType||ha(i)};if(c.contentEncoding)h["Content-Encoding"]=c.contentEncoding;if(c.cacheControl)h["Cache-Control"]=c.cacheControl;if(c.contentDisposition)h["Content-Disposition"]=c.contentDisposition;if(c.storageClass)h["x-amz-storage-class"]=c.storageClass;if(c.serverSideEncryption)h["x-amz-server-side-encryption"]=c.serverSideEncryption;if(c.acl)h["x-amz-acl"]=c.acl;if(c.tagging)h["x-amz-tagging"]=c.tagging;if(c.metadata)for(let[b,v]of Object.entries(c.metadata))h[`x-amz-meta-${b.toLowerCase()}`]=v;let y;if(typeof s==="string")y=s;else if(s instanceof Blob)y=await s.text();else y=new TextDecoder().decode(s instanceof ArrayBuffer?new Uint8Array(s):s);let f=O({method:"PUT",url:u,headers:h,body:y,...l,service:"s3",region:this.region}),S=await fetch(f.url,{method:f.method,headers:f.headers,body:s});if(!S.ok){let b=await S.text();throw new V(`Failed to put object: ${b}`,S.status,n,i)}return{etag:(S.headers.get("ETag")||"").replace(/"/g,"")}}async delete(n,i){let s=await this.getCredentials(),o=this.buildUrl(n,i),c=O({method:"DELETE",url:o,...s,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(!l.ok&&l.status!==204){let u=await l.text();throw new V(`Failed to delete object: ${u}`,l.status,n,i)}}async deleteMany(n,i){let s=await this.getCredentials(),o=`${this.buildUrl(n)}?delete`,c=`<?xml version="1.0" encoding="UTF-8"?><Delete><Quiet>false</Quiet>${i.map((w)=>`<Object><Key>${kn(w)}</Key></Object>`).join("")}</Delete>`,l=O({method:"POST",url:o,headers:{"Content-Type":"application/xml"},body:c,...s,service:"s3",region:this.region}),u=await fetch(l.url,{method:l.method,headers:l.headers,body:c});if(!u.ok){let w=await u.text();throw new V(`Failed to delete objects: ${w}`,u.status,n)}let h=await u.text(),y=[],f=[],S=/<Deleted><Key>([^<]+)<\/Key>/g,b;while((b=S.exec(h))!==null)y.push(b[1]);let v=/<Error><Key>([^<]+)<\/Key><Code>([^<]+)<\/Code><Message>([^<]+)<\/Message>/g;while((b=v.exec(h))!==null)f.push({key:b[1],error:`${b[2]}: ${b[3]}`});return{deleted:y,errors:f}}async list(n,i={}){let s=await this.getCredentials(),o=new URL(this.buildUrl(n));if(o.searchParams.set("list-type","2"),i.prefix)o.searchParams.set("prefix",i.prefix);if(i.delimiter)o.searchParams.set("delimiter",i.delimiter);if(i.maxKeys)o.searchParams.set("max-keys",String(i.maxKeys));if(i.continuationToken)o.searchParams.set("continuation-token",i.continuationToken);if(i.startAfter)o.searchParams.set("start-after",i.startAfter);let c=O({method:"GET",url:o.toString(),...s,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(!l.ok){let h=await l.text();throw new V(`Failed to list objects: ${h}`,l.status,n)}let u=await l.text();return Dn(u)}async*listAll(n,i={}){let s;do{let o=await this.list(n,{...i,continuationToken:s});for(let c of o.contents)yield c;s=o.nextContinuationToken}while(s)}async head(n,i){let s=await this.getCredentials(),o=this.buildUrl(n,i),c=O({method:"HEAD",url:o,...s,service:"s3",region:this.region}),l=await fetch(c.url,{method:c.method,headers:c.headers});if(l.status===404)return null;if(!l.ok){let h=await l.text();throw new V(`Failed to head object: ${h}`,l.status,n,i)}let u={};return l.headers.forEach((h,y)=>{if(y.toLowerCase().startsWith("x-amz-meta-"))u[y.slice(11)]=h}),{contentLength:Number(l.headers.get("Content-Length")||0),contentType:l.headers.get("Content-Type")||"application/octet-stream",etag:(l.headers.get("ETag")||"").replace(/"/g,""),lastModified:new Date(l.headers.get("Last-Modified")||0),metadata:u,storageClass:l.headers.get("x-amz-storage-class")||void 0,serverSideEncryption:l.headers.get("x-amz-server-side-encryption")||void 0}}async exists(n,i){return await this.head(n,i)!==null}async copy(n,i,s,o,c={}){let l=await this.getCredentials(),u=this.buildUrl(s,o),h={"x-amz-copy-source":`/${n}/${encodeURIComponent(i)}`};if(c.metadataDirective)h["x-amz-metadata-directive"]=c.metadataDirective;if(c.contentType)h["Content-Type"]=c.contentType;if(c.storageClass)h["x-amz-storage-class"]=c.storageClass;if(c.acl)h["x-amz-acl"]=c.acl;if(c.metadata)for(let[b,v]of Object.entries(c.metadata))h[`x-amz-meta-${b.toLowerCase()}`]=v;let y=O({method:"PUT",url:u,headers:h,...l,service:"s3",region:this.region}),f=await fetch(y.url,{method:y.method,headers:y.headers});if(!f.ok){let b=await f.text();throw new V(`Failed to copy object: ${b}`,f.status,s,o)}let S=(await f.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:S?S[1]:""}}async getPresignedUrl(n,i,s={}){let o=await this.getCredentials(),c=this.buildUrl(n,i);return nA({url:c,method:s.method||"GET",expiresIn:s.expiresIn||3600,...o,service:"s3",region:this.region})}async uploadMultipart(n,i,s,o={}){let c=await this.getCredentials(),l=Math.max(o.partSize||Dt,Rn),u,h;if(s instanceof ReadableStream)u=s;else if(s instanceof Blob)u=s.stream(),h=s.size;else{let S=new Blob([s]);u=S.stream(),h=S.size}let{uploadId:y,baseUrl:f}=await this.initiateMultipartUpload(n,i,o);try{let S=await this.uploadParts(n,i,f,y,u,l,c,h,o.concurrency||4,o.onProgress);return await this.completeMultipartUpload(n,i,f,y,S)}catch(S){throw await this.abortMultipartUpload(n,i,y,f).catch(()=>{}),S}}async initiateMultipartUpload(n,i,s){let o=await this.getCredentials(),c=this.buildUrl(n,i),l=`${c}?uploads`,u={"Content-Type":s.contentType||ha(i)};if(s.storageClass)u["x-amz-storage-class"]=s.storageClass;if(s.serverSideEncryption)u["x-amz-server-side-encryption"]=s.serverSideEncryption;if(s.acl)u["x-amz-acl"]=s.acl;if(s.metadata)for(let[b,v]of Object.entries(s.metadata))u[`x-amz-meta-${b.toLowerCase()}`]=v;let h=O({method:"POST",url:l,headers:u,...o,service:"s3",region:this.region}),y=await fetch(h.url,{method:h.method,headers:h.headers});if(!y.ok){let b=await y.text();throw new V(`Failed to initiate multipart upload: ${b}`,y.status,n,i)}let f=(await y.text()).match(/<UploadId>([^<]+)<\/UploadId>/);if(!f)throw new V("Failed to parse upload ID from response",0,n,i);let S=c;if(y.url)try{let b=new URL(y.url);b.search="",S=b.toString()}catch{}return{uploadId:f[1],baseUrl:S}}async uploadParts(n,i,s,o,c,l,u,h,y,f){let S=[],b=c.getReader(),v=1,w=new Uint8Array(0),E=0,P=h?Math.ceil(h/l):void 0,R=new Map,D=async(I,_)=>{let B=`${s}?partNumber=${_}&uploadId=${encodeURIComponent(o)}`,W={"Content-Length":String(I.byteLength),"x-amz-content-sha256":"UNSIGNED-PAYLOAD"},J=O({method:"PUT",url:B,headers:W,...u,service:"s3",region:this.region}),K=await fetch(J.url,{method:J.method,headers:J.headers,body:I,redirect:"error"});if(!K.ok){let Z=await K.text();throw new V(`Failed to upload part ${_}: ${Z}`,K.status,n,i)}let Y=(K.headers.get("ETag")||"").replace(/"/g,"");if(!Y)throw new V(`Missing ETag for part ${_}`,K.status,n,i);return{partNumber:_,etag:Y}},x=async()=>{let I=await Promise.race(R.values());R.delete(I.partNumber),S.push(I)};while(!0){let{done:I,value:_}=await b.read();if(_){let B=new Uint8Array(w.length+_.length);B.set(w),B.set(_,w.length),w=B}while(w.length>=l||I&&w.length>0){let B=w.slice(0,l);w=w.slice(l);let W=v++;if(R.size>=y)await x();if(R.set(W,D(B,W)),E+=B.byteLength,f)f({loaded:E,total:h||E,part:W,totalParts:P||W})}if(I)break}while(R.size>0)await x();return S.sort((I,_)=>I.partNumber-_.partNumber),S}async completeMultipartUpload(n,i,s,o,c){let l=await this.getCredentials(),u=`${s}?uploadId=${encodeURIComponent(o)}`,h=`<?xml version="1.0" encoding="UTF-8"?><CompleteMultipartUpload>${c.map((b)=>`<Part><PartNumber>${b.partNumber}</PartNumber><ETag>"${b.etag}"</ETag></Part>`).join("")}</CompleteMultipartUpload>`,y=O({method:"POST",url:u,headers:{"Content-Type":"application/xml"},body:h,...l,service:"s3",region:this.region}),f=await fetch(y.url,{method:y.method,headers:y.headers,body:h});if(!f.ok){let b=await f.text();throw new V(`Failed to complete multipart upload: ${b}`,f.status,n,i)}let S=(await f.text()).match(/<ETag>"?([^"<]+)"?<\/ETag>/);return{etag:S?S[1]:""}}async abortMultipartUpload(n,i,s,o){let c=await this.getCredentials(),l=`${o??this.buildUrl(n,i)}?uploadId=${encodeURIComponent(s)}`,u=O({method:"DELETE",url:l,...c,service:"s3",region:this.region});await fetch(u.url,{method:u.method,headers:u.headers})}async emptyAndDeleteBucket(n){let i=[];for await(let l of this.listAll(n,{}))if(i.push(l.key),i.length>=1000)await this.deleteMany(n,i),i=[];if(i.length>0)await this.deleteMany(n,i);let s=await this.getCredentials(),o=this.buildUrl(n),c=O({method:"DELETE",url:o,...s,service:"s3",region:this.region});await fetch(c.url,{method:c.method,headers:c.headers})}}class V extends Error{statusCode;bucket;key;constructor(n,i,s,o){super(n);this.statusCode=i,this.bucket=s,this.key=o,this.name="S3Error"}}function Dn(n){let i=[],s=[],o=/<Contents>([\s\S]*?)<\/Contents>/g,c;while((c=o.exec(n))!==null){let u=c[1];i.push({key:ce(u,"Key")||"",lastModified:new Date(ce(u,"LastModified")||0),etag:(ce(u,"ETag")||"").replace(/"/g,""),size:Number(ce(u,"Size")||0),storageClass:ce(u,"StorageClass")||"STANDARD"})}let l=/<CommonPrefixes><Prefix>([^<]+)<\/Prefix><\/CommonPrefixes>/g;while((c=l.exec(n))!==null)s.push(c[1]);return{contents:i,commonPrefixes:s,isTruncated:ce(n,"IsTruncated")==="true",continuationToken:ce(n,"ContinuationToken")||void 0,nextContinuationToken:ce(n,"NextContinuationToken")||void 0,keyCount:Number(ce(n,"KeyCount")||0),maxKeys:Number(ce(n,"MaxKeys")||1000),prefix:ce(n,"Prefix")||void 0,delimiter:ce(n,"Delimiter")||void 0}}function ce(n,i){let s=new RegExp(`<${i}>([^<]*)</${i}>`),o=n.match(s);return o?o[1]:null}function kn(n){return n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;")}function ha(n){let i=n.split(".").pop()?.toLowerCase();return{html:"text/html",htm:"text/html",css:"text/css",js:"application/javascript",mjs:"application/javascript",json:"application/json",xml:"application/xml",txt:"text/plain",md:"text/markdown",csv:"text/csv",jpg:"image/jpeg",jpeg:"image/jpeg",png:"image/png",gif:"image/gif",webp:"image/webp",svg:"image/svg+xml",ico:"image/x-icon",avif:"image/avif",mp4:"video/mp4",webm:"video/webm",mov:"video/quicktime",avi:"video/x-msvideo",mp3:"audio/mpeg",wav:"audio/wav",ogg:"audio/ogg",pdf:"application/pdf",doc:"application/msword",docx:"application/vnd.openxmlformats-officedocument.wordprocessingml.document",xls:"application/vnd.ms-excel",xlsx:"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",ppt:"application/vnd.ms-powerpoint",pptx:"application/vnd.openxmlformats-officedocument.presentationml.presentation",zip:"application/zip",gz:"application/gzip",tar:"application/x-tar",rar:"application/vnd.rar","7z":"application/x-7z-compressed",woff:"font/woff",woff2:"font/woff2",ttf:"font/ttf",otf:"font/otf",eot:"application/vnd.ms-fontobject",wasm:"application/wasm"}[i||""]||"application/octet-stream"}function $n(n){if(n instanceof Blob)return n;if(typeof n==="string")return new Blob([n],{type:"text/plain"});return new Blob([n])}function lS(n){return new Ba(n)}await rt();class We extends Error{code;solution;details;constructor(n,i,s,o){super(n);this.code=i,this.solution=s,this.details=o,this.name="CloudError",Error.captureStackTrace?.(this,We)}toString(){let n=`${this.name} [${this.code}]: ${this.message}`;if(this.solution)n+=`
2496
2496
 
2497
2497
  \uD83D\uDCA1 Solution: ${this.solution}`;if(this.details&&Object.keys(this.details).length>0){n+=`
2498
2498
 
@@ -2507,9 +2507,9 @@ Stack trace:`),console.error(i.stack)}}static success(n){console.log(`✔ ${n}`)
2507
2507
  `,s=n.reduce((o,c)=>{if(!o[c.service])o[c.service]=[];return o[c.service].push(c),o},{});for(let[o,c]of Object.entries(s)){i+=`${o}:
2508
2508
  `;for(let l of c){let u=l.warning?"⚠":"✓";i+=` ${u} ${l.quotaName}: ${l.currentValue}/${l.limit} (${l.percentage.toFixed(1)}%)
2509
2509
  `}i+=`
2510
- `}return i}function yS(n){let i=[];for(let s of n)if(s.percentage>=100)i.push(`Request quota increase for ${s.service} - ${s.quotaName} (currently ${s.limit})`);else if(s.warning)i.push(`Consider requesting quota increase for ${s.service} - ${s.quotaName} (${s.percentage.toFixed(1)}% used)`);return i}class Pg{cacheDir;ttl;constructor(n,i={}){this.cacheDir=n,this.ttl=i.ttl||86400000}ensureCacheDir(){if(!lt(this.cacheDir))Ln(this.cacheDir,{recursive:!0})}getCachePath(n){let i=_a("sha256").update(n).digest("hex");return kt(this.cacheDir,`${i}.json`)}get(n){let i=this.getCachePath(n);if(!lt(i))return;try{let s=fa(i,"utf-8"),o=JSON.parse(s);if(Date.now()-o.timestamp>this.ttl){Ye(i);return}return o.value}catch{Ye(i);return}}set(n,i,s){this.ensureCacheDir();let o=this.getCachePath(n),c={value:i,timestamp:Date.now(),hash:s};Mn(o,JSON.stringify(c),"utf-8")}has(n){return this.get(n)!==void 0}clear(){if(!lt(this.cacheDir))return;let n=ya(this.cacheDir);for(let i of n)Ye(kt(this.cacheDir,i))}prune(){if(!lt(this.cacheDir))return;let n=ya(this.cacheDir),i=Date.now();for(let s of n){let o=kt(this.cacheDir,s);try{let c=fa(o,"utf-8"),l=JSON.parse(c);if(i-l.timestamp>this.ttl)Ye(o)}catch{Ye(o)}}}}class Ng{cache;constructor(n=L("cache","templates")){this.cache=new Pg(n,{ttl:86400000})}getTemplate(n){return this.cache.get(`template:${n}`)}setTemplate(n,i){let s=this.hashTemplate(i);this.cache.set(`template:${n}`,i,s)}hasChanged(n,i){let s=this.cache.get(`template:${n}`);if(!s)return!0;let o=this.hashTemplate(s),c=this.hashTemplate(i);return o!==c}hashTemplate(n){return _a("sha256").update(n).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var $t=null;function IS(){if(!$t)$t=new Ng;return $t}async function kg(n,i={}){let s=i.algorithm||"sha256",o=i.chunkSize||65536;return new Promise((c,l)=>{let u=Yt(s),h=On(n,{highWaterMark:o});h.on("data",(y)=>u.update(y)),h.on("end",()=>c(u.digest("hex"))),h.on("error",l)})}function Bg(n,i="sha256"){return Yt(i).update(n).digest("hex")}function SS(n,i="sha256"){return Yt(i).update(n).digest("hex")}async function CS(n,i={}){let s=i.ignorePatterns||["node_modules",".git","dist","build",lo()],o=[];async function c(l){let u=xn(l,{withFileTypes:!0});for(let h of u){let y=Bn(l,h.name),f=_n(n,y);if(s.some((b)=>f.includes(b)))continue;if(h.isDirectory())await c(y);else if(h.isFile()){let b=St(y),C=await kg(y,i);o.push({path:f,hash:C,size:b.size,mtime:b.mtimeMs})}}}return await c(n),o}function ES(n){let i=[...n].sort((s,o)=>s.path.localeCompare(o.path)).map((s)=>`${s.path}:${s.hash}`).join(`
2511
- `);return Bg(i)}function bS(n){let i=St(n);return Bg(`${n}:${i.size}:${i.mtimeMs}`)}function vS(n,i){let s=new Map(n.map((h)=>[h.path,h])),o=new Map(i.map((h)=>[h.path,h])),c=[],l=[],u=[];for(let[h,y]of o){let f=s.get(h);if(!f)c.push(y);else if(f.hash!==y.hash)l.push(y)}for(let[h,y]of s)if(!o.has(h))u.push(y);return{added:c,modified:l,deleted:u}}class kA{cache;constructor(){this.cache=new Map}get(n){let i=St(n),s=this.cache.get(n);if(s&&s.mtime===i.mtimeMs&&s.size===i.size)return s.hash;return}set(n,i){let s=St(n);this.cache.set(n,{hash:i,mtime:s.mtimeMs,size:s.size})}async getOrCompute(n,i={}){let s=this.get(n);if(s)return s;let o=await kg(n,i);return this.set(n,o),o}clear(){this.cache.clear()}}async function Md(n,i={}){let s=i.concurrency||5,o=i.stopOnError??!0,c=[],l=[],u=Date.now(),h=[...n],y=[];async function f(T,w){try{let E=await T();c[w]=E}catch(E){let I=E instanceof Error?E:Error(String(E));if(l.push(I),o)throw h.length=0,I}}let b=0;while(h.length>0||y.length>0){while(y.length<s&&h.length>0){let T=h.shift(),w=b++,E=f(T,w);y.push(E)}if(y.length>0){await Promise.race(y);for(let T=y.length-1;T>=0;T--)if(await Promise.race([y[T].then(()=>!0),Promise.resolve(!1)]))y.splice(T,1)}if(o&&l.length>0)break}let C=Date.now()-u;return{results:c.filter((T)=>T!==void 0),errors:l,duration:C}}async function TS(n,i,s={}){let o=n.map((c)=>()=>i(c));return Md(o,s)}async function wS(n,i,s=5){let o=n.map((l,u)=>()=>i(l,u)),c=await Md(o,{concurrency:s,stopOnError:!1});if(c.errors.length>0)throw AggregateError(c.errors,"Parallel map failed");return c.results}async function RS(n,i={}){let s=i.retries||3,o=i.retryDelay||1000,c=n.map((l)=>async()=>{let u;for(let h=0;h<=s;h++)try{return await l()}catch(y){if(u=y instanceof Error?y:Error(String(y)),h<s)await Wa(o*(h+1))}throw u});return Md(c,i)}async function DS(n){let i=[];for(let s of n){let o=await s();i.push(o)}return i}function Wa(n){return new Promise((i)=>setTimeout(i,n))}async function PS(n,i,s="Operation timed out"){return Promise.race([n(),new Promise((o,c)=>setTimeout(()=>c(Error(s)),i))])}class BA{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(n=5,i=100){this.maxConcurrent=n,this.minInterval=i}async execute(n){await this.waitForSlot(),this.running++,this.lastExecution=Date.now();try{return await n()}finally{this.running--,this.processQueue()}}waitForSlot(){if(this.running<this.maxConcurrent){let n=Date.now()-this.lastExecution;if(n>=this.minInterval)return Promise.resolve();return Wa(this.minInterval-n)}return new Promise((n)=>this.queue.push(n))}processQueue(){if(this.queue.length>0&&this.running<this.maxConcurrent)this.queue.shift()()}stats(){return{running:this.running,queued:this.queue.length}}}function _A(n,i){let s=[];for(let o=0;o<n.length;o+=i)s.push(n.slice(o,o+i));return s}async function NS(n,i,s){let o=_A(n,i),c=[];for(let l of o){let u=await s(l);c.push(...u)}return c}function kS(n,i){let s=[],o=[],c=[],l=[],u=n.Resources||{},h=i.Resources||{},y=new Set(Object.keys(u)),f=new Set(Object.keys(h));for(let T of f)if(!y.has(T))s.push(T);for(let T of y)if(!f.has(T))c.push(T);for(let T of f)if(y.has(T)){let w=u[T],E=h[T];if(JSON.stringify(w)!==JSON.stringify(E))o.push(T);else l.push(T)}let b=JSON.stringify(n.Parameters||{})!==JSON.stringify(i.Parameters||{}),C=JSON.stringify(n.Outputs||{})!==JSON.stringify(i.Outputs||{});return{added:s,modified:o,deleted:c,unchanged:l,parametersChanged:b,outputsChanged:C,hasChanges:s.length>0||o.length>0||c.length>0||b||C}}function BS(n){let i=[];if(!n.hasChanges)return"No changes detected";if(n.added.length>0){i.push(`Added resources (${n.added.length}):`);for(let s of n.added)i.push(` + ${s}`)}if(n.modified.length>0){i.push(`Modified resources (${n.modified.length}):`);for(let s of n.modified)i.push(` ~ ${s}`)}if(n.deleted.length>0){i.push(`Deleted resources (${n.deleted.length}):`);for(let s of n.deleted)i.push(` - ${s}`)}if(n.parametersChanged)i.push("Parameters changed");if(n.outputsChanged)i.push("Outputs changed");return i.join(`
2512
- `)}function _S(n,i,s){if(n.deleted.length>0)return!0;for(let o of n.modified){let c=i.Resources[o],l=s.Resources[o];if(c.Type!==l.Type)return!0;let u=Wn(l.Type);for(let h of u){let y=c.Properties?.[h],f=l.Properties?.[h];if(JSON.stringify(y)!==JSON.stringify(f))return!0}}return!1}function Wn(n){return{"AWS::S3::Bucket":["BucketName"],"AWS::EC2::Instance":["ImageId","InstanceType","KeyName"],"AWS::RDS::DBInstance":["DBInstanceIdentifier","Engine"],"AWS::DynamoDB::Table":["TableName","KeySchema"],"AWS::Lambda::Function":["FunctionName"],"AWS::ECS::Service":["ServiceName"],"AWS::ElasticLoadBalancingV2::LoadBalancer":["Name","Type"]}[n]||[]}function xS(n){let i=[],s=[],o=[];i.push(...n.added);for(let c of n.modified)s.push(c);return o.push(...n.deleted),{safe:i,caution:s,dangerous:o}}function OS(n){if(!n.hasChanges)return{strategy:"skip",reason:"No changes detected"};if(n.deleted.length>0)return{strategy:"replace",reason:"Resources will be deleted"};if(n.added.length>0&&n.modified.length===0)return{strategy:"update",reason:"Only new resources added"};return{strategy:"update",reason:"Resources will be updated"}}function LS(n){let i=n.added.length+n.modified.length+n.deleted.length+n.unchanged.length,s=n.added.length+n.modified.length+n.deleted.length,o=i>0?s/i*100:0;return{total:i,added:n.added.length,modified:n.modified.length,deleted:n.deleted.length,unchanged:n.unchanged.length,changePercentage:o}}var $S={$schema:"http://json-schema.org/draft-07/schema#",title:"ts-cloud Configuration",description:"Configuration schema for ts-cloud infrastructure-as-code",type:"object",required:["project"],properties:{project:{type:"object",description:"Project configuration",required:["name","slug"],properties:{name:{type:"string",description:"Human-readable project name",minLength:1},slug:{type:"string",description:"URL-safe project identifier (lowercase, alphanumeric, hyphens only)",pattern:"^[a-z0-9-]+$",minLength:1,maxLength:63},region:{type:"string",description:"Default AWS region",enum:["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"]}}},mode:{type:"string",description:"Deployment mode (server and serverless are mutually exclusive; auto-detected when omitted)",enum:["server","serverless"]},environments:{type:"object",description:"Environment-specific configurations",properties:{production:{$ref:"#/definitions/environment"},staging:{$ref:"#/definitions/environment"},development:{$ref:"#/definitions/environment"}}},infrastructure:{type:"object",description:"Infrastructure configuration",properties:{network:{$ref:"#/definitions/network"},storage:{type:"object",description:"S3 storage configuration",additionalProperties:{$ref:"#/definitions/storage"}},compute:{$ref:"#/definitions/compute"},database:{$ref:"#/definitions/database"},cache:{$ref:"#/definitions/cache"},cdn:{$ref:"#/definitions/cdn"},sftp:{$ref:"#/definitions/sftp"},functions:{type:"object",description:"Lambda functions configuration",additionalProperties:{type:"array",items:{$ref:"#/definitions/function"}}},monitoring:{$ref:"#/definitions/monitoring"},security:{$ref:"#/definitions/security"},queue:{type:"object",description:"SQS queue configuration",additionalProperties:{$ref:"#/definitions/queue"}}}}},definitions:{environment:{type:"object",properties:{domain:{type:"string",description:"Custom domain for this environment"},region:{type:"string",description:"AWS region override for this environment"},app:{type:"object",description:"Serverless application manifest (Laravel-Vapor-equivalent). Defining this opts the environment into the serverless app deploy pipeline (http/queue/cli Lambda functions, assets, build/deploy hooks).",properties:{runtime:{type:"string",description:"Lambda runtime override (usually derived from kind + runtimeVersion)"},runtimeVersion:{type:"string",description:"Node major (18/20/22 managed, 24+ custom layer) or Bun release for node/bun apps"},kind:{type:"string",enum:["node","bun","php"],description:"Application kind (drives packaging + runtime)"},entry:{type:"string",description:"Entry file exporting the request handler"},memory:{type:"number",description:"HTTP function memory in MB"},timeout:{type:"number",description:"HTTP request timeout in seconds"},gatewayVersion:{type:"number",enum:[1,2],description:"API Gateway version (2 = HTTP API, 1 = REST)"},warm:{type:"number",description:"Keep-warm / provisioned concurrency count"},lambdaInsights:{type:"object",description:"CloudWatch Lambda Insights extension configuration for zip deployments",required:["layerArn"],properties:{layerArn:{type:"string",description:"Region- and architecture-specific Lambda Insights extension layer ARN"}}},queues:{description:"Queue names (true = single default queue, false = disabled)"},scheduler:{type:"string",enum:["off","on","sub-minute"],description:"Task scheduler mode"},build:{type:"array",items:{type:"string"},description:"Commands run locally before packaging"},deploy:{type:"array",items:{type:"string"},description:"Commands run remotely after activation (e.g. migrations)"},octane:{type:"boolean",description:"Persistent application mode (Laravel Octane)"},packaging:{type:"string",enum:["zip","image"],description:"Deployment package format (zip or container image)"},phpVersion:{type:"string",description:"PHP version for the runtime layer (kind: php)"},architecture:{type:"string",enum:["x86_64","arm64"],description:"CPU architecture"}}}}},network:{type:"object",properties:{vpc:{type:"object",properties:{cidr:{type:"string",description:"VPC CIDR block",pattern:"^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$",default:"10.0.0.0/16"},availabilityZones:{type:"number",description:"Number of availability zones",minimum:1,maximum:3,default:2},natGateways:{type:"number",description:"Number of NAT gateways (0 for no NAT, saves cost)",minimum:0,maximum:3,default:1}}}}},storage:{type:"object",properties:{public:{type:"boolean",description:"Allow public access",default:!1},versioning:{type:"boolean",description:"Enable versioning",default:!1},encryption:{type:"boolean",description:"Enable server-side encryption",default:!0},website:{type:"boolean",description:"Enable static website hosting",default:!1},cors:{type:"object",description:"CORS configuration",properties:{allowedOrigins:{type:"array",items:{type:"string"}},allowedMethods:{type:"array",items:{type:"string",enum:["GET","PUT","POST","DELETE","HEAD"]}}}}}},compute:{type:"object",properties:{server:{type:"object",description:"EC2 server configuration",properties:{instanceType:{type:"string",description:"EC2 instance type",enum:["t3.micro","t3.small","t3.medium","t3.large","t3.xlarge","t3.2xlarge"]},autoScaling:{type:"object",properties:{min:{type:"number",minimum:1},max:{type:"number",minimum:1},desired:{type:"number",minimum:1}}}}},fargate:{type:"object",description:"ECS Fargate configuration",properties:{cpu:{type:"number",description:"CPU units (256, 512, 1024, 2048, 4096)",enum:[256,512,1024,2048,4096]},memory:{type:"number",description:"Memory in MB"},desiredCount:{type:"number",description:"Desired number of tasks",minimum:1}}}}},database:{type:"object",properties:{postgres:{type:"object",properties:{instanceClass:{type:"string",description:"RDS instance class",pattern:"^db\\.[a-z0-9]+\\.[a-z0-9]+$"},engine:{type:"string",const:"postgres"},version:{type:"string",description:"PostgreSQL version"},multiAZ:{type:"boolean",description:"Enable Multi-AZ deployment",default:!1},backupRetentionDays:{type:"number",description:"Backup retention period in days",minimum:0,maximum:35,default:7}}},mysql:{type:"object",properties:{instanceClass:{type:"string",pattern:"^db\\.[a-z0-9]+\\.[a-z0-9]+$"},engine:{type:"string",const:"mysql"},version:{type:"string"},multiAZ:{type:"boolean",default:!1},backupRetentionDays:{type:"number",minimum:0,maximum:35,default:7}}},dynamodb:{type:"object",properties:{tables:{type:"array",items:{type:"object",required:["name","partitionKey"],properties:{name:{type:"string"},partitionKey:{type:"string"},sortKey:{type:"string"},billingMode:{type:"string",enum:["PAY_PER_REQUEST","PROVISIONED"],default:"PAY_PER_REQUEST"}}}}}}}},cache:{type:"object",properties:{redis:{type:"object",properties:{nodeType:{type:"string",description:"ElastiCache node type",pattern:"^cache\\.[a-z0-9]+\\.[a-z0-9]+$"},numCacheNodes:{type:"number",minimum:1,default:1},engineVersion:{type:"string",description:"Redis engine version"}}},memcached:{type:"object",properties:{nodeType:{type:"string",pattern:"^cache\\.[a-z0-9]+\\.[a-z0-9]+$"},numCacheNodes:{type:"number",minimum:1,default:1}}}}},cdn:{type:"object",properties:{enabled:{type:"boolean",default:!0},originShield:{type:"boolean",description:"Enable CloudFront Origin Shield",default:!1},originShieldRegion:{type:"string",description:"AWS region used by CloudFront Origin Shield"},compress:{type:"boolean",description:"Enable automatic compression",default:!0},http3:{type:"boolean",description:"Enable HTTP/3 support",default:!0},customDomain:{type:"object",properties:{domain:{type:"string"},certificateArn:{type:"string"}}},cachePolicy:{type:"object",properties:{minTTL:{type:"number",minimum:0},defaultTTL:{type:"number",minimum:0},maxTTL:{type:"number",minimum:0}}}}},sftp:{type:"object",required:["bucket","users"],properties:{bucket:{type:"string",description:"S3 bucket backing the SFTP server"},endpointType:{type:"string",enum:["PUBLIC","VPC"],default:"PUBLIC"},endpointDetails:{type:"object",required:["vpcId","subnetIds"],properties:{vpcId:{type:"string"},subnetIds:{type:"array",items:{type:"string"},minItems:1},securityGroupIds:{type:"array",items:{type:"string"}},addressAllocationIds:{type:"array",items:{type:"string"}}}},securityPolicyName:{type:"string"},logging:{type:"boolean",default:!0},users:{type:"object",additionalProperties:{type:"object",required:["sshPublicKeys"],properties:{sshPublicKeys:{type:"array",items:{type:"string"},minItems:1},homeDirectory:{type:"string"},roleArn:{type:"string"}}}}}},function:{type:"object",required:["name","runtime"],properties:{name:{type:"string"},runtime:{type:"string",enum:["nodejs18.x","nodejs20.x","python3.10","python3.11","python3.12"]},handler:{type:"string",default:"index.handler"},timeout:{type:"number",minimum:1,maximum:900,default:30},memory:{type:"number",minimum:128,maximum:10240,default:1024}}},monitoring:{type:"object",properties:{alarms:{type:"array",items:{type:"object",required:["metric","threshold"],properties:{metric:{type:"string"},threshold:{type:"number"},evaluationPeriods:{type:"number",minimum:1,default:2}}}},dashboard:{type:"object",properties:{name:{type:"string"},widgets:{type:"array"}}}}},security:{type:"object",properties:{waf:{type:"boolean",description:"Enable AWS WAF",default:!1},certificates:{type:"array",items:{type:"object",required:["domain"],properties:{domain:{type:"string"},subdomains:{type:"array",items:{type:"string"}}}}}}},queue:{type:"object",properties:{fifo:{type:"boolean",default:!1},deadLetterQueue:{type:"boolean",default:!0},visibilityTimeout:{type:"number",minimum:0,maximum:43200,default:30},messageRetentionPeriod:{type:"number",minimum:60,maximum:1209600,default:345600}}}}};function MS(n){let i=[];if(!n.project)i.push("Missing required field: project");else{if(!n.project.name)i.push("Missing required field: project.name");if(!n.project.slug)i.push("Missing required field: project.slug")}if(n.project?.slug&&!/^[a-z0-9-]+$/.test(n.project.slug))i.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let s=["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"];if(n.project?.region&&!s.includes(n.project.region))i.push(`Invalid region: ${n.project.region}. Must be one of: ${s.join(", ")}`);if(n.mode&&!["server","serverless"].includes(n.mode))i.push("Invalid mode: must be one of server or serverless");return{valid:i.length===0,errors:i}}var _g={enabled:process.env.TS_CLOUD_LOCAL==="true"||!0,localstackEndpoint:process.env.LOCALSTACK_ENDPOINT||"http://localhost:4566",postgresUrl:process.env.POSTGRES_URL||"postgresql://tscloud:tscloud@localhost:5432/tscloud",redisUrl:process.env.REDIS_URL||"redis://localhost:6379",dynamodbEndpoint:process.env.DYNAMODB_ENDPOINT||"http://localhost:8000",s3Endpoint:process.env.S3_ENDPOINT||"http://localhost:9000",emailEndpoint:process.env.EMAIL_ENDPOINT||"smtp://localhost:1025",awsRegion:process.env.AWS_REGION||"us-east-1",awsAccessKeyId:process.env.AWS_ACCESS_KEY_ID||"test",awsSecretAccessKey:process.env.AWS_SECRET_ACCESS_KEY||"test"};function Fd(){return _g}function FS(){return _g.enabled}function US(n){let i=Fd();if(!i.enabled)return"";switch(n.toLowerCase()){case"dynamodb":return i.dynamodbEndpoint;case"s3":return i.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return i.localstackEndpoint;default:return i.localstackEndpoint}}function QS(){let n=Fd();return{accessKeyId:n.awsAccessKeyId,secretAccessKey:n.awsSecretAccessKey,region:n.awsRegion}}function HS(){let n=Fd();if(!n.enabled)return{};return{AWS_ACCESS_KEY_ID:n.awsAccessKeyId,AWS_SECRET_ACCESS_KEY:n.awsSecretAccessKey,AWS_REGION:n.awsRegion,AWS_ENDPOINT_URL:n.localstackEndpoint,LOCALSTACK_ENDPOINT:n.localstackEndpoint,TS_CLOUD_LOCAL:"true"}}class xg{stacks=new Map;stackEvents=new Map;async createStack(n){let i=`arn:aws:cloudformation:${n.region||"us-east-1"}:123456789012:stack/${n.StackName}/${Date.now()}`;return this.stacks.set(n.StackName,{StackId:i,StackName:n.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:n.TemplateBody,Parameters:n.Parameters||[]}),this.addEvent(n.StackName,{EventId:Date.now().toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let s=this.stacks.get(n.StackName);if(s)s.StackStatus="CREATE_COMPLETE",this.addEvent(n.StackName,{EventId:(Date.now()+1).toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:i}}async updateStack(n){let i=this.stacks.get(n.StackName);if(!i)throw Error(`Stack ${n.StackName} does not exist`);return i.StackStatus="UPDATE_IN_PROGRESS",i.TemplateBody=n.TemplateBody||i.TemplateBody,this.addEvent(n.StackName,{EventId:Date.now().toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_IN_PROGRESS"}),setTimeout(()=>{i.StackStatus="UPDATE_COMPLETE",this.addEvent(n.StackName,{EventId:(Date.now()+1).toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_COMPLETE"})},100),{StackId:i.StackId}}async deleteStack(n){let i=this.stacks.get(n.StackName);if(!i)throw Error(`Stack ${n.StackName} does not exist`);i.StackStatus="DELETE_IN_PROGRESS",this.addEvent(n.StackName,{EventId:Date.now().toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_IN_PROGRESS"}),setTimeout(()=>{this.stacks.delete(n.StackName),this.addEvent(n.StackName,{EventId:(Date.now()+1).toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_COMPLETE"})},100)}async describeStacks(n){if(n.StackName){let i=this.stacks.get(n.StackName);if(!i)throw Error(`Stack ${n.StackName} does not exist`);return{Stacks:[i]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(n){return{StackEvents:this.stackEvents.get(n.StackName)||[]}}addEvent(n,i){if(!this.stackEvents.has(n))this.stackEvents.set(n,[]);this.stackEvents.get(n).unshift(i)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class Og{buckets=new Map;async createBucket(n){return this.buckets.set(n.Bucket,new Map),{Location:`/${n.Bucket}`}}async deleteBucket(n){this.buckets.delete(n.Bucket)}async putObject(n){let i=this.buckets.get(n.Bucket);if(!i)i=new Map,this.buckets.set(n.Bucket,i);return i.set(n.Key,Buffer.from(n.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(n){let i=this.buckets.get(n.Bucket);if(!i)throw Error(`Bucket ${n.Bucket} does not exist`);let s=i.get(n.Key);if(!s)throw Error(`Object ${n.Key} does not exist`);return{Body:s,ContentLength:s.length}}async deleteObject(n){let i=this.buckets.get(n.Bucket);if(i)i.delete(n.Key)}async listObjects(n){let i=this.buckets.get(n.Bucket);if(!i)throw Error(`Bucket ${n.Bucket} does not exist`);return{Contents:Array.from(i.keys()).map((s)=>({Key:s,Size:i.get(s).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class Lg{tables=new Map;data=new Map;async createTable(n){return this.tables.set(n.TableName,{TableName:n.TableName,KeySchema:n.KeySchema,AttributeDefinitions:n.AttributeDefinitions,TableStatus:"ACTIVE",CreationDateTime:new Date().toISOString()}),this.data.set(n.TableName,new Map),{TableDescription:this.tables.get(n.TableName)}}async deleteTable(n){this.tables.delete(n.TableName),this.data.delete(n.TableName)}async putItem(n){let i=this.data.get(n.TableName);if(!i)i=new Map,this.data.set(n.TableName,i);let s=JSON.stringify(n.Item);i.set(s,n.Item)}async getItem(n){let i=this.data.get(n.TableName);if(!i)return{};let s=JSON.stringify(n.Key),o=i.get(s);return o?{Item:o}:{}}async deleteItem(n){let i=this.data.get(n.TableName);if(i){let s=JSON.stringify(n.Key);i.delete(s)}}async scan(n){let i=this.data.get(n.TableName);if(!i)return{Items:[]};return{Items:Array.from(i.values())}}reset(){this.tables.clear(),this.data.clear()}}function GS(n){return{cloudformation:new xg,s3:new Og,dynamodb:new Lg}}class $g{environments=new Map;async createPreviewEnvironment(n){let{branch:i,pr:s,commitSha:o,ttl:c=24,baseConfig:l,region:u="us-east-1"}=n,h=this.generatePreviewId(i,s,o),y=this.generatePreviewName(i,s),f=`preview-${y}`,b=new Date,C=new Date(b.getTime()+c*60*60*1000),T={id:h,name:y,branch:i,pr:s,commitSha:o,createdAt:b,expiresAt:C,status:"creating",stackName:f,region:u,resources:[]};this.environments.set(h,T);try{let w=this.createPreviewConfig(l,y);return T.status="active",T.url=`https://${y}.preview.example.com`,T}catch(w){throw T.status="failed",w}}async destroyPreviewEnvironment(n){let i=this.environments.get(n);if(!i)throw Error(`Preview environment ${n} not found`);i.status="destroying";try{i.status="destroyed",this.environments.delete(n)}catch(s){throw Error(`Failed to destroy preview environment: ${s}`)}}getPreviewEnvironment(n){return this.environments.get(n)}getPreviewEnvironmentByBranch(n){return Array.from(this.environments.values()).find((i)=>i.branch===n)}getPreviewEnvironmentByPR(n){return Array.from(this.environments.values()).find((i)=>i.pr===n)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((n)=>n.status==="active")}async cleanupExpiredEnvironments(n={}){let{maxAge:i,keepCount:s,dryRun:o=!1}=n,c=[],l=[],u=new Date,h=this.listPreviewEnvironments().sort((y,f)=>f.createdAt.getTime()-y.createdAt.getTime());for(let y=0;y<h.length;y++){let f=h[y];if(f.status!=="active")continue;let b=!1;if(f.expiresAt<u)b=!0;if(i){if((u.getTime()-f.createdAt.getTime())/3600000>i)b=!0}if(s&&y>=s)b=!0;if(b)if(o)c.push(f.id);else try{await this.destroyPreviewEnvironment(f.id),c.push(f.id)}catch(C){l.push(f.id)}}return{destroyed:c,failed:l}}async updatePreviewEnvironment(n,i){let s=this.environments.get(n);if(!s)throw Error(`Preview environment ${n} not found`);s.commitSha=i,s.status="creating";try{return s.status="active",s}catch(o){throw s.status="failed",o}}async getPreviewEnvironmentsCost(){let n={},i=0;for(let s of this.environments.values())n[s.id]=0,i+=0;return{total:i,byEnvironment:n}}generatePreviewId(n,i,s){let o=n.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),c=s?.substring(0,7)||Date.now().toString();return i?`pr-${i}-${c}`:`${o}-${c}`}generatePreviewName(n,i){let s=n.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return i?`pr-${i}`:s}createPreviewConfig(n,i){return{...n,project:{...n.project,name:`${n.project.name} Preview (${i})`,slug:`${n.project.slug}-preview-${i}`}}}}var qS=new $g;function VS(n={}){let{workflowName:i="Preview Environment",trigger:s="pull_request",branches:o=["main","develop"],awsRegion:c="us-east-1",awsRole:l,configFile:u="cloud.config.ts",ttl:h=24}=n;return`name: ${i}
2510
+ `}return i}function yS(n){let i=[];for(let s of n)if(s.percentage>=100)i.push(`Request quota increase for ${s.service} - ${s.quotaName} (currently ${s.limit})`);else if(s.warning)i.push(`Consider requesting quota increase for ${s.service} - ${s.quotaName} (${s.percentage.toFixed(1)}% used)`);return i}class Pg{cacheDir;ttl;constructor(n,i={}){this.cacheDir=n,this.ttl=i.ttl||86400000}ensureCacheDir(){if(!lt(this.cacheDir))Ln(this.cacheDir,{recursive:!0})}getCachePath(n){let i=_a("sha256").update(n).digest("hex");return kt(this.cacheDir,`${i}.json`)}get(n){let i=this.getCachePath(n);if(!lt(i))return;try{let s=fa(i,"utf-8"),o=JSON.parse(s);if(Date.now()-o.timestamp>this.ttl){Ye(i);return}return o.value}catch{Ye(i);return}}set(n,i,s){this.ensureCacheDir();let o=this.getCachePath(n),c={value:i,timestamp:Date.now(),hash:s};Mn(o,JSON.stringify(c),"utf-8")}has(n){return this.get(n)!==void 0}clear(){if(!lt(this.cacheDir))return;let n=ya(this.cacheDir);for(let i of n)Ye(kt(this.cacheDir,i))}prune(){if(!lt(this.cacheDir))return;let n=ya(this.cacheDir),i=Date.now();for(let s of n){let o=kt(this.cacheDir,s);try{let c=fa(o,"utf-8"),l=JSON.parse(c);if(i-l.timestamp>this.ttl)Ye(o)}catch{Ye(o)}}}}class Ng{cache;constructor(n=L("cache","templates")){this.cache=new Pg(n,{ttl:86400000})}getTemplate(n){return this.cache.get(`template:${n}`)}setTemplate(n,i){let s=this.hashTemplate(i);this.cache.set(`template:${n}`,i,s)}hasChanged(n,i){let s=this.cache.get(`template:${n}`);if(!s)return!0;let o=this.hashTemplate(s),c=this.hashTemplate(i);return o!==c}hashTemplate(n){return _a("sha256").update(n).digest("hex")}clear(){this.cache.clear()}prune(){this.cache.prune()}}var $t=null;function IS(){if(!$t)$t=new Ng;return $t}async function kg(n,i={}){let s=i.algorithm||"sha256",o=i.chunkSize||65536;return new Promise((c,l)=>{let u=Yt(s),h=On(n,{highWaterMark:o});h.on("data",(y)=>u.update(y)),h.on("end",()=>c(u.digest("hex"))),h.on("error",l)})}function Bg(n,i="sha256"){return Yt(i).update(n).digest("hex")}function SS(n,i="sha256"){return Yt(i).update(n).digest("hex")}async function CS(n,i={}){let s=i.ignorePatterns||["node_modules",".git","dist","build",lo()],o=[];async function c(l){let u=xn(l,{withFileTypes:!0});for(let h of u){let y=Bn(l,h.name),f=_n(n,y);if(s.some((S)=>f.includes(S)))continue;if(h.isDirectory())await c(y);else if(h.isFile()){let S=St(y),b=await kg(y,i);o.push({path:f,hash:b,size:S.size,mtime:S.mtimeMs})}}}return await c(n),o}function ES(n){let i=[...n].sort((s,o)=>s.path.localeCompare(o.path)).map((s)=>`${s.path}:${s.hash}`).join(`
2511
+ `);return Bg(i)}function bS(n){let i=St(n);return Bg(`${n}:${i.size}:${i.mtimeMs}`)}function vS(n,i){let s=new Map(n.map((h)=>[h.path,h])),o=new Map(i.map((h)=>[h.path,h])),c=[],l=[],u=[];for(let[h,y]of o){let f=s.get(h);if(!f)c.push(y);else if(f.hash!==y.hash)l.push(y)}for(let[h,y]of s)if(!o.has(h))u.push(y);return{added:c,modified:l,deleted:u}}class kA{cache;constructor(){this.cache=new Map}get(n){let i=St(n),s=this.cache.get(n);if(s&&s.mtime===i.mtimeMs&&s.size===i.size)return s.hash;return}set(n,i){let s=St(n);this.cache.set(n,{hash:i,mtime:s.mtimeMs,size:s.size})}async getOrCompute(n,i={}){let s=this.get(n);if(s)return s;let o=await kg(n,i);return this.set(n,o),o}clear(){this.cache.clear()}}async function Md(n,i={}){let s=i.concurrency||5,o=i.stopOnError??!0,c=[],l=[],u=Date.now(),h=[...n],y=[];async function f(v,w){try{let E=await v();c[w]=E}catch(E){let P=E instanceof Error?E:Error(String(E));if(l.push(P),o)throw h.length=0,P}}let S=0;while(h.length>0||y.length>0){while(y.length<s&&h.length>0){let v=h.shift(),w=S++,E=f(v,w);y.push(E)}if(y.length>0){await Promise.race(y);for(let v=y.length-1;v>=0;v--)if(await Promise.race([y[v].then(()=>!0),Promise.resolve(!1)]))y.splice(v,1)}if(o&&l.length>0)break}let b=Date.now()-u;return{results:c.filter((v)=>v!==void 0),errors:l,duration:b}}async function TS(n,i,s={}){let o=n.map((c)=>()=>i(c));return Md(o,s)}async function wS(n,i,s=5){let o=n.map((l,u)=>()=>i(l,u)),c=await Md(o,{concurrency:s,stopOnError:!1});if(c.errors.length>0)throw AggregateError(c.errors,"Parallel map failed");return c.results}async function RS(n,i={}){let s=i.retries||3,o=i.retryDelay||1000,c=n.map((l)=>async()=>{let u;for(let h=0;h<=s;h++)try{return await l()}catch(y){if(u=y instanceof Error?y:Error(String(y)),h<s)await Wa(o*(h+1))}throw u});return Md(c,i)}async function DS(n){let i=[];for(let s of n){let o=await s();i.push(o)}return i}function Wa(n){return new Promise((i)=>setTimeout(i,n))}async function PS(n,i,s="Operation timed out"){return Promise.race([n(),new Promise((o,c)=>setTimeout(()=>c(Error(s)),i))])}class BA{maxConcurrent;minInterval;queue=[];running=0;lastExecution=0;constructor(n=5,i=100){this.maxConcurrent=n,this.minInterval=i}async execute(n){await this.waitForSlot(),this.running++,this.lastExecution=Date.now();try{return await n()}finally{this.running--,this.processQueue()}}waitForSlot(){if(this.running<this.maxConcurrent){let n=Date.now()-this.lastExecution;if(n>=this.minInterval)return Promise.resolve();return Wa(this.minInterval-n)}return new Promise((n)=>this.queue.push(n))}processQueue(){if(this.queue.length>0&&this.running<this.maxConcurrent)this.queue.shift()()}stats(){return{running:this.running,queued:this.queue.length}}}function _A(n,i){let s=[];for(let o=0;o<n.length;o+=i)s.push(n.slice(o,o+i));return s}async function NS(n,i,s){let o=_A(n,i),c=[];for(let l of o){let u=await s(l);c.push(...u)}return c}function kS(n,i){let s=[],o=[],c=[],l=[],u=n.Resources||{},h=i.Resources||{},y=new Set(Object.keys(u)),f=new Set(Object.keys(h));for(let v of f)if(!y.has(v))s.push(v);for(let v of y)if(!f.has(v))c.push(v);for(let v of f)if(y.has(v)){let w=u[v],E=h[v];if(JSON.stringify(w)!==JSON.stringify(E))o.push(v);else l.push(v)}let S=JSON.stringify(n.Parameters||{})!==JSON.stringify(i.Parameters||{}),b=JSON.stringify(n.Outputs||{})!==JSON.stringify(i.Outputs||{});return{added:s,modified:o,deleted:c,unchanged:l,parametersChanged:S,outputsChanged:b,hasChanges:s.length>0||o.length>0||c.length>0||S||b}}function BS(n){let i=[];if(!n.hasChanges)return"No changes detected";if(n.added.length>0){i.push(`Added resources (${n.added.length}):`);for(let s of n.added)i.push(` + ${s}`)}if(n.modified.length>0){i.push(`Modified resources (${n.modified.length}):`);for(let s of n.modified)i.push(` ~ ${s}`)}if(n.deleted.length>0){i.push(`Deleted resources (${n.deleted.length}):`);for(let s of n.deleted)i.push(` - ${s}`)}if(n.parametersChanged)i.push("Parameters changed");if(n.outputsChanged)i.push("Outputs changed");return i.join(`
2512
+ `)}function _S(n,i,s){if(n.deleted.length>0)return!0;for(let o of n.modified){let c=i.Resources[o],l=s.Resources[o];if(c.Type!==l.Type)return!0;let u=Wn(l.Type);for(let h of u){let y=c.Properties?.[h],f=l.Properties?.[h];if(JSON.stringify(y)!==JSON.stringify(f))return!0}}return!1}function Wn(n){return{"AWS::S3::Bucket":["BucketName"],"AWS::EC2::Instance":["ImageId","InstanceType","KeyName"],"AWS::RDS::DBInstance":["DBInstanceIdentifier","Engine"],"AWS::DynamoDB::Table":["TableName","KeySchema"],"AWS::Lambda::Function":["FunctionName"],"AWS::ECS::Service":["ServiceName"],"AWS::ElasticLoadBalancingV2::LoadBalancer":["Name","Type"]}[n]||[]}function xS(n){let i=[],s=[],o=[];i.push(...n.added);for(let c of n.modified)s.push(c);return o.push(...n.deleted),{safe:i,caution:s,dangerous:o}}function OS(n){if(!n.hasChanges)return{strategy:"skip",reason:"No changes detected"};if(n.deleted.length>0)return{strategy:"replace",reason:"Resources will be deleted"};if(n.added.length>0&&n.modified.length===0)return{strategy:"update",reason:"Only new resources added"};return{strategy:"update",reason:"Resources will be updated"}}function LS(n){let i=n.added.length+n.modified.length+n.deleted.length+n.unchanged.length,s=n.added.length+n.modified.length+n.deleted.length,o=i>0?s/i*100:0;return{total:i,added:n.added.length,modified:n.modified.length,deleted:n.deleted.length,unchanged:n.unchanged.length,changePercentage:o}}var $S={$schema:"http://json-schema.org/draft-07/schema#",title:"ts-cloud Configuration",description:"Configuration schema for ts-cloud infrastructure-as-code",type:"object",required:["project"],properties:{project:{type:"object",description:"Project configuration",required:["name","slug"],properties:{name:{type:"string",description:"Human-readable project name",minLength:1},slug:{type:"string",description:"URL-safe project identifier (lowercase, alphanumeric, hyphens only)",pattern:"^[a-z0-9-]+$",minLength:1,maxLength:63},region:{type:"string",description:"Default AWS region",enum:["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"]}}},mode:{type:"string",description:"Deployment mode (server and serverless are mutually exclusive; auto-detected when omitted)",enum:["server","serverless"]},environments:{type:"object",description:"Environment-specific configurations",properties:{production:{$ref:"#/definitions/environment"},staging:{$ref:"#/definitions/environment"},development:{$ref:"#/definitions/environment"}}},infrastructure:{type:"object",description:"Infrastructure configuration",properties:{network:{$ref:"#/definitions/network"},storage:{type:"object",description:"S3 storage configuration",additionalProperties:{$ref:"#/definitions/storage"}},compute:{$ref:"#/definitions/compute"},database:{$ref:"#/definitions/database"},cache:{$ref:"#/definitions/cache"},cdn:{$ref:"#/definitions/cdn"},sftp:{$ref:"#/definitions/sftp"},functions:{type:"object",description:"Lambda functions configuration",additionalProperties:{type:"array",items:{$ref:"#/definitions/function"}}},monitoring:{$ref:"#/definitions/monitoring"},security:{$ref:"#/definitions/security"},queue:{type:"object",description:"SQS queue configuration",additionalProperties:{$ref:"#/definitions/queue"}}}}},definitions:{environment:{type:"object",properties:{domain:{type:"string",description:"Custom domain for this environment"},region:{type:"string",description:"AWS region override for this environment"},app:{type:"object",description:"Serverless application manifest (Laravel-Vapor-equivalent). Defining this opts the environment into the serverless app deploy pipeline (http/queue/cli Lambda functions, assets, build/deploy hooks).",properties:{runtime:{type:"string",description:"Lambda runtime override (usually derived from kind + runtimeVersion)"},runtimeVersion:{type:"string",description:"Node major (18/20/22 managed, 24+ custom layer) or Bun release for node/bun apps"},kind:{type:"string",enum:["node","bun","php"],description:"Application kind (drives packaging + runtime)"},entry:{type:"string",description:"Entry file exporting the request handler"},memory:{type:"number",description:"HTTP function memory in MB"},timeout:{type:"number",description:"HTTP request timeout in seconds"},gatewayVersion:{type:"number",enum:[1,2],description:"API Gateway version (2 = HTTP API, 1 = REST)"},warm:{type:"number",description:"Keep-warm / provisioned concurrency count"},lambdaInsights:{type:"object",description:"CloudWatch Lambda Insights extension configuration for zip deployments",required:["layerArn"],properties:{layerArn:{type:"string",description:"Region- and architecture-specific Lambda Insights extension layer ARN"}}},queues:{description:"Queue names (true = single default queue, false = disabled)"},scheduler:{type:"string",enum:["off","on","sub-minute"],description:"Task scheduler mode"},build:{type:"array",items:{type:"string"},description:"Commands run locally before packaging"},deploy:{type:"array",items:{type:"string"},description:"Commands run remotely after activation (e.g. migrations)"},octane:{type:"boolean",description:"Persistent application mode (Laravel Octane)"},packaging:{type:"string",enum:["zip","image"],description:"Deployment package format (zip or container image)"},phpVersion:{type:"string",description:"PHP version for the runtime layer (kind: php)"},architecture:{type:"string",enum:["x86_64","arm64"],description:"CPU architecture"}}}}},network:{type:"object",properties:{vpc:{type:"object",properties:{cidr:{type:"string",description:"VPC CIDR block",pattern:"^([0-9]{1,3}\\.){3}[0-9]{1,3}/[0-9]{1,2}$",default:"10.0.0.0/16"},availabilityZones:{type:"number",description:"Number of availability zones",minimum:1,maximum:3,default:2},natGateways:{type:"number",description:"Number of NAT gateways (0 for no NAT, saves cost)",minimum:0,maximum:3,default:1}}}}},storage:{type:"object",properties:{public:{type:"boolean",description:"Allow public access",default:!1},versioning:{type:"boolean",description:"Enable versioning",default:!1},encryption:{type:"boolean",description:"Enable server-side encryption",default:!0},website:{type:"boolean",description:"Enable static website hosting",default:!1},cors:{type:"object",description:"CORS configuration",properties:{allowedOrigins:{type:"array",items:{type:"string"}},allowedMethods:{type:"array",items:{type:"string",enum:["GET","PUT","POST","DELETE","HEAD"]}}}}}},compute:{type:"object",properties:{server:{type:"object",description:"EC2 server configuration",properties:{instanceType:{type:"string",description:"EC2 instance type",enum:["t3.micro","t3.small","t3.medium","t3.large","t3.xlarge","t3.2xlarge"]},autoScaling:{type:"object",properties:{min:{type:"number",minimum:1},max:{type:"number",minimum:1},desired:{type:"number",minimum:1}}}}},fargate:{type:"object",description:"ECS Fargate configuration",properties:{cpu:{type:"number",description:"CPU units (256, 512, 1024, 2048, 4096)",enum:[256,512,1024,2048,4096]},memory:{type:"number",description:"Memory in MB"},desiredCount:{type:"number",description:"Desired number of tasks",minimum:1}}}}},database:{type:"object",properties:{postgres:{type:"object",properties:{instanceClass:{type:"string",description:"RDS instance class",pattern:"^db\\.[a-z0-9]+\\.[a-z0-9]+$"},engine:{type:"string",const:"postgres"},version:{type:"string",description:"PostgreSQL version"},multiAZ:{type:"boolean",description:"Enable Multi-AZ deployment",default:!1},backupRetentionDays:{type:"number",description:"Backup retention period in days",minimum:0,maximum:35,default:7}}},mysql:{type:"object",properties:{instanceClass:{type:"string",pattern:"^db\\.[a-z0-9]+\\.[a-z0-9]+$"},engine:{type:"string",const:"mysql"},version:{type:"string"},multiAZ:{type:"boolean",default:!1},backupRetentionDays:{type:"number",minimum:0,maximum:35,default:7}}},dynamodb:{type:"object",properties:{tables:{type:"array",items:{type:"object",required:["name","partitionKey"],properties:{name:{type:"string"},partitionKey:{type:"string"},sortKey:{type:"string"},billingMode:{type:"string",enum:["PAY_PER_REQUEST","PROVISIONED"],default:"PAY_PER_REQUEST"}}}}}}}},cache:{type:"object",properties:{redis:{type:"object",properties:{nodeType:{type:"string",description:"ElastiCache node type",pattern:"^cache\\.[a-z0-9]+\\.[a-z0-9]+$"},numCacheNodes:{type:"number",minimum:1,default:1},engineVersion:{type:"string",description:"Redis engine version"}}},memcached:{type:"object",properties:{nodeType:{type:"string",pattern:"^cache\\.[a-z0-9]+\\.[a-z0-9]+$"},numCacheNodes:{type:"number",minimum:1,default:1}}}}},cdn:{type:"object",properties:{enabled:{type:"boolean",default:!0},originShield:{type:"boolean",description:"Enable CloudFront Origin Shield",default:!1},originShieldRegion:{type:"string",description:"AWS region used by CloudFront Origin Shield"},compress:{type:"boolean",description:"Enable automatic compression",default:!0},http3:{type:"boolean",description:"Enable HTTP/3 support",default:!0},customDomain:{type:"object",properties:{domain:{type:"string"},certificateArn:{type:"string"}}},cachePolicy:{type:"object",properties:{minTTL:{type:"number",minimum:0},defaultTTL:{type:"number",minimum:0},maxTTL:{type:"number",minimum:0}}}}},sftp:{type:"object",required:["bucket","users"],properties:{bucket:{type:"string",description:"S3 bucket backing the SFTP server"},endpointType:{type:"string",enum:["PUBLIC","VPC"],default:"PUBLIC"},endpointDetails:{type:"object",required:["vpcId","subnetIds"],properties:{vpcId:{type:"string"},subnetIds:{type:"array",items:{type:"string"},minItems:1},securityGroupIds:{type:"array",items:{type:"string"}},addressAllocationIds:{type:"array",items:{type:"string"}}}},securityPolicyName:{type:"string"},logging:{type:"boolean",default:!0},users:{type:"object",additionalProperties:{type:"object",required:["sshPublicKeys"],properties:{sshPublicKeys:{type:"array",items:{type:"string"},minItems:1},homeDirectory:{type:"string"},roleArn:{type:"string"}}}}}},function:{type:"object",required:["name","runtime"],properties:{name:{type:"string"},runtime:{type:"string",enum:["nodejs18.x","nodejs20.x","python3.10","python3.11","python3.12"]},handler:{type:"string",default:"index.handler"},timeout:{type:"number",minimum:1,maximum:900,default:30},memory:{type:"number",minimum:128,maximum:10240,default:1024}}},monitoring:{type:"object",properties:{alarms:{type:"array",items:{type:"object",required:["metric","threshold"],properties:{metric:{type:"string"},threshold:{type:"number"},evaluationPeriods:{type:"number",minimum:1,default:2}}}},dashboard:{type:"object",properties:{name:{type:"string"},widgets:{type:"array"}}}}},security:{type:"object",properties:{waf:{type:"boolean",description:"Enable AWS WAF",default:!1},certificates:{type:"array",items:{type:"object",required:["domain"],properties:{domain:{type:"string"},subdomains:{type:"array",items:{type:"string"}}}}}}},queue:{type:"object",properties:{fifo:{type:"boolean",default:!1},deadLetterQueue:{type:"boolean",default:!0},visibilityTimeout:{type:"number",minimum:0,maximum:43200,default:30},messageRetentionPeriod:{type:"number",minimum:60,maximum:1209600,default:345600}}}}};function MS(n){let i=[];if(!n.project)i.push("Missing required field: project");else{if(!n.project.name)i.push("Missing required field: project.name");if(!n.project.slug)i.push("Missing required field: project.slug")}if(n.project?.slug&&!/^[a-z0-9-]+$/.test(n.project.slug))i.push("Invalid project.slug: must contain only lowercase letters, numbers, and hyphens");let s=["us-east-1","us-east-2","us-west-1","us-west-2","eu-west-1","eu-west-2","eu-west-3","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-northeast-2","sa-east-1","ca-central-1"];if(n.project?.region&&!s.includes(n.project.region))i.push(`Invalid region: ${n.project.region}. Must be one of: ${s.join(", ")}`);if(n.mode&&!["server","serverless"].includes(n.mode))i.push("Invalid mode: must be one of server or serverless");return{valid:i.length===0,errors:i}}var _g={enabled:process.env.TS_CLOUD_LOCAL==="true"||!0,localstackEndpoint:process.env.LOCALSTACK_ENDPOINT||"http://localhost:4566",postgresUrl:process.env.POSTGRES_URL||"postgresql://tscloud:tscloud@localhost:5432/tscloud",redisUrl:process.env.REDIS_URL||"redis://localhost:6379",dynamodbEndpoint:process.env.DYNAMODB_ENDPOINT||"http://localhost:8000",s3Endpoint:process.env.S3_ENDPOINT||"http://localhost:9000",emailEndpoint:process.env.EMAIL_ENDPOINT||"smtp://localhost:1025",awsRegion:process.env.AWS_REGION||"us-east-1",awsAccessKeyId:process.env.AWS_ACCESS_KEY_ID||"test",awsSecretAccessKey:process.env.AWS_SECRET_ACCESS_KEY||"test"};function Fd(){return _g}function FS(){return _g.enabled}function US(n){let i=Fd();if(!i.enabled)return"";switch(n.toLowerCase()){case"dynamodb":return i.dynamodbEndpoint;case"s3":return i.s3Endpoint;case"localstack":case"cloudformation":case"lambda":case"apigateway":case"sns":case"sqs":case"cloudwatch":case"iam":case"sts":return i.localstackEndpoint;default:return i.localstackEndpoint}}function QS(){let n=Fd();return{accessKeyId:n.awsAccessKeyId,secretAccessKey:n.awsSecretAccessKey,region:n.awsRegion}}function HS(){let n=Fd();if(!n.enabled)return{};return{AWS_ACCESS_KEY_ID:n.awsAccessKeyId,AWS_SECRET_ACCESS_KEY:n.awsSecretAccessKey,AWS_REGION:n.awsRegion,AWS_ENDPOINT_URL:n.localstackEndpoint,LOCALSTACK_ENDPOINT:n.localstackEndpoint,TS_CLOUD_LOCAL:"true"}}class xg{stacks=new Map;stackEvents=new Map;async createStack(n){let i=`arn:aws:cloudformation:${n.region||"us-east-1"}:123456789012:stack/${n.StackName}/${Date.now()}`;return this.stacks.set(n.StackName,{StackId:i,StackName:n.StackName,StackStatus:"CREATE_IN_PROGRESS",CreationTime:new Date().toISOString(),TemplateBody:n.TemplateBody,Parameters:n.Parameters||[]}),this.addEvent(n.StackName,{EventId:Date.now().toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_IN_PROGRESS"}),setTimeout(()=>{let s=this.stacks.get(n.StackName);if(s)s.StackStatus="CREATE_COMPLETE",this.addEvent(n.StackName,{EventId:(Date.now()+1).toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"CREATE_COMPLETE"})},100),{StackId:i}}async updateStack(n){let i=this.stacks.get(n.StackName);if(!i)throw Error(`Stack ${n.StackName} does not exist`);return i.StackStatus="UPDATE_IN_PROGRESS",i.TemplateBody=n.TemplateBody||i.TemplateBody,this.addEvent(n.StackName,{EventId:Date.now().toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_IN_PROGRESS"}),setTimeout(()=>{i.StackStatus="UPDATE_COMPLETE",this.addEvent(n.StackName,{EventId:(Date.now()+1).toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"UPDATE_COMPLETE"})},100),{StackId:i.StackId}}async deleteStack(n){let i=this.stacks.get(n.StackName);if(!i)throw Error(`Stack ${n.StackName} does not exist`);i.StackStatus="DELETE_IN_PROGRESS",this.addEvent(n.StackName,{EventId:Date.now().toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_IN_PROGRESS"}),setTimeout(()=>{this.stacks.delete(n.StackName),this.addEvent(n.StackName,{EventId:(Date.now()+1).toString(),StackName:n.StackName,LogicalResourceId:n.StackName,ResourceType:"AWS::CloudFormation::Stack",Timestamp:new Date().toISOString(),ResourceStatus:"DELETE_COMPLETE"})},100)}async describeStacks(n){if(n.StackName){let i=this.stacks.get(n.StackName);if(!i)throw Error(`Stack ${n.StackName} does not exist`);return{Stacks:[i]}}return{Stacks:Array.from(this.stacks.values())}}async describeStackEvents(n){return{StackEvents:this.stackEvents.get(n.StackName)||[]}}addEvent(n,i){if(!this.stackEvents.has(n))this.stackEvents.set(n,[]);this.stackEvents.get(n).unshift(i)}reset(){this.stacks.clear(),this.stackEvents.clear()}}class Og{buckets=new Map;async createBucket(n){return this.buckets.set(n.Bucket,new Map),{Location:`/${n.Bucket}`}}async deleteBucket(n){this.buckets.delete(n.Bucket)}async putObject(n){let i=this.buckets.get(n.Bucket);if(!i)i=new Map,this.buckets.set(n.Bucket,i);return i.set(n.Key,Buffer.from(n.Body||"")),{ETag:`"${Date.now()}"`}}async getObject(n){let i=this.buckets.get(n.Bucket);if(!i)throw Error(`Bucket ${n.Bucket} does not exist`);let s=i.get(n.Key);if(!s)throw Error(`Object ${n.Key} does not exist`);return{Body:s,ContentLength:s.length}}async deleteObject(n){let i=this.buckets.get(n.Bucket);if(i)i.delete(n.Key)}async listObjects(n){let i=this.buckets.get(n.Bucket);if(!i)throw Error(`Bucket ${n.Bucket} does not exist`);return{Contents:Array.from(i.keys()).map((s)=>({Key:s,Size:i.get(s).length,LastModified:new Date().toISOString()}))}}reset(){this.buckets.clear()}}class Lg{tables=new Map;data=new Map;async createTable(n){return this.tables.set(n.TableName,{TableName:n.TableName,KeySchema:n.KeySchema,AttributeDefinitions:n.AttributeDefinitions,TableStatus:"ACTIVE",CreationDateTime:new Date().toISOString()}),this.data.set(n.TableName,new Map),{TableDescription:this.tables.get(n.TableName)}}async deleteTable(n){this.tables.delete(n.TableName),this.data.delete(n.TableName)}async putItem(n){let i=this.data.get(n.TableName);if(!i)i=new Map,this.data.set(n.TableName,i);let s=JSON.stringify(n.Item);i.set(s,n.Item)}async getItem(n){let i=this.data.get(n.TableName);if(!i)return{};let s=JSON.stringify(n.Key),o=i.get(s);return o?{Item:o}:{}}async deleteItem(n){let i=this.data.get(n.TableName);if(i){let s=JSON.stringify(n.Key);i.delete(s)}}async scan(n){let i=this.data.get(n.TableName);if(!i)return{Items:[]};return{Items:Array.from(i.values())}}reset(){this.tables.clear(),this.data.clear()}}function GS(n){return{cloudformation:new xg,s3:new Og,dynamodb:new Lg}}class $g{environments=new Map;async createPreviewEnvironment(n){let{branch:i,pr:s,commitSha:o,ttl:c=24,baseConfig:l,region:u="us-east-1"}=n,h=this.generatePreviewId(i,s,o),y=this.generatePreviewName(i,s),f=`preview-${y}`,S=new Date,b=new Date(S.getTime()+c*60*60*1000),v={id:h,name:y,branch:i,pr:s,commitSha:o,createdAt:S,expiresAt:b,status:"creating",stackName:f,region:u,resources:[]};this.environments.set(h,v);try{let w=this.createPreviewConfig(l,y);return v.status="active",v.url=`https://${y}.preview.example.com`,v}catch(w){throw v.status="failed",w}}async destroyPreviewEnvironment(n){let i=this.environments.get(n);if(!i)throw Error(`Preview environment ${n} not found`);i.status="destroying";try{i.status="destroyed",this.environments.delete(n)}catch(s){throw Error(`Failed to destroy preview environment: ${s}`)}}getPreviewEnvironment(n){return this.environments.get(n)}getPreviewEnvironmentByBranch(n){return Array.from(this.environments.values()).find((i)=>i.branch===n)}getPreviewEnvironmentByPR(n){return Array.from(this.environments.values()).find((i)=>i.pr===n)}listPreviewEnvironments(){return Array.from(this.environments.values())}listActivePreviewEnvironments(){return this.listPreviewEnvironments().filter((n)=>n.status==="active")}async cleanupExpiredEnvironments(n={}){let{maxAge:i,keepCount:s,dryRun:o=!1}=n,c=[],l=[],u=new Date,h=this.listPreviewEnvironments().sort((y,f)=>f.createdAt.getTime()-y.createdAt.getTime());for(let y=0;y<h.length;y++){let f=h[y];if(f.status!=="active")continue;let S=!1;if(f.expiresAt<u)S=!0;if(i){if((u.getTime()-f.createdAt.getTime())/3600000>i)S=!0}if(s&&y>=s)S=!0;if(S)if(o)c.push(f.id);else try{await this.destroyPreviewEnvironment(f.id),c.push(f.id)}catch(b){l.push(f.id)}}return{destroyed:c,failed:l}}async updatePreviewEnvironment(n,i){let s=this.environments.get(n);if(!s)throw Error(`Preview environment ${n} not found`);s.commitSha=i,s.status="creating";try{return s.status="active",s}catch(o){throw s.status="failed",o}}async getPreviewEnvironmentsCost(){let n={},i=0;for(let s of this.environments.values())n[s.id]=0,i+=0;return{total:i,byEnvironment:n}}generatePreviewId(n,i,s){let o=n.replace(/[^a-z0-9-]/gi,"-").toLowerCase(),c=s?.substring(0,7)||Date.now().toString();return i?`pr-${i}-${c}`:`${o}-${c}`}generatePreviewName(n,i){let s=n.replace(/[^a-z0-9-]/gi,"-").toLowerCase();return i?`pr-${i}`:s}createPreviewConfig(n,i){return{...n,project:{...n.project,name:`${n.project.name} Preview (${i})`,slug:`${n.project.slug}-preview-${i}`}}}}var qS=new $g;function VS(n={}){let{workflowName:i="Preview Environment",trigger:s="pull_request",branches:o=["main","develop"],awsRegion:c="us-east-1",awsRole:l,configFile:u="cloud.config.ts",ttl:h=24}=n;return`name: ${i}
2513
2513
 
2514
2514
  on:
2515
2515
  ${s}:
@@ -2737,9 +2737,9 @@ jobs:
2737
2737
  curl -X POST -H 'Content-type: application/json' \\
2738
2738
  --data '{"text":"Preview Environment Cost Report\\n\${{ steps.cost.outputs.cost_json }}"}' \\
2739
2739
  $SLACK_WEBHOOK_URL`:'run: |\n echo "${{ steps.cost.outputs.cost_json }}"'}
2740
- `}class Mg{channels=[];addChannel(n){this.channels.push(n)}removeChannel(n){this.channels=this.channels.filter((i)=>i.type!==n)}async notify(n){let i=this.channels.map((s)=>this.sendToChannel(s,n));await Promise.allSettled(i)}async sendToChannel(n,i){switch(n.type){case"slack":await this.sendToSlack(n.config,i);break;case"discord":await this.sendToDiscord(n.config,i);break;case"email":await this.sendToEmail(n.config,i);break;case"webhook":await this.sendToWebhook(n.config,i);break}}async sendToSlack(n,i){let s=this.formatSlackMessage(i,n),o=await fetch(n.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!o.ok)throw Error(`Failed to send Slack notification: ${o.statusText}`)}formatSlackMessage(n,i){let{environment:s,type:o}=n,c={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass_flowing_sand:"}[o],l={created:"#36a64f",updated:"#2196F3",destroyed:"#808080",failed:"#f44336",expired:"#ff9800"}[o],u={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[o];return{username:i.username||"ts-cloud",icon_emoji:i.iconEmoji||":cloud:",channel:i.channel,attachments:[{color:l,title:`${c} ${u}`,fields:[{title:"Environment",value:s.name,short:!0},{title:"Branch",value:s.branch,short:!0},...s.pr?[{title:"PR",value:`#${s.pr}`,short:!0}]:[],{title:"Commit",value:s.commitSha.substring(0,7),short:!0},...s.url?[{title:"URL",value:s.url,short:!1}]:[],...o==="created"?[{title:"Expires",value:s.expiresAt.toLocaleString(),short:!0}]:[]],footer:"ts-cloud Preview Environments",ts:Math.floor(n.timestamp.getTime()/1000)}]}}async sendToDiscord(n,i){let s=this.formatDiscordMessage(i,n),o=await fetch(n.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!o.ok)throw Error(`Failed to send Discord notification: ${o.statusText}`)}formatDiscordMessage(n,i){let{environment:s,type:o}=n,c={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass:"}[o],l={created:3581519,updated:2201331,destroyed:8421504,failed:16007990,expired:16750592}[o],u={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[o];return{username:i.username||"ts-cloud",avatar_url:i.avatarUrl,embeds:[{title:`${c} ${u}`,color:l,fields:[{name:"Environment",value:s.name,inline:!0},{name:"Branch",value:s.branch,inline:!0},...s.pr?[{name:"PR",value:`#${s.pr}`,inline:!0}]:[],{name:"Commit",value:`\`${s.commitSha.substring(0,7)}\``,inline:!0},...s.url?[{name:"URL",value:s.url,inline:!1}]:[]],timestamp:n.timestamp.toISOString(),footer:{text:"ts-cloud Preview Environments"}}]}}async sendToEmail(n,i){console.log(`Email notification would be sent to ${n.to.join(", ")}`)}async sendToWebhook(n,i){let s=await fetch(n.url,{method:n.method||"POST",headers:{"Content-Type":"application/json",...n.headers},body:JSON.stringify({event:i.type,environment:i.environment,timestamp:i.timestamp.toISOString(),metadata:i.metadata})});if(!s.ok)throw Error(`Failed to send webhook notification: ${s.statusText}`)}}var KS=new Mg;function WS(n){let{columns:i,data:s,border:o=!0,header:c=!0,compact:l=!1,maxWidth:u}=n;if(s.length===0)return"No data to display";let h=i.map((f)=>{let b=f.label.length,C=Math.max(...s.map((w)=>(f.formatter?f.formatter(w[f.key]):String(w[f.key]||"")).length)),T=f.width||Math.max(b,C);if(u&&T>u)T=u;return T}),y=[];if(o)y.push(Lt(h,"top",l));if(c){if(y.push(Sa(i.map((f)=>f.label),h,i.map((f)=>f.align||"left"),o)),o)y.push(Lt(h,"middle",l))}for(let f of s){let b=i.map((C)=>{let T=C.formatter?C.formatter(f[C.key]):String(f[C.key]||"");return Fn(T,h[i.indexOf(C)])});y.push(Sa(b,h,i.map((C)=>C.align||"left"),o))}if(o)y.push(Lt(h,"bottom",l));return y.join(`
2741
- `)}function Sa(n,i,s,o){let c=n.map((l,u)=>{let h=i[u],y=s[u];return Gn(l,h,y)});if(o)return`│ ${c.join(" │ ")} │`;return c.join(" ")}function Lt(n,i,s){let o=i==="top"?"┌":i==="middle"?"├":"└",c=i==="top"?"┐":i==="middle"?"┤":"┘",l=i==="top"?"┬":i==="middle"?"┼":"┴",u="─";if(s)return o+n.map((h)=>"─".repeat(h+2)).join(l)+c;return o+n.map((h)=>"─".repeat(h+2)).join(l)+c}function Gn(n,i,s){let o=Ga(n).length;if(o>=i)return n;let c=i-o;switch(s){case"right":return" ".repeat(c)+n;case"center":{let l=Math.floor(c/2),u=c-l;return" ".repeat(l)+n+" ".repeat(u)}default:return n+" ".repeat(c)}}function Fn(n,i){if(Ga(n).length<=i)return n;return n.substring(0,i-1)+"…"}function Ga(n){return n.replace(/\x1B\[[0-9;]*m/g,"")}function JS(n,i={}){let{indent:s=" ",showMetadata:o=!1}=i,c=[];function l(u,h,y){let f=h+(y?"└─ ":"├─ ")+u.label;if(c.push(f),o&&u.metadata){let b=h+(y?" ":"│ ");for(let[C,T]of Object.entries(u.metadata))c.push(`${b}${C}: ${T}`)}if(u.children&&u.children.length>0){let b=h+(y?" ":"│ ");u.children.forEach((C,T)=>{l(C,b,T===u.children.length-1)})}}return n.forEach((u,h)=>{l(u,"",h===n.length-1)}),c.join(`
2742
- `)}function XS(n){let{total:i,current:s,width:o=40,format:c=":bar :percent :current/:total",complete:l="█",incomplete:u="░"}=n,h=Math.min(100,Math.max(0,s/i*100)),y=Math.floor(o*s/i),f=o-y,b=l.repeat(y)+u.repeat(f);return c.replace(":bar",b).replace(":percent",`${h.toFixed(0)}%`).replace(":current",String(s)).replace(":total",String(i))}function YS(n,i=2){if(n===0)return"0 Bytes";let s=1024,o=i<0?0:i,c=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],l=Math.floor(Math.log(n)/Math.log(s));return`${Number.parseFloat((n/Math.pow(s,l)).toFixed(o))} ${c[l]}`}function ZS(n){if(n<1000)return`${n}ms`;let i=Math.floor(n/1000);if(i<60)return`${i}s`;let s=Math.floor(i/60),o=i%60;if(s<60)return o>0?`${s}m ${o}s`:`${s}m`;let c=Math.floor(s/60),l=s%60;if(c<24)return l>0?`${c}h ${l}m`:`${c}h`;let u=Math.floor(c/24),h=c%24;return h>0?`${u}d ${h}h`:`${u}d`}function eC(n,i="•"){return n.map((s)=>`${i} ${s}`).join(`
2740
+ `}class Mg{channels=[];addChannel(n){this.channels.push(n)}removeChannel(n){this.channels=this.channels.filter((i)=>i.type!==n)}async notify(n){let i=this.channels.map((s)=>this.sendToChannel(s,n));await Promise.allSettled(i)}async sendToChannel(n,i){switch(n.type){case"slack":await this.sendToSlack(n.config,i);break;case"discord":await this.sendToDiscord(n.config,i);break;case"email":await this.sendToEmail(n.config,i);break;case"webhook":await this.sendToWebhook(n.config,i);break}}async sendToSlack(n,i){let s=this.formatSlackMessage(i,n),o=await fetch(n.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!o.ok)throw Error(`Failed to send Slack notification: ${o.statusText}`)}formatSlackMessage(n,i){let{environment:s,type:o}=n,c={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass_flowing_sand:"}[o],l={created:"#36a64f",updated:"#2196F3",destroyed:"#808080",failed:"#f44336",expired:"#ff9800"}[o],u={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[o];return{username:i.username||"ts-cloud",icon_emoji:i.iconEmoji||":cloud:",channel:i.channel,attachments:[{color:l,title:`${c} ${u}`,fields:[{title:"Environment",value:s.name,short:!0},{title:"Branch",value:s.branch,short:!0},...s.pr?[{title:"PR",value:`#${s.pr}`,short:!0}]:[],{title:"Commit",value:s.commitSha.substring(0,7),short:!0},...s.url?[{title:"URL",value:s.url,short:!1}]:[],...o==="created"?[{title:"Expires",value:s.expiresAt.toLocaleString(),short:!0}]:[]],footer:"ts-cloud Preview Environments",ts:Math.floor(n.timestamp.getTime()/1000)}]}}async sendToDiscord(n,i){let s=this.formatDiscordMessage(i,n),o=await fetch(n.webhookUrl,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!o.ok)throw Error(`Failed to send Discord notification: ${o.statusText}`)}formatDiscordMessage(n,i){let{environment:s,type:o}=n,c={created:":rocket:",updated:":arrows_counterclockwise:",destroyed:":wastebasket:",failed:":x:",expired:":hourglass:"}[o],l={created:3581519,updated:2201331,destroyed:8421504,failed:16007990,expired:16750592}[o],u={created:"Preview Environment Created",updated:"Preview Environment Updated",destroyed:"Preview Environment Destroyed",failed:"Preview Environment Failed",expired:"Preview Environment Expired"}[o];return{username:i.username||"ts-cloud",avatar_url:i.avatarUrl,embeds:[{title:`${c} ${u}`,color:l,fields:[{name:"Environment",value:s.name,inline:!0},{name:"Branch",value:s.branch,inline:!0},...s.pr?[{name:"PR",value:`#${s.pr}`,inline:!0}]:[],{name:"Commit",value:`\`${s.commitSha.substring(0,7)}\``,inline:!0},...s.url?[{name:"URL",value:s.url,inline:!1}]:[]],timestamp:n.timestamp.toISOString(),footer:{text:"ts-cloud Preview Environments"}}]}}async sendToEmail(n,i){console.log(`Email notification would be sent to ${n.to.join(", ")}`)}async sendToWebhook(n,i){let s=await fetch(n.url,{method:n.method||"POST",headers:{"Content-Type":"application/json",...n.headers},body:JSON.stringify({event:i.type,environment:i.environment,timestamp:i.timestamp.toISOString(),metadata:i.metadata})});if(!s.ok)throw Error(`Failed to send webhook notification: ${s.statusText}`)}}var KS=new Mg;function WS(n){let{columns:i,data:s,border:o=!0,header:c=!0,compact:l=!1,maxWidth:u}=n;if(s.length===0)return"No data to display";let h=i.map((f)=>{let S=f.label.length,b=Math.max(...s.map((w)=>(f.formatter?f.formatter(w[f.key]):String(w[f.key]||"")).length)),v=f.width||Math.max(S,b);if(u&&v>u)v=u;return v}),y=[];if(o)y.push(Lt(h,"top",l));if(c){if(y.push(Sa(i.map((f)=>f.label),h,i.map((f)=>f.align||"left"),o)),o)y.push(Lt(h,"middle",l))}for(let f of s){let S=i.map((b)=>{let v=b.formatter?b.formatter(f[b.key]):String(f[b.key]||"");return Fn(v,h[i.indexOf(b)])});y.push(Sa(S,h,i.map((b)=>b.align||"left"),o))}if(o)y.push(Lt(h,"bottom",l));return y.join(`
2741
+ `)}function Sa(n,i,s,o){let c=n.map((l,u)=>{let h=i[u],y=s[u];return Gn(l,h,y)});if(o)return`│ ${c.join(" │ ")} │`;return c.join(" ")}function Lt(n,i,s){let o=i==="top"?"┌":i==="middle"?"├":"└",c=i==="top"?"┐":i==="middle"?"┤":"┘",l=i==="top"?"┬":i==="middle"?"┼":"┴",u="─";if(s)return o+n.map((h)=>"─".repeat(h+2)).join(l)+c;return o+n.map((h)=>"─".repeat(h+2)).join(l)+c}function Gn(n,i,s){let o=Ga(n).length;if(o>=i)return n;let c=i-o;switch(s){case"right":return" ".repeat(c)+n;case"center":{let l=Math.floor(c/2),u=c-l;return" ".repeat(l)+n+" ".repeat(u)}default:return n+" ".repeat(c)}}function Fn(n,i){if(Ga(n).length<=i)return n;return n.substring(0,i-1)+"…"}function Ga(n){return n.replace(/\x1B\[[0-9;]*m/g,"")}function JS(n,i={}){let{indent:s=" ",showMetadata:o=!1}=i,c=[];function l(u,h,y){let f=h+(y?"└─ ":"├─ ")+u.label;if(c.push(f),o&&u.metadata){let S=h+(y?" ":"│ ");for(let[b,v]of Object.entries(u.metadata))c.push(`${S}${b}: ${v}`)}if(u.children&&u.children.length>0){let S=h+(y?" ":"│ ");u.children.forEach((b,v)=>{l(b,S,v===u.children.length-1)})}}return n.forEach((u,h)=>{l(u,"",h===n.length-1)}),c.join(`
2742
+ `)}function XS(n){let{total:i,current:s,width:o=40,format:c=":bar :percent :current/:total",complete:l="█",incomplete:u="░"}=n,h=Math.min(100,Math.max(0,s/i*100)),y=Math.floor(o*s/i),f=o-y,S=l.repeat(y)+u.repeat(f);return c.replace(":bar",S).replace(":percent",`${h.toFixed(0)}%`).replace(":current",String(s)).replace(":total",String(i))}function YS(n,i=2){if(n===0)return"0 Bytes";let s=1024,o=i<0?0:i,c=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],l=Math.floor(Math.log(n)/Math.log(s));return`${Number.parseFloat((n/Math.pow(s,l)).toFixed(o))} ${c[l]}`}function ZS(n){if(n<1000)return`${n}ms`;let i=Math.floor(n/1000);if(i<60)return`${i}s`;let s=Math.floor(i/60),o=i%60;if(s<60)return o>0?`${s}m ${o}s`:`${s}m`;let c=Math.floor(s/60),l=s%60;if(c<24)return l>0?`${c}h ${l}m`:`${c}h`;let u=Math.floor(c/24),h=c%24;return h>0?`${u}d ${h}h`:`${u}d`}function eC(n,i="•"){return n.map((s)=>`${i} ${s}`).join(`
2743
2743
  `)}function tC(n,i={}){let{indent:s="",separator:o=": "}=i,c=Math.max(...Object.keys(n).map((l)=>l.length));return Object.entries(n).map(([l,u])=>{let h=l.padEnd(c);return`${s}${h}${o}${u}`}).join(`
2744
2744
  `)}class xA{total;current=0;width;format;message;showETA;showPercentage;showCounter;startTime=Date.now();lastUpdate=0;constructor(n){this.total=n.total,this.current=n.current||0,this.width=n.width||40,this.format=n.format||":message :bar :percent :eta",this.message=n.message||"Progress",this.showETA=n.showETA!==!1,this.showPercentage=n.showPercentage!==!1,this.showCounter=n.showCounter!==!1}tick(n=1){this.current=Math.min(this.total,this.current+n),this.lastUpdate=Date.now()}update(n){this.current=Math.min(this.total,Math.max(0,n)),this.lastUpdate=Date.now()}setMessage(n){this.message=n}getPercentage(){return Math.min(100,this.current/this.total*100)}getETA(){if(this.current===0)return 0;let n=Date.now()-this.startTime,i=this.current/n,s=this.total-this.current;return Math.round(s/i)}getETAFormatted(){if(this.current===0)return"calculating...";if(this.current===this.total)return"complete";let n=this.getETA();if(n<1000)return"< 1s";if(n<60000)return`${Math.round(n/1000)}s`;let i=Math.floor(n/60000);if(i<60)return`${i}m`;let s=Math.floor(i/60),o=i%60;if(s<24)return o>0?`${s}h ${o}m`:`${s}h`;let c=Math.floor(s/24),l=s%24;return l>0?`${c}d ${l}h`:`${c}d`}render(){let n=this.getPercentage(),i=Math.floor(this.width*this.current/this.total),s=this.width-i,o="█".repeat(i)+"░".repeat(s),c=`${n.toFixed(1)}%`,l=`${this.current}/${this.total}`,u=this.showETA?`ETA: ${this.getETAFormatted()}`:"",h=this.format.replace(":message",this.message).replace(":bar",o).replace(":percent",this.showPercentage?c:"").replace(":counter",this.showCounter?l:"").replace(":eta",u).replace(":current",String(this.current)).replace(":total",String(this.total));return h=h.replace(/\s+/g," ").trim(),h}isComplete(){return this.current>=this.total}}class OA{steps;currentStepIndex=0;constructor(n){this.steps=n.map((i)=>({name:i,status:"pending"}))}startStep(n,i){if(n>=0&&n<this.steps.length)this.steps[n].status="active",this.steps[n].message=i,this.currentStepIndex=n}completeStep(n){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="completed",this.steps[this.currentStepIndex].message=n,this.currentStepIndex++}failStep(n){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="failed",this.steps[this.currentStepIndex].error=n}skipStep(n){if(this.currentStepIndex>=0&&this.currentStepIndex<this.steps.length)this.steps[this.currentStepIndex].status="skipped",this.steps[this.currentStepIndex].message=n,this.currentStepIndex++}getStep(n){return this.steps[n]}getSteps(){return this.steps}render(){let n=[];for(let i of this.steps){let s=`${this.getStatusIcon(i.status)} ${i.name}`;if(i.message)s+=` - ${i.message}`;if(i.error)s+=`
2745
2745
  Error: ${i.error}`;n.push(s)}return n.join(`
@@ -2759,16 +2759,16 @@ ${i.map((s)=>` • ${s}`).join(`
2759
2759
  `)}function lC(n,i,s=[]){let o={valid:!0,errors:[],warnings:[],suggestions:[]},[c,...l]=n.split(" ");if(!i.includes(c)){o.valid=!1,o.errors.push(`Unknown command: ${c}`);let u=Fg(c,i);if(u.length>0)o.suggestions.push(...u)}for(let u of s)if(!l.some((h)=>h===`--${u}`||h.startsWith(`--${u}=`)))o.valid=!1,o.errors.push(`Missing required flag: --${u}`);return o}class MA{options;running=!1;history={commands:[],maxSize:1000};historyIndex=-1;constructor(n){this.options={prompt:n.prompt||"> ",welcome:n.welcome||'Welcome to ts-cloud interactive mode. Type "help" for available commands.',...n}}async start(){if(this.running=!0,this.options.welcome)console.log(this.options.welcome),console.log("");if(this.options.historyFile)await this.loadHistory();while(this.running)try{let n=await this.readInput();if(!n.trim())continue;this.addToHistory(n),await this.executeCommand(n)}catch(n){if(n instanceof Error)console.error(`Error: ${n.message}`)}if(this.options.historyFile)await this.saveHistory()}stop(){this.running=!1}async readInput(){return new Promise((n)=>{process.stdout.write(this.options.prompt||"> "),n("")})}async executeCommand(n){let[i,...s]=this.parseCommand(n);if(i==="exit"||i==="quit"){this.stop();return}if(i==="help"){this.showHelp();return}if(i==="history"){this.showHistory();return}if(i==="clear"){console.clear();return}let o=this.findCommand(i);if(!o){console.error(`Unknown command: ${i}`),console.log('Type "help" to see available commands.');return}try{await o.handler(s)}catch(c){if(c instanceof Error)console.error(`Command failed: ${c.message}`)}}parseCommand(n){return n.trim().split(/\s+/)}findCommand(n){for(let[i,s]of this.options.commands)if(s.name===n||s.aliases?.includes(n))return s;return}showHelp(){console.log("Available commands:"),console.log("");let n=Array.from(this.options.commands.values());console.log(" help Show this help message"),console.log(" history Show command history"),console.log(" clear Clear screen"),console.log(" exit, quit Exit interactive mode"),console.log("");for(let i of n){let s=` ${i.name.padEnd(20)} ${i.description}`;if(i.aliases&&i.aliases.length>0)s+=` (aliases: ${i.aliases.join(", ")})`;console.log(s)}}showHistory(){if(this.history.commands.length===0){console.log("No command history");return}console.log("Command history:"),this.history.commands.forEach((n,i)=>{console.log(` ${(i+1).toString().padStart(4)} ${n}`)})}addToHistory(n){if(this.history.commands[this.history.commands.length-1]===n)return;if(this.history.commands.push(n),this.history.commands.length>this.history.maxSize)this.history.commands=this.history.commands.slice(-this.history.maxSize);this.historyIndex=this.history.commands.length}historyBack(){if(this.historyIndex>0)return this.historyIndex--,this.history.commands[this.historyIndex];return}historyForward(){if(this.historyIndex<this.history.commands.length-1)return this.historyIndex++,this.history.commands[this.historyIndex];return this.historyIndex=this.history.commands.length,""}autocomplete(n){let i=[],s=["help","history","clear","exit","quit"];for(let o of s)if(o.startsWith(n))i.push(o);for(let[o,c]of this.options.commands){if(c.name.startsWith(n))i.push(c.name);if(c.aliases){for(let l of c.aliases)if(l.startsWith(n))i.push(l)}}return i}async loadHistory(){if(!this.options.historyFile)return;try{let n=await import("node:fs/promises"),i=await n.readFile(this.options.historyFile,"utf-8");this.history.commands=i.split(`
2760
2760
  `).filter((s)=>s.trim()),this.historyIndex=this.history.commands.length}catch{}}async saveHistory(){if(!this.options.historyFile)return;try{let n=await import("node:fs/promises");await n.writeFile(this.options.historyFile,this.history.commands.join(`
2761
2761
  `))}catch(n){console.error(`Failed to save history: ${n}`)}}searchHistory(n){return this.history.commands.filter((i)=>i.includes(n))}clearHistory(){this.history.commands=[],this.historyIndex=0}}class FA{variables=new Map;workingDirectory=process.cwd();set(n,i){this.variables.set(n,i)}get(n){return this.variables.get(n)}has(n){return this.variables.has(n)}delete(n){this.variables.delete(n)}getAll(){return Object.fromEntries(this.variables)}clear(){this.variables.clear()}setWorkingDirectory(n){this.workingDirectory=n}getWorkingDirectory(){return this.workingDirectory}}class UA{command={};name(n){return this.command.name=n,this}description(n){return this.command.description=n,this}aliases(...n){return this.command.aliases=n,this}handler(n){return this.command.handler=n,this}autocomplete(n){return this.command.autocomplete=n,this}build(){if(!this.command.name||!this.command.description||!this.command.handler)throw Error("Command must have name, description, and handler");return this.command}}class QA{entries=[];maxSize;persistFile;trackOutput;constructor(n={}){this.maxSize=n.maxSize||1000,this.persistFile=n.persistFile,this.trackOutput=n.trackOutput||!1}add(n){if(this.entries.push({...n,timestamp:new Date}),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}getAll(){return[...this.entries]}getRecent(n=10){return this.entries.slice(-n)}search(n){let i=n.toLowerCase();return this.entries.filter((s)=>s.command.toLowerCase().includes(i))}searchByDate(n,i){return this.entries.filter((s)=>s.timestamp>=n&&s.timestamp<=i)}getSuccessful(){return this.entries.filter((n)=>n.success)}getFailed(){return this.entries.filter((n)=>!n.success)}getMostUsed(n=10){let i=new Map;for(let s of this.entries){let o=s.command.split(" ")[0];i.set(o,(i.get(o)||0)+1)}return Array.from(i.entries()).map(([s,o])=>({command:s,count:o})).sort((s,o)=>o.count-s.count).slice(0,n)}getStats(){let n=this.entries.length,i=this.entries.filter((h)=>h.success).length,s=this.entries.filter((h)=>!h.success).length,o=this.entries.filter((h)=>h.duration!==void 0),c=o.length>0?o.reduce((h,y)=>h+(y.duration||0),0)/o.length:0,l=this.getMostUsed(1),u=l.length>0?l[0].command:"N/A";return{total:n,successful:i,failed:s,averageDuration:c,mostUsed:u}}clear(){this.entries=[]}getByIndex(n){if(n<0||n>=this.entries.length)return;return this.entries[n]}removeByIndex(n){if(n>=0&&n<this.entries.length)this.entries.splice(n,1)}async save(){if(!this.persistFile)return;try{let n=await import("node:fs/promises"),i=JSON.stringify(this.entries,null,2);await n.writeFile(this.persistFile,i,"utf-8")}catch(n){throw Error(`Failed to save history: ${n}`)}}async load(){if(!this.persistFile)return;try{let n=await import("node:fs/promises"),i=await n.readFile(this.persistFile,"utf-8"),s=JSON.parse(i);this.entries=s.map((o)=>({...o,timestamp:new Date(o.timestamp)}))}catch{this.entries=[]}}exportJSON(){return JSON.stringify(this.entries,null,2)}exportCSV(){return["Timestamp,Command,Success,Duration",...this.entries.map((n)=>[n.timestamp.toISOString(),`"${n.command.replace(/"/g,'""')}"`,n.success,n.duration||""].join(","))].join(`
2762
- `)}importJSON(n){let i=JSON.parse(n).map((s)=>({...s,timestamp:new Date(s.timestamp)}));if(this.entries.push(...i),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let n=new Map;for(let i of this.entries){let s=i.timestamp.toISOString().split("T")[0];if(!n.has(s))n.set(s,[]);n.get(s).push(i)}return n}groupByCommand(){let n=new Map;for(let i of this.entries){let s=i.command.split(" ")[0];if(!n.has(s))n.set(s,[]);n.get(s).push(i)}return n}replay(n){return this.getByIndex(n)?.command}getSuggestions(n,i=5){let s=n.toLowerCase(),o=this.entries.filter((c)=>c.command.toLowerCase().startsWith(s)).map((c)=>c.command);return[...new Set(o)].slice(0,i)}analyzePatterns(){let n=new Map,i=new Map;for(let o of this.entries){let c=o.timestamp.getHours(),l=o.timestamp.getDay();n.set(c,(n.get(c)||0)+1),i.set(l,(i.get(l)||0)+1)}let s=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:n,dayOfWeek:i,successRate:s}}}function uC(n,i={}){let{maxWidth:s=100}=i;if(n.length===0)return"No command history";let o=[];for(let c=0;c<n.length;c++){let l=n[c],u=(c+1).toString().padStart(4),h=l.timestamp.toLocaleString(),y=l.success?"✓":"✗",f=l.command;if(f.length>s-30)f=f.substring(0,s-33)+"...";let b=`${u} ${h} ${y} ${f}`;if(l.duration)b+=` (${l.duration}ms)`;o.push(b)}return o.join(`
2762
+ `)}importJSON(n){let i=JSON.parse(n).map((s)=>({...s,timestamp:new Date(s.timestamp)}));if(this.entries.push(...i),this.entries.length>this.maxSize)this.entries=this.entries.slice(-this.maxSize)}groupByDate(){let n=new Map;for(let i of this.entries){let s=i.timestamp.toISOString().split("T")[0];if(!n.has(s))n.set(s,[]);n.get(s).push(i)}return n}groupByCommand(){let n=new Map;for(let i of this.entries){let s=i.command.split(" ")[0];if(!n.has(s))n.set(s,[]);n.get(s).push(i)}return n}replay(n){return this.getByIndex(n)?.command}getSuggestions(n,i=5){let s=n.toLowerCase(),o=this.entries.filter((c)=>c.command.toLowerCase().startsWith(s)).map((c)=>c.command);return[...new Set(o)].slice(0,i)}analyzePatterns(){let n=new Map,i=new Map;for(let o of this.entries){let c=o.timestamp.getHours(),l=o.timestamp.getDay();n.set(c,(n.get(c)||0)+1),i.set(l,(i.get(l)||0)+1)}let s=this.entries.length>0?this.getSuccessful().length/this.entries.length:0;return{timeOfDay:n,dayOfWeek:i,successRate:s}}}function uC(n,i={}){let{maxWidth:s=100}=i;if(n.length===0)return"No command history";let o=[];for(let c=0;c<n.length;c++){let l=n[c],u=(c+1).toString().padStart(4),h=l.timestamp.toLocaleString(),y=l.success?"✓":"✗",f=l.command;if(f.length>s-30)f=f.substring(0,s-33)+"...";let S=`${u} ${h} ${y} ${f}`;if(l.duration)S+=` (${l.duration}ms)`;o.push(S)}return o.join(`
2763
2763
  `)}function pC(n){let i=[];return i.push("Command History Statistics"),i.push("─".repeat(30)),i.push(`Total commands: ${n.total}`),i.push(`Successful: ${n.successful}`),i.push(`Failed: ${n.failed}`),i.push(`Success rate: ${(n.successful/n.total*100).toFixed(1)}%`),i.push(`Average duration: ${n.averageDuration.toFixed(0)}ms`),i.push(`Most used: ${n.mostUsed}`),i.join(`
2764
2764
  `)}class Ug{deployments=new Map;async deploy(n,i){let s=this.generateDeploymentId(),o={id:s,regions:i.regions.map((c)=>({region:c.code,stackName:this.getStackName(n,c.code),status:"pending"})),status:"deploying",startTime:new Date};this.deployments.set(s,o);try{let c=i.regions.find((u)=>u.isPrimary)||i.regions[0];await this.deployToRegion(n,c,o);let l=i.regions.filter((u)=>u.code!==c.code);if(await Promise.all(l.map((u)=>this.deployToRegion(n,u,o))),i.globalResources)await this.deployGlobalResources(o,i);if(i.replication)await this.setupReplication(o,i);if(i.failover?.enabled)await this.setupFailover(o,i);return o.status="deployed",o.endTime=new Date,o}catch(c){throw o.status="failed",o.endTime=new Date,c}}async deployToRegion(n,i,s){let o=s.regions.find((c)=>c.region===i.code);if(!o)throw Error(`Region deployment not found: ${i.code}`);o.status="deploying",o.startTime=new Date;try{let c=this.createRegionConfig(n,i);await this.deployStack(o.stackName,c,i.code),o.status="deployed",o.endTime=new Date,o.outputs={stackId:`arn:aws:cloudformation:${i.code}:123456789012:stack/${o.stackName}/guid`,endpoint:`https://${o.stackName}.${i.code}.example.com`}}catch(c){throw o.status="failed",o.endTime=new Date,o.error=c instanceof Error?c.message:String(c),c}}async deployGlobalResources(n,i){let s={};if(i.globalResources?.route53)s.route53=await this.deployRoute53(n,i);if(i.globalResources?.cloudfront)s.cloudfront=await this.deployCloudFront(n,i);if(i.globalResources?.waf)s.waf=await this.deployWAF(n);n.globalResources=s}async deployRoute53(n,i){let s=[],o=[];for(let c of n.regions){if(c.status!=="deployed")continue;let l={id:`health-${c.region}`,endpoint:c.outputs?.endpoint,path:i.failover?.healthCheckPath||"/health",region:c.region};s.push(l);let u={name:"example.com",type:"A",region:c.region,setIdentifier:c.region,healthCheckId:l.id,resourceRecords:[c.outputs?.endpoint]};o.push(u)}return{healthChecks:s,recordSets:o,hostedZoneId:"Z1234567890ABC"}}async deployCloudFront(n,i){return{distributionId:"E1234567890ABC",domainName:"d1234567890abc.cloudfront.net",origins:n.regions.filter((s)=>s.status==="deployed").map((s,o)=>{let c=i.regions[o];return{id:`origin-${s.region}`,domainName:s.outputs?.endpoint,weight:c?.weight||100}}),status:"Deployed"}}async deployWAF(n){return{webAclId:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6",webAclArn:"arn:aws:wafv2:us-east-1:123456789012:global/webacl/test/a1234567-b890-c123-d456-e789012345f6"}}async setupReplication(n,i){if(i.replication?.s3)await this.setupS3Replication(n);if(i.replication?.dynamodb)await this.setupDynamoDBReplication(n);if(i.replication?.secrets)await this.setupSecretsReplication(n)}async setupS3Replication(n){let i=n.regions.filter((s)=>s.status==="deployed");for(let s=0;s<i.length-1;s++){let o=i[s],c=i[s+1];console.log(`Setting up S3 replication: ${o.region} -> ${c.region}`)}}async setupDynamoDBReplication(n){let i=n.regions.filter((s)=>s.status==="deployed").map((s)=>s.region);console.log(`Setting up DynamoDB global table in regions: ${i.join(", ")}`)}async setupSecretsReplication(n){let i=n.regions.filter((s)=>s.status==="deployed").map((s)=>s.region);console.log(`Setting up Secrets Manager replication in regions: ${i.join(", ")}`)}async setupFailover(n,i){let s=n.regions.find((c,l)=>i.regions[l]?.isPrimary)||n.regions[0],o=n.regions.filter((c)=>c.region!==s.region);console.log(`Setting up failover: primary=${s.region}, secondary=${o.map((c)=>c.region).join(", ")}`)}async destroy(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);i.status="rolling-back";try{if(i.globalResources)await this.destroyGlobalResources(i.globalResources);await Promise.all(i.regions.map((s)=>this.destroyRegionStack(s))),this.deployments.delete(n)}catch(s){throw i.status="failed",s}}async destroyGlobalResources(n){if(n.waf)console.log("Destroying WAF resources");if(n.cloudfront)console.log("Destroying CloudFront distribution");if(n.route53)console.log("Destroying Route53 resources")}async destroyRegionStack(n){if(n.status!=="deployed")return;n.status="rolling-back";try{console.log(`Destroying stack ${n.stackName} in ${n.region}`),n.status="pending"}catch(i){throw n.status="failed",n.error=i instanceof Error?i.message:String(i),i}}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getStackName(n,i){return`${n.project.slug}-${i}`}createRegionConfig(n,i){return{...n,infrastructure:{...n.infrastructure}}}async deployStack(n,i,s){console.log(`Deploying stack ${n} to ${s}`)}generateDeploymentId(){return`deploy-${Date.now()}-${Math.random().toString(36).substring(7)}`}}var gC=new Ug;class Qg{references=[];exports=new Map;addExport(n){let i=`${n.region}:${n.exportName}`;if(!this.exports.has(n.region))this.exports.set(n.region,[]);this.exports.get(n.region).push(n)}getExport(n,i){let s=this.exports.get(n);if(!s)return;return s.find((o)=>o.exportName===i)?.value}createReference(n,i,s,o){let c=`/cross-region/${n}/${s}/${o}`;return this.references.push({sourceRegion:n,targetRegion:i,resourceType:s,resourceId:o,value:c}),c}async resolveReference(n,i){let s=this.references.find((o)=>o.targetRegion===n&&o.value===i);if(!s)throw Error(`Reference not found: ${i}`);return`arn:aws:resource:${s.sourceRegion}:123456789012:${s.resourceType}/${s.resourceId}`}getReferencesForRegion(n){return this.references.filter((i)=>i.sourceRegion===n||i.targetRegion===n)}clear(){this.references=[],this.exports.clear()}}class Hg{resources=new Map;register(n){this.resources.set(n.id,n)}get(n){return this.resources.get(n)}getByType(n){return Array.from(this.resources.values()).filter((i)=>i.type===n)}getCloudFrontDistributions(){return this.getByType("cloudfront")}getRoute53HostedZones(){return this.getByType("route53")}getWAFWebACLs(){return this.getByType("waf")}remove(n){this.resources.delete(n)}clear(){this.resources.clear()}}class Gg{pairs=[];addPair(n){this.pairs.push(n)}getPairedRegion(n){let i=this.pairs.find((s)=>s.primary===n||s.secondary===n);if(!i)return;return i.primary===n?i.secondary:i.primary}getAllPairs(){return[...this.pairs]}getReplicatedPairs(){return this.pairs.filter((n)=>n.replicationConfig)}getFailoverPairs(){return this.pairs.filter((n)=>n.failoverConfig?.automatic)}arePaired(n,i){return this.pairs.some((s)=>s.primary===n&&s.secondary===i||s.primary===i&&s.secondary===n)}clear(){this.pairs=[]}}class qg{dependencies=[];addDependency(n){this.dependencies.push(n)}getDependencies(n,i){return this.dependencies.filter((s)=>s.dependentStack===n&&s.dependentRegion===i)}getDependents(n,i){return this.dependencies.filter((s)=>s.dependsOnStack===n&&s.dependsOnRegion===i)}hasDependencies(n,i){return this.getDependencies(n,i).length>0}getDeploymentOrder(n){let i=new Set,s=[],o=(c)=>{let l=`${c.name}:${c.region}`;if(i.has(l))return;i.add(l);let u=this.getDependencies(c.name,c.region);for(let h of u)o({name:h.dependsOnStack,region:h.dependsOnRegion});s.push(c)};for(let c of n)o(c);return s}detectCircularDependencies(){let n=new Set,i=new Set,s=(o,c)=>{let l=`${o}:${c}`;if(i.has(l))return!0;if(n.has(l))return!1;n.add(l),i.add(l);let u=this.getDependencies(o,c);for(let h of u)if(s(h.dependsOnStack,h.dependsOnRegion))return!0;return i.delete(l),!1};for(let o of this.dependencies)if(s(o.dependentStack,o.dependentRegion))return!0;return!1}clear(){this.dependencies=[]}}var mC=new Qg,hC=new Hg,fC=new Gg,AC=new qg,Ne=[{code:"us-east-1",name:"US East (N. Virginia)",location:"Virginia, USA",launchYear:2006,availabilityZones:6,localZones:16,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO","FedRAMP"]},{code:"us-east-2",name:"US East (Ohio)",location:"Ohio, USA",launchYear:2016,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-1",name:"US West (N. California)",location:"California, USA",launchYear:2009,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"us-west-2",name:"US West (Oregon)",location:"Oregon, USA",launchYear:2011,availabilityZones:4,localZones:2,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1},compliance:["PCI-DSS","HIPAA","SOC","ISO"]},{code:"eu-west-1",name:"Europe (Ireland)",location:"Dublin, Ireland",launchYear:2007,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"standard",multiplier:1.05},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"eu-central-1",name:"Europe (Frankfurt)",location:"Frankfurt, Germany",launchYear:2014,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.1},compliance:["PCI-DSS","GDPR","SOC","ISO"]},{code:"ap-southeast-1",name:"Asia Pacific (Singapore)",location:"Singapore",launchYear:2010,availabilityZones:3,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.12},compliance:["PCI-DSS","SOC","ISO","MTCS"]},{code:"ap-northeast-1",name:"Asia Pacific (Tokyo)",location:"Tokyo, Japan",launchYear:2011,availabilityZones:4,services:{compute:!0,storage:!0,database:!0,networking:!0,ml:!0,analytics:!0},pricing:{tier:"premium",multiplier:1.15},compliance:["PCI-DSS","SOC","ISO"]}];function ki(n){return Ne.find((i)=>i.code===n)}function yC(){return Ne}function IC(n){let i=n.toLowerCase();return Ne.filter((s)=>s.location.toLowerCase().includes(i))}function SC(n){return Ne.filter((i)=>i.compliance.includes(n))}function CC(n){return Ne.filter((i)=>i.pricing.tier===n)}function EC(n){return Ne.some((i)=>i.code===n)}function bC(n){if(n.continent==="North America")return ki("us-east-1");if(n.continent==="Europe")return ki("eu-west-1");if(n.continent==="Asia")return ki("ap-southeast-1");return ki("us-east-1")}function vC(n){let i=[...Ne];if(n.compliance)i=i.filter((s)=>n.compliance.every((o)=>s.compliance.includes(o)));if(n.requiredServices)i=i.filter((s)=>n.requiredServices.every((o)=>s.services[o]));if(n.pricingSensitive)i.sort((s,o)=>s.pricing.multiplier-o.pricing.multiplier);return i.slice(0,5)}function TC(n){let i=ki(n);if(!i)throw Error(`Invalid region: ${n}`);let s=[];for(let o of Ne){if(o.code===n)continue;let c=jn(i,o),l=Kn(i,o);s.push({primary:i,secondary:o,distance:c,sameContinent:l})}return s.sort((o,c)=>{if(o.sameContinent!==c.sameContinent)return o.sameContinent?1:-1;return o.distance-c.distance}),s.slice(0,3)}function jn(n,i){let s={"North America":0,"South America":1,Europe:2,Asia:3,Africa:4,Oceania:5},o=at(n.location),c=at(i.location);return Math.abs((s[o]||0)-(s[c]||0))}function Kn(n,i){return at(n.location)===at(i.location)}function at(n){if(n.includes("USA")||n.includes("Canada"))return"North America";if(n.includes("Europe")||n.includes("Ireland")||n.includes("Germany"))return"Europe";if(n.includes("Asia")||n.includes("Singapore")||n.includes("Japan"))return"Asia";if(n.includes("Brazil"))return"South America";if(n.includes("Australia"))return"Oceania";return"Unknown"}function HA(n){return`${n.name} (${n.code})`}function wC(n){return n.map((i)=>HA(i)).join(`
2765
2765
  `)}function RC(){let n={total:Ne.length,byContinent:{},byPricingTier:{}};for(let i of Ne){let s=at(i.location);n.byContinent[s]=(n.byContinent[s]||0)+1,n.byPricingTier[i.pricing.tier]=(n.byPricingTier[i.pricing.tier]||0)+1}return n}class Vg{accounts=new Map;crossAccountRoles=[];accountMappings=[];registerAccount(n){this.accounts.set(n.id,n)}getAccount(n){return this.accounts.get(n)}getAccountByAlias(n){return Array.from(this.accounts.values()).find((i)=>i.alias===n)}listAccounts(){return Array.from(this.accounts.values())}getAccountsByRole(n){return Array.from(this.accounts.values()).filter((i)=>i.role===n)}createCrossAccountRole(n,i,s,o,c){let l={roleArn:`arn:aws:iam::${i}:role/${s}`,roleName:s,sourceAccountId:n,targetAccountId:i,permissions:o,externalId:c?.externalId,sessionDuration:c?.sessionDuration||3600};return this.crossAccountRoles.push(l),l}getAssumeRolePolicyDocument(n,i){let s={Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${n}:root`},Action:"sts:AssumeRole"}]};if(i)s.Statement[0].Condition={StringEquals:{"sts:ExternalId":i}};return s}generateCrossAccountPolicy(n){return{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:n,Resource:"*"}]}}mapEnvironmentToAccount(n,i,s){this.accountMappings.push({environment:n,accountId:i,region:s})}getAccountForEnvironment(n){return this.accountMappings.find((i)=>i.environment===n)}async assumeRole(n,i,s){return console.log(`Assuming role: ${n} with session: ${i}`),{accessKeyId:"AKIAIOSFODNN7EXAMPLE",secretAccessKey:"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",sessionToken:"token",expiration:new Date(Date.now()+3600000)}}async getCredentialsForAccount(n){let i=this.accounts.get(n);if(!i)throw Error(`Account not found: ${n}`);if(i.assumeRoleArn){let s=await this.assumeRole(i.assumeRoleArn,`ts-cloud-${Date.now()}`);return{accessKeyId:s.accessKeyId,secretAccessKey:s.secretAccessKey,sessionToken:s.sessionToken}}throw Error("No credentials available for account")}listCrossAccountRoles(){return[...this.crossAccountRoles]}getCrossAccountRolesForAccount(n){return this.crossAccountRoles.filter((i)=>i.sourceAccountId===n||i.targetAccountId===n)}async validateAccountAccess(n){try{let i=await this.getCredentialsForAccount(n);return console.log(`Validating access to account: ${n}`),!0}catch{return!1}}async getConsolidatedBilling(){let n={};for(let i of this.accounts.values())n[i.id]=Math.random()*1000;return{totalCost:Object.values(n).reduce((i,s)=>i+s,0),byAccount:n}}clear(){this.accounts.clear(),this.crossAccountRoles=[],this.accountMappings=[]}}class jg{organizationId;organizationalUnits=new Map;getOrganizationId(){return this.organizationId}setOrganizationId(n){this.organizationId=n}createOrganizationalUnit(n,i){let s={id:`ou-${Date.now()}`,name:n,parentId:i,accounts:[]};return this.organizationalUnits.set(s.id,s),s}getOrganizationalUnit(n){return this.organizationalUnits.get(n)}listOrganizationalUnits(){return Array.from(this.organizationalUnits.values())}addAccountToOU(n,i){let s=this.organizationalUnits.get(n);if(!s)throw Error(`Organizational unit not found: ${n}`);if(!s.accounts.includes(i))s.accounts.push(i)}removeAccountFromOU(n,i){let s=this.organizationalUnits.get(n);if(!s)throw Error(`Organizational unit not found: ${n}`);s.accounts=s.accounts.filter((o)=>o!==i)}getAccountsInOU(n){let i=this.organizationalUnits.get(n);if(!i)return[];return[...i.accounts]}applyServiceControlPolicy(n,i){return{id:`scp-${Date.now()}`,name:"Custom SCP",targetId:n,policyDocument:i}}clear(){this.organizationId=void 0,this.organizationalUnits.clear()}}var DC=new Vg,PC=new jg,GA={basic:{name:"Basic (3 Accounts)",description:"Simple structure for small teams",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account for AWS Organizations"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production workloads"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development and testing"}],organizationalUnits:[{name:"root"},{name:"workloads",parent:"root"}]},standard:{name:"Standard (5 Accounts)",description:"Recommended for most organizations",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"security",email:"aws+security@example.com",role:"security",ou:"security",description:"Security tooling and audit logs"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared services (CI/CD, monitoring)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"workloads",description:"Production environment"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"workloads",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"workloads",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root"},{name:"infrastructure",parent:"root"},{name:"workloads",parent:"root"}]},enterprise:{name:"Enterprise (7+ Accounts)",description:"For large organizations with strict compliance requirements",accounts:[{alias:"management",email:"aws+management@example.com",role:"management",ou:"root",description:"Management account"},{alias:"audit",email:"aws+audit@example.com",role:"security",ou:"security",description:"Audit and compliance"},{alias:"log-archive",email:"aws+logs@example.com",role:"security",ou:"security",description:"Centralized log storage"},{alias:"shared-services",email:"aws+shared@example.com",role:"shared-services",ou:"infrastructure",description:"Shared infrastructure"},{alias:"network",email:"aws+network@example.com",role:"shared-services",ou:"infrastructure",description:"Network infrastructure (Transit Gateway)"},{alias:"production",email:"aws+production@example.com",role:"production",ou:"production-ou",description:"Production workloads"},{alias:"staging",email:"aws+staging@example.com",role:"staging",ou:"non-production-ou",description:"Staging environment"},{alias:"development",email:"aws+development@example.com",role:"development",ou:"non-production-ou",description:"Development environment"}],organizationalUnits:[{name:"root"},{name:"security",parent:"root",policies:["deny-root-access"]},{name:"infrastructure",parent:"root"},{name:"production-ou",parent:"root",policies:["require-mfa"]},{name:"non-production-ou",parent:"root"}]}},NC={denyRootAccess:{name:"Deny Root User Access",description:"Prevent root user from performing any actions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyRootUser",Effect:"Deny",Action:"*",Resource:"*",Condition:{StringLike:{"aws:PrincipalArn":"arn:aws:iam::*:root"}}}]}},requireMFA:{name:"Require MFA for All Actions",description:"Require MFA for console and API access",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"RequireMFA",Effect:"Deny",Action:"*",Resource:"*",Condition:{BoolIfExists:{"aws:MultiFactorAuthPresent":"false"}}}]}},denyRegions:{name:"Deny Access to Non-Approved Regions",description:"Restrict operations to specific regions",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyNonApprovedRegions",Effect:"Deny",NotAction:["iam:*","organizations:*","route53:*","cloudfront:*","support:*","s3:*"],Resource:"*",Condition:{StringNotEquals:{"aws:RequestedRegion":["us-east-1","us-west-2"]}}}]}},preventLeaving:{name:"Prevent Leaving Organization",description:"Prevent accounts from leaving the organization",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"PreventLeaving",Effect:"Deny",Action:"organizations:LeaveOrganization",Resource:"*"}]}},denyS3Unencrypted:{name:"Deny Unencrypted S3 Uploads",description:"Require encryption for all S3 uploads",policyDocument:{Version:"2012-10-17",Statement:[{Sid:"DenyUnencryptedS3Uploads",Effect:"Deny",Action:"s3:PutObject",Resource:"*",Condition:{StringNotEquals:{"s3:x-amz-server-side-encryption":["AES256","aws:kms"]}}}]}}},kC={deploymentRole:{name:"CrossAccountDeploymentRole",description:"Role for deploying infrastructure from CI/CD",permissions:["cloudformation:*","s3:*","ec2:*","ecs:*","lambda:*","iam:GetRole","iam:PassRole","logs:*","events:*"]},readOnlyRole:{name:"CrossAccountReadOnlyRole",description:"Read-only access for monitoring and auditing",permissions:["cloudformation:Describe*","cloudformation:List*","ec2:Describe*","ecs:Describe*","lambda:Get*","lambda:List*","s3:Get*","s3:List*","logs:Get*","logs:Describe*"]},securityAuditRole:{name:"CrossAccountSecurityAuditRole",description:"Security audit and compliance checks",permissions:["iam:Get*","iam:List*","iam:Generate*","access-analyzer:*","guardduty:Get*","guardduty:List*","securityhub:Get*","securityhub:List*","config:Describe*","config:Get*","config:List*"]},breakGlassRole:{name:"CrossAccountBreakGlassRole",description:"Emergency access role (use with caution)",permissions:["*"]}};function BC(n){return GA[n]}function _C(n,i){return{Type:"AWS::IAM::Role",Properties:{RoleName:n.roleName,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{AWS:`arn:aws:iam::${n.sourceAccountId}:root`},Action:"sts:AssumeRole",...n.externalId&&{Condition:{StringEquals:{"sts:ExternalId":n.externalId}}}}]},Policies:[{PolicyName:`${n.roleName}Policy`,PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:n.permissions,Resource:"*"}]}}],...i&&{ManagedPolicyArns:i},MaxSessionDuration:n.sessionDuration||3600,Tags:[{Key:"ManagedBy",Value:"TS-Cloud"},{Key:"SourceAccount",Value:n.sourceAccountId}]}}}function xC(n){let i=[],s=[],o=n.accounts.filter((y)=>y.role==="management");if(o.length===0)i.push("No management account defined");if(o.length>1)i.push("Multiple management accounts defined");let c=n.accounts.map((y)=>y.email),l=c.filter((y,f)=>c.indexOf(y)!==f);if(l.length>0)i.push(`Duplicate email addresses: ${l.join(", ")}`);let u=n.accounts.map((y)=>y.alias),h=u.filter((y,f)=>u.indexOf(y)!==f);if(h.length>0)i.push(`Duplicate aliases: ${h.join(", ")}`);if(!n.accounts.some((y)=>y.role==="security"))s.push("No dedicated security account - consider adding one for audit logs");if(n.accounts.length<3)s.push("Less than 3 accounts - consider separating environments");if(!n.accounts.some((y)=>y.role==="production"))s.push("No production account defined");return{valid:i.length===0,errors:i,warnings:s}}function OC(n){let i=[];if(i.push(`${n.name}`),i.push("─".repeat(n.name.length)),i.push(n.description),i.push(""),n.organizationalUnits){i.push("Organizational Units:");for(let s of n.organizationalUnits){let o=s.parent?" └─ ":" ";i.push(`${o}${s.name}`)}i.push("")}i.push("Accounts:");for(let s of n.accounts)i.push(` ${s.alias.padEnd(20)} ${s.role.padEnd(15)} ${s.email}`),i.push(` ${"".padEnd(20)} ${s.description}`),i.push("");return i.join(`
2766
- `)}function LC(n={}){let{workflowName:i="Deploy",trigger:s="push",branches:o=["main"],environments:c=["production"],awsRegion:l="us-east-1",awsRole:u,bunVersion:h="latest",deployCommand:y="bun run cloud deploy",testCommand:f="bun test",buildCommand:b="bun run build"}=n,C=!!u;return`name: ${i}
2766
+ `)}function LC(n={}){let{workflowName:i="Deploy",trigger:s="push",branches:o=["main"],environments:c=["production"],awsRegion:l="us-east-1",awsRole:u,bunVersion:h="latest",deployCommand:y="bun run cloud deploy",testCommand:f="bun test",buildCommand:S="bun run build"}=n,b=!!u;return`name: ${i}
2767
2767
 
2768
2768
  on:
2769
2769
  ${s}:
2770
2770
  branches:
2771
- ${o.map((T)=>` - ${T}`).join(`
2771
+ ${o.map((v)=>` - ${v}`).join(`
2772
2772
  `)}
2773
2773
 
2774
2774
  env:
@@ -2794,7 +2794,7 @@ jobs:
2794
2794
  run: ${f}
2795
2795
 
2796
2796
  - name: Build
2797
- run: ${b}
2797
+ run: ${S}
2798
2798
 
2799
2799
  deploy:
2800
2800
  needs: test
@@ -2816,7 +2816,7 @@ jobs:
2816
2816
  - name: Install dependencies
2817
2817
  run: bun install
2818
2818
 
2819
- ${C?`- name: Configure AWS credentials (OIDC)
2819
+ ${b?`- name: Configure AWS credentials (OIDC)
2820
2820
  uses: aws-actions/configure-aws-credentials@v4
2821
2821
  with:
2822
2822
  role-to-assume: ${u}
@@ -3597,7 +3597,7 @@ workflows:
3597
3597
  requires:
3598
3598
  - test
3599
3599
  ${c}
3600
- `}class zg{backupPlans=new Map;backupVaults=new Map;restoreJobs=new Map;continuousBackups=new Map;planCounter=0;restoreCounter=0;continuousBackupCounter=0;createVault(n){this.backupVaults.set(n.name,n)}getVault(n){return this.backupVaults.get(n)}createBackupPlan(n){let i=`backup-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.backupPlans.set(i,s),s}getBackupPlan(n){return this.backupPlans.get(n)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(n){let{dbInstanceArn:i,schedule:s="0 2 * * *",retentionDays:o=7,vaultName:c="default-vault"}=n;return this.createBackupPlan({name:"RDS Daily Backup",schedule:s,retentionDays:o,vaultName:c,resources:[{resourceArn:i,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:o}})}createDynamoDBBackupPlan(n){let{tableArn:i,schedule:s="0 3 * * *",retentionDays:o=35,crossRegionCopy:c}=n;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:s,retentionDays:o,vaultName:"dynamodb-vault",resources:[{resourceArn:i,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:o},tags:c?{CrossRegionCopy:c.join(",")}:void 0})}createEFSBackupPlan(n){let{fileSystemArn:i,schedule:s="0 1 * * *",retentionDays:o=30}=n;return this.createBackupPlan({name:"EFS Daily Backup",schedule:s,retentionDays:o,vaultName:"efs-vault",resources:[{resourceArn:i,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:o}})}enableContinuousBackup(n,i=35){let s=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,o={id:s,resourceId:n,enabled:!0,retentionDays:i};return this.continuousBackups.set(s,o),o}getContinuousBackup(n){return this.continuousBackups.get(n)}enablePointInTimeRecovery(n,i){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(n){let{backupId:i,resourceType:s,targetRegion:o}=n,c={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:i,resourceType:s,status:"pending",startTime:new Date,targetRegion:o};return this.restoreJobs.set(c.id,c),setTimeout(()=>{c.status="running"},100),setTimeout(()=>{c.status="completed",c.endTime=new Date},1000),c}async restoreToPointInTime(n){let{sourceResourceArn:i,targetResourceName:s,restoreTime:o,resourceType:c}=n,l={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${o.getTime()}`,resourceType:c,status:"pending",startTime:new Date};return this.restoreJobs.set(l.id,l),console.log(`Restoring ${c} from ${i} to ${s} at ${o.toISOString()}`),setTimeout(()=>{l.status="completed",l.endTime=new Date},2000),l}getRestoreJob(n){return this.restoreJobs.get(n)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(n){let{sourceVault:i,sourceRegion:s,targetRegions:o}=n;console.log("Setting up cross-region replication:"),console.log(` Source: ${i} in ${s}`),console.log(` Targets: ${o.join(", ")}`)}generateBackupVaultCF(n){return{Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:n.name,...n.encryptionKeyArn&&{EncryptionKeyArn:n.encryptionKeyArn},...n.accessPolicy&&{AccessPolicy:n.accessPolicy}}}}generateBackupPlanCF(n){return{Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:n.name,BackupPlanRule:[{RuleName:"DailyBackup",TargetBackupVault:n.vaultName,ScheduleExpression:`cron(${n.schedule})`,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:n.lifecycle?{...n.lifecycle.moveTocoldStorageAfterDays&&{MoveToColdStorageAfterDays:n.lifecycle.moveTocoldStorageAfterDays},...n.lifecycle.deleteAfterDays&&{DeleteAfterDays:n.lifecycle.deleteAfterDays}}:void 0}]},...n.tags&&{BackupPlanTags:n.tags}}}}generateBackupSelectionCF(n){return{Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:{Ref:`BackupPlan${n.id}`},BackupSelection:{SelectionName:`${n.name}Selection`,IamRoleArn:"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole",Resources:n.resources.map((i)=>i.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var XC=new zg;class Kg{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(n){let i=`dr-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.drPlans.set(i,s),s}createRDSDRPlan(n){let{primaryDbArn:i,secondaryDbArn:s,primaryRegion:o,secondaryRegion:c,rto:l=60,rpo:u=5}=n;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:o,secondaryRegion:c,rto:l,rpo:u,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:i,secondaryArn:s,replicationEnabled:!0}],runbook:this.generateRDSRunbook(o,c),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(n){let{tableArn:i,regions:s,rto:o=15,rpo:c=1}=n;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:s[0],secondaryRegion:s[1],rto:o,rpo:c,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:i,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(s)})}generateRDSRunbook(n,i){return{estimatedDuration:60,requiredApprovals:["cto","engineering-lead"],steps:[{order:1,name:"Verify Primary Database Failure",description:"Confirm that the primary database is truly unavailable and not experiencing temporary issues",action:"aws rds describe-db-instances --region "+n,automatable:!0,estimatedDuration:2,rollbackable:!1},{order:2,name:"Check Replication Lag",description:"Verify that the read replica is up to date",action:"Check ReplicaLag metric in CloudWatch",automatable:!0,estimatedDuration:1,rollbackable:!1},{order:3,name:"Promote Read Replica",description:"Promote the read replica in the secondary region to be the new primary",action:"aws rds promote-read-replica --db-instance-identifier replica --region "+i,automatable:!0,estimatedDuration:10,rollbackable:!1},{order:4,name:"Update DNS Records",description:"Update Route53 records to point to the new primary database",action:"Update Route53 failover record set",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:5,name:"Update Application Configuration",description:"Update application connection strings if needed",action:"Deploy configuration update to ECS/Lambda",automatable:!0,estimatedDuration:10,rollbackable:!0},{order:6,name:"Verify Application Connectivity",description:"Test that applications can connect to the new primary",action:"Run smoke tests",automatable:!0,estimatedDuration:5,rollbackable:!1},{order:7,name:"Monitor for Issues",description:"Monitor CloudWatch metrics and application logs",action:"Monitor for 30 minutes",automatable:!1,estimatedDuration:30,rollbackable:!1}]}}generateDynamoDBRunbook(n){return{estimatedDuration:15,steps:[{order:1,name:"Verify Primary Region Failure",description:"Confirm that the primary region is experiencing an outage",action:"Check AWS Health Dashboard",automatable:!0,estimatedDuration:2,rollbackable:!1},{order:2,name:"Update Route53 Failover",description:"Update Route53 to direct traffic to secondary region",action:"Update Route53 health check and failover records",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:3,name:"Update Application Endpoints",description:"Update Lambda/ECS to use secondary region DynamoDB endpoint",action:"Deploy configuration update",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:4,name:"Verify Data Consistency",description:"Verify that data is consistent in secondary region",action:"Run data validation queries",automatable:!0,estimatedDuration:3,rollbackable:!1}]}}async executeFailover(n,i=!1){let s=this.drPlans.get(n);if(!s)throw Error(`DR plan not found: ${n}`);let o=Date.now(),c=0;console.log(`${i?"[DRY RUN] ":""}Executing failover for plan: ${s.name}`),console.log(`Primary: ${s.primaryRegion} -> Secondary: ${s.secondaryRegion}`),console.log(`RTO: ${s.rto} minutes, RPO: ${s.rpo} minutes`),console.log("");for(let l of s.runbook.steps){if(console.log(`Step ${l.order}: ${l.name}`),console.log(` ${l.description}`),console.log(` Action: ${l.action}`),console.log(` Estimated: ${l.estimatedDuration} minutes`),i)console.log(" [SKIPPED - DRY RUN]");else if(l.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");c++,console.log("")}return{success:!0,duration:(Date.now()-o)/1000/60,completedSteps:c}}scheduleFailoverTest(n,i){let s={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:n,status:"scheduled",startTime:i};return this.failoverTests.set(s.id,s),s}async runFailoverTest(n){let i=this.drPlans.get(n);if(!i)throw Error(`DR plan not found: ${n}`);let s={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:n,status:"running",startTime:new Date,results:[]};this.failoverTests.set(s.id,s),console.log(`Running failover test for plan: ${i.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let o of i.runbook.steps){let c=Date.now();console.log(`Testing step ${o.order}: ${o.name}`);let l={step:o.name,status:"success",duration:(Date.now()-c)/1000,message:`Successfully validated step ${o.order}`};s.results.push(l)}return s.status="completed",s.endTime=new Date,s}getDRPlan(n){return this.drPlans.get(n)}listDRPlans(){return Array.from(this.drPlans.values())}getFailoverTest(n){return this.failoverTests.get(n)}listFailoverTests(){return Array.from(this.failoverTests.values())}validateDRPlan(n){let i=[],s=[];if(n.rto<n.rpo)s.push("RTO cannot be less than RPO");if(n.rto>240)i.push("RTO exceeds 4 hours - consider improving recovery time");if(n.rpo>60)i.push("RPO exceeds 1 hour - consider more frequent backups");if(n.resources.length===0)s.push("No resources defined in DR plan");for(let l of n.resources){if(!l.replicationEnabled)i.push(`Resource ${l.resourceId} does not have replication enabled`);if(!l.secondaryArn&&l.resourceType!=="dynamodb")i.push(`Resource ${l.resourceId} does not have secondary resource defined`)}if(n.runbook.steps.length===0)s.push("No recovery steps defined in runbook");let o=n.runbook.steps.reduce((l,u)=>l+u.estimatedDuration,0);if(o>n.rto)i.push(`Estimated recovery duration (${o}m) exceeds RTO (${n.rto}m)`);let c=n.runbook.steps.filter((l)=>!l.automatable);if(c.length>0)i.push(`${c.length} manual steps in runbook - consider automation`);return{valid:s.length===0,warnings:i,errors:s}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var YC=new Kg;class Wg{configRules=new Map;configRecorders=new Map;deliveryChannels=new Map;ruleCounter=0;createConfigRecorder(n){return this.configRecorders.set(n.name,n),n}createDeliveryChannel(n){return this.deliveryChannels.set(n.name,n),n}createConfigRule(n){let i=`config-rule-${Date.now()}-${this.ruleCounter++}`,s={id:i,...n};return this.configRules.set(i,s),s}createS3EncryptionRule(){return this.createConfigRule({name:"s3-bucket-server-side-encryption-enabled",description:"Checks that S3 buckets have server-side encryption enabled",source:"AWS_MANAGED",identifier:"S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createS3PublicAccessBlockRule(){return this.createConfigRule({name:"s3-bucket-public-read-prohibited",description:"Checks that S3 buckets do not allow public read access",source:"AWS_MANAGED",identifier:"S3_BUCKET_PUBLIC_READ_PROHIBITED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createS3VersioningRule(){return this.createConfigRule({name:"s3-bucket-versioning-enabled",description:"Checks whether versioning is enabled for S3 buckets",source:"AWS_MANAGED",identifier:"S3_BUCKET_VERSIONING_ENABLED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createRdsEncryptionRule(){return this.createConfigRule({name:"rds-storage-encrypted",description:"Checks whether storage encryption is enabled for RDS DB instances",source:"AWS_MANAGED",identifier:"RDS_STORAGE_ENCRYPTED",scope:{complianceResourceTypes:["AWS::RDS::DBInstance"]}})}createRdsSnapshotEncryptionRule(){return this.createConfigRule({name:"rds-snapshots-public-prohibited",description:"Checks if RDS snapshots are public",source:"AWS_MANAGED",identifier:"RDS_SNAPSHOTS_PUBLIC_PROHIBITED",scope:{complianceResourceTypes:["AWS::RDS::DBSnapshot","AWS::RDS::DBClusterSnapshot"]}})}createRdsBackupRule(n=7){return this.createConfigRule({name:"db-backup-enabled",description:"Checks whether RDS DB instances have backups enabled",source:"AWS_MANAGED",identifier:"DB_BACKUP_ENABLED",inputParameters:{backupRetentionPeriod:n},scope:{complianceResourceTypes:["AWS::RDS::DBInstance"]}})}createEc2InstanceProfileRule(){return this.createConfigRule({name:"ec2-instance-managed-by-systems-manager",description:"Checks if EC2 instances are managed by Systems Manager",source:"AWS_MANAGED",identifier:"EC2_INSTANCE_MANAGED_BY_SSM",scope:{complianceResourceTypes:["AWS::EC2::Instance"]}})}createEbsEncryptionRule(){return this.createConfigRule({name:"encrypted-volumes",description:"Checks whether EBS volumes are encrypted",source:"AWS_MANAGED",identifier:"ENCRYPTED_VOLUMES",scope:{complianceResourceTypes:["AWS::EC2::Volume"]}})}createIamPasswordPolicyRule(){return this.createConfigRule({name:"iam-password-policy",description:"Checks whether the IAM password policy meets specified requirements",source:"AWS_MANAGED",identifier:"IAM_PASSWORD_POLICY",inputParameters:{RequireUppercaseCharacters:!0,RequireLowercaseCharacters:!0,RequireSymbols:!0,RequireNumbers:!0,MinimumPasswordLength:14,PasswordReusePrevention:24,MaxPasswordAge:90}})}createIamMfaRule(){return this.createConfigRule({name:"iam-user-mfa-enabled",description:"Checks whether IAM users have MFA enabled",source:"AWS_MANAGED",identifier:"IAM_USER_MFA_ENABLED"})}createRootAccountMfaRule(){return this.createConfigRule({name:"root-account-mfa-enabled",description:"Checks whether the root account has MFA enabled",source:"AWS_MANAGED",identifier:"ROOT_ACCOUNT_MFA_ENABLED"})}createVpcFlowLogsRule(){return this.createConfigRule({name:"vpc-flow-logs-enabled",description:"Checks whether VPC Flow Logs is enabled",source:"AWS_MANAGED",identifier:"VPC_FLOW_LOGS_ENABLED",scope:{complianceResourceTypes:["AWS::EC2::VPC"]}})}createCloudTrailEnabledRule(){return this.createConfigRule({name:"cloudtrail-enabled",description:"Checks whether CloudTrail is enabled",source:"AWS_MANAGED",identifier:"CLOUD_TRAIL_ENABLED",maxExecutionFrequency:"TwentyFour_Hours"})}createCloudWatchAlarmRule(){return this.createConfigRule({name:"cloudwatch-alarm-action-check",description:"Checks whether CloudWatch alarms have actions configured",source:"AWS_MANAGED",identifier:"CLOUDWATCH_ALARM_ACTION_CHECK",inputParameters:{alarmActionRequired:!0,insufficientDataActionRequired:!1,okActionRequired:!1},scope:{complianceResourceTypes:["AWS::CloudWatch::Alarm"]}})}createCustomLambdaRule(n){return this.createConfigRule({name:n.name,description:n.description,source:"CUSTOM_LAMBDA",lambdaFunctionArn:n.lambdaFunctionArn,scope:n.resourceTypes?{complianceResourceTypes:n.resourceTypes}:void 0,maxExecutionFrequency:n.maxExecutionFrequency,inputParameters:n.inputParameters})}createCompliancePreset(n){let i=[];switch(n){case"hipaa":i.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":i.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":i.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":i.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":i.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return i}getConfigRule(n){return this.configRules.get(n)}listConfigRules(){return Array.from(this.configRules.values())}getConfigRecorder(n){return this.configRecorders.get(n)}listConfigRecorders(){return Array.from(this.configRecorders.values())}getDeliveryChannel(n){return this.deliveryChannels.get(n)}listDeliveryChannels(){return Array.from(this.deliveryChannels.values())}generateConfigRuleCF(n){let i={Type:"AWS::Config::ConfigRule",Properties:{ConfigRuleName:n.name,Description:n.description,Source:{Owner:n.source==="AWS_MANAGED"?"AWS":"CUSTOM_LAMBDA"}}};if(n.source==="AWS_MANAGED"&&n.identifier)i.Properties.Source.SourceIdentifier=n.identifier;if(n.source==="CUSTOM_LAMBDA"&&n.lambdaFunctionArn)i.Properties.Source.SourceIdentifier=n.lambdaFunctionArn,i.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(n.inputParameters)i.Properties.InputParameters=JSON.stringify(n.inputParameters);if(n.scope){if(i.Properties.Scope={},n.scope.complianceResourceTypes)i.Properties.Scope.ComplianceResourceTypes=n.scope.complianceResourceTypes;if(n.scope.tagKey)i.Properties.Scope.TagKey=n.scope.tagKey;if(n.scope.tagValue)i.Properties.Scope.TagValue=n.scope.tagValue}if(n.maxExecutionFrequency)i.Properties.MaximumExecutionFrequency=n.maxExecutionFrequency;return i}generateConfigRecorderCF(n){return{Type:"AWS::Config::ConfigurationRecorder",Properties:{Name:n.name,RoleArn:n.roleArn,RecordingGroup:n.recordingGroup||{AllSupported:!0,IncludeGlobalResourceTypes:!0}}}}generateDeliveryChannelCF(n){return{Type:"AWS::Config::DeliveryChannel",Properties:{Name:n.name,S3BucketName:n.s3BucketName,...n.s3KeyPrefix&&{S3KeyPrefix:n.s3KeyPrefix},...n.snsTopicArn&&{SnsTopicARN:n.snsTopicArn},...n.configSnapshotDeliveryProperties&&{ConfigSnapshotDeliveryProperties:n.configSnapshotDeliveryProperties}}}}clear(){this.configRules.clear(),this.configRecorders.clear(),this.deliveryChannels.clear(),this.ruleCounter=0}}var ZC=new Wg;class Jg{trails=new Map;trailCounter=0;createTrail(n){let i=`trail-${Date.now()}-${this.trailCounter++}`,s={id:i,...n};return this.trails.set(i,s),s}createOrganizationTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"organization-trail",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:n.kmsKeyId,cloudWatchLogsLogGroupArn:n.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:n.cloudWatchLogsRoleArn})}createSecurityAuditTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"security-audit",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:n.kmsKeyId,cloudWatchLogsLogGroupArn:n.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:n.cloudWatchLogsRoleArn,eventSelectors:[{readWriteType:"All",includeManagementEvents:!0,excludeManagementEventSources:[]}],insightSelectors:[{insightType:"ApiCallRateInsight"},{insightType:"ApiErrorRateInsight"}]})}createDataEventsTrail(n){let i=[];if(n.s3DataBuckets&&n.s3DataBuckets.length>0)i.push({type:"AWS::S3::Object",values:n.s3DataBuckets.map((s)=>`arn:aws:s3:::${s}/*`)});if(n.lambdaFunctions&&n.lambdaFunctions.length>0)i.push({type:"AWS::Lambda::Function",values:n.lambdaFunctions});return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"data-events",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"All",includeManagementEvents:!1,dataResources:i}]})}createAdvancedTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,advancedEventSelectors:n.selectors})}createReadOnlyTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"ReadOnly",includeManagementEvents:!0}]})}createWriteOnlyTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"WriteOnly",includeManagementEvents:!0}]})}getTrail(n){return this.trails.get(n)}listTrails(){return Array.from(this.trails.values())}generateTrailCF(n){let i={Type:"AWS::CloudTrail::Trail",Properties:{TrailName:n.name,S3BucketName:n.s3BucketName,IsLogging:!0,IncludeGlobalServiceEvents:n.includeGlobalServiceEvents??!0,IsMultiRegionTrail:n.isMultiRegionTrail??!0,EnableLogFileValidation:n.enableLogFileValidation??!0}};if(n.s3KeyPrefix)i.Properties.S3KeyPrefix=n.s3KeyPrefix;if(n.cloudWatchLogsLogGroupArn)i.Properties.CloudWatchLogsLogGroupArn=n.cloudWatchLogsLogGroupArn;if(n.cloudWatchLogsRoleArn)i.Properties.CloudWatchLogsRoleArn=n.cloudWatchLogsRoleArn;if(n.snsTopicName)i.Properties.SnsTopicName=n.snsTopicName;if(n.kmsKeyId)i.Properties.KMSKeyId=n.kmsKeyId;if(n.eventSelectors)i.Properties.EventSelectors=n.eventSelectors.map((s)=>({ReadWriteType:s.readWriteType,IncludeManagementEvents:s.includeManagementEvents??!0,...s.dataResources&&{DataResources:s.dataResources.map((o)=>({Type:o.type,Values:o.values}))},...s.excludeManagementEventSources&&{ExcludeManagementEventSources:s.excludeManagementEventSources}}));if(n.insightSelectors)i.Properties.InsightSelectors=n.insightSelectors.map((s)=>({InsightType:s.insightType}));if(n.advancedEventSelectors)i.Properties.AdvancedEventSelectors=n.advancedEventSelectors.map((s)=>({Name:s.name,FieldSelectors:s.fieldSelectors.map((o)=>({Field:o.field,...o.equals&&{Equals:o.equals},...o.startsWith&&{StartsWith:o.startsWith},...o.endsWith&&{EndsWith:o.endsWith},...o.notEquals&&{NotEquals:o.notEquals},...o.notStartsWith&&{NotStartsWith:o.notStartsWith},...o.notEndsWith&&{NotEndsWith:o.notEndsWith}}))}));return i}generateBucketPolicy(n,i){return{Version:"2012-10-17",Statement:[{Sid:"AWSCloudTrailAclCheck",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:GetBucketAcl",Resource:`arn:aws:s3:::${n}`},{Sid:"AWSCloudTrailWrite",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:PutObject",Resource:i.map((s)=>`arn:aws:s3:::${n}/AWSLogs/${s}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var eE=new Jg;class Xg{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(n){let i=`detector-${Date.now()}-${this.detectorCounter++}`,s={id:i,...n};return this.detectors.set(i,s),s}createComprehensiveDetector(){return this.createDetector({enable:!0,findingPublishingFrequency:"FIFTEEN_MINUTES",dataSources:{s3Logs:{enable:!0},kubernetes:{auditLogs:{enable:!0}},malwareProtection:{scanEc2InstanceWithFindings:{ebsVolumes:{enable:!0}}}},features:[{name:"S3_DATA_EVENTS",status:"ENABLED"},{name:"EKS_AUDIT_LOGS",status:"ENABLED"},{name:"EBS_MALWARE_PROTECTION",status:"ENABLED"},{name:"RDS_LOGIN_EVENTS",status:"ENABLED"},{name:"LAMBDA_NETWORK_LOGS",status:"ENABLED"}]})}createBasicDetector(){return this.createDetector({enable:!0,findingPublishingFrequency:"SIX_HOURS"})}createThreatIntelSet(n){let i=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,s={id:i,...n};return this.threatIntelSets.set(i,s),s}createIPSet(n){let i=`ip-set-${Date.now()}-${this.ipSetCounter++}`,s={id:i,...n};return this.ipSets.set(i,s),s}createFindingFilter(n){let i=`filter-${Date.now()}-${this.filterCounter++}`,s={id:i,...n};return this.filters.set(i,s),s}createLowSeverityArchiveFilter(n){return this.createFindingFilter({detectorId:n,name:"archive-low-severity",description:"Automatically archive low severity findings",action:"ARCHIVE",rank:1,findingCriteria:{criterion:{severity:{lt:4}}}})}createFindingTypeFilter(n,i,s){return this.createFindingFilter({detectorId:n,name:`filter-finding-types-${s.toLowerCase()}`,description:`${s==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:s,rank:2,findingCriteria:{criterion:{type:{eq:i}}}})}createTrustedIPFilter(n,i){return this.createFindingFilter({detectorId:n,name:"trusted-ip-addresses",description:"Archive findings from trusted IP addresses",action:"ARCHIVE",rank:3,findingCriteria:{criterion:{"resource.instanceDetails.networkInterfaces.privateIpAddress":{eq:i}}}})}getDetector(n){return this.detectors.get(n)}listDetectors(){return Array.from(this.detectors.values())}getThreatIntelSet(n){return this.threatIntelSets.get(n)}listThreatIntelSets(){return Array.from(this.threatIntelSets.values())}getIPSet(n){return this.ipSets.get(n)}listIPSets(){return Array.from(this.ipSets.values())}getFindingFilter(n){return this.filters.get(n)}listFindingFilters(){return Array.from(this.filters.values())}generateDetectorCF(n){let i={Type:"AWS::GuardDuty::Detector",Properties:{Enable:n.enable}};if(n.findingPublishingFrequency)i.Properties.FindingPublishingFrequency=n.findingPublishingFrequency;if(n.dataSources){if(i.Properties.DataSources={},n.dataSources.s3Logs)i.Properties.DataSources.S3Logs={Enable:n.dataSources.s3Logs.enable};if(n.dataSources.kubernetes)i.Properties.DataSources.Kubernetes={AuditLogs:{Enable:n.dataSources.kubernetes.auditLogs.enable}};if(n.dataSources.malwareProtection)i.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:n.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(n.features)i.Properties.Features=n.features.map((s)=>({Name:s.name,Status:s.status,...s.additionalConfiguration&&{AdditionalConfiguration:s.additionalConfiguration}}));return i}generateThreatIntelSetCF(n){return{Type:"AWS::GuardDuty::ThreatIntelSet",Properties:{DetectorId:n.detectorId,Name:n.name,Format:n.format,Location:n.location,Activate:n.activate}}}generateIPSetCF(n){return{Type:"AWS::GuardDuty::IPSet",Properties:{DetectorId:n.detectorId,Name:n.name,Format:n.format,Location:n.location,Activate:n.activate}}}generateFilterCF(n){return{Type:"AWS::GuardDuty::Filter",Properties:{DetectorId:n.detectorId,Name:n.name,Description:n.description,Action:n.action,Rank:n.rank,FindingCriteria:{Criterion:n.findingCriteria.criterion}}}}clear(){this.detectors.clear(),this.threatIntelSets.clear(),this.ipSets.clear(),this.filters.clear(),this.detectorCounter=0,this.threatIntelCounter=0,this.ipSetCounter=0,this.filterCounter=0}}var tE=new Xg;class jr{hubs=new Map;hubCounter=0;ruleCounter=0;static Standards={AWS_FOUNDATIONAL_SECURITY:{arn:"arn:aws:securityhub:::ruleset/aws-foundational-security-best-practices/v/1.0.0",name:"AWS Foundational Security Best Practices",description:"AWS recommended security best practices"},CIS_AWS_FOUNDATIONS_1_2:{arn:"arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0",name:"CIS AWS Foundations Benchmark v1.2.0",description:"CIS AWS Foundations Benchmark v1.2.0"},CIS_AWS_FOUNDATIONS_1_4:{arn:"arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0",name:"CIS AWS Foundations Benchmark v1.4.0",description:"CIS AWS Foundations Benchmark v1.4.0"},PCI_DSS:{arn:"arn:aws:securityhub:us-east-1::standards/pci-dss/v/3.2.1",name:"PCI DSS v3.2.1",description:"Payment Card Industry Data Security Standard"},NIST_800_53:{arn:"arn:aws:securityhub:us-east-1::standards/nist-800-53/v/5.0.0",name:"NIST SP 800-53 Rev. 5",description:"NIST Special Publication 800-53 Revision 5"}};createHub(n){let i=`hub-${Date.now()}-${this.hubCounter++}`,s={id:i,...n};return this.hubs.set(i,s),s}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...jr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...jr.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...jr.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...jr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0}]})}createLowSeveritySuppressionRule(){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Suppress Low Severity Informational Findings",description:"Automatically suppress informational findings",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Automatically suppressed low severity finding",updatedBy:"SecurityHub Automation"}}}],criteria:{severityLabel:[{value:"INFORMATIONAL",comparison:"EQUALS"}],recordState:[{value:"ACTIVE",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:1}}createResourceTypeNotificationRule(n){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Notify on Critical Resource Findings",description:"Set findings for critical resources to NOTIFIED status",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"NOTIFIED"},note:{text:"Critical resource finding requires attention",updatedBy:"SecurityHub Automation"}}}],criteria:{resourceType:n.map((i)=>({value:i,comparison:"EQUALS"})),severityLabel:[{value:"HIGH",comparison:"EQUALS"},{value:"CRITICAL",comparison:"EQUALS"}],workflowStatus:[{value:"NEW",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:2}}createComplianceFailureRule(){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Flag Compliance Failures",description:"Increase severity for compliance failures",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{severity:{label:"HIGH"},workflow:{status:"NOTIFIED"},note:{text:"Compliance failure detected - requires immediate attention",updatedBy:"SecurityHub Automation"}}}],criteria:{complianceStatus:[{value:"FAILED",comparison:"EQUALS"}],recordState:[{value:"ACTIVE",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:3}}createFalsePositiveSuppressionRule(n,i){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:`Suppress False Positives - ${n}`,description:`Automatically suppress known false positives from ${n}`,actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Known false positive - automatically suppressed",updatedBy:"SecurityHub Automation"}}}],criteria:{productName:[{value:n,comparison:"EQUALS"}],title:i.map((s)=>({value:s,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(n){return this.hubs.get(n)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(n){let i={Type:"AWS::SecurityHub::Hub",Properties:{}};if(n.controlFindingGenerator)i.Properties.ControlFindingGenerator=n.controlFindingGenerator;if(n.enableDefaultStandards!==void 0)i.Properties.EnableDefaultStandards=n.enableDefaultStandards;return i}generateStandardCF(n){let i={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:n.arn}};if(n.disabledControls&&n.disabledControls.length>0)i.Properties.DisabledStandardsControls=n.disabledControls.map((s)=>({StandardsControlArn:s,Reason:"Disabled by configuration"}));return i}generateAutomationRuleCF(n){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:n.ruleName,Description:n.description,Actions:n.actions.map((i)=>({Type:i.type,FindingFieldsUpdate:i.findingFieldsUpdate})),Criteria:n.criteria,RuleStatus:n.ruleStatus,RuleOrder:n.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var rE=new jr;class Yg{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(n){let i=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,s={id:i,...n};return this.deployments.set(i,s),s}createALBDeployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:n.listenerArn,switchoverTimeSeconds:0},autoPromote:n.autoPromote,healthCheckConfig:n.healthCheckConfig})}createRoute53Deployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"route53",hostedZoneId:n.hostedZoneId,switchoverTimeSeconds:n.switchoverTimeSeconds||60}})}createECSDeployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,taskDefinitionArn:n.blueTaskDefinitionArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,taskDefinitionArn:n.greenTaskDefinitionArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:n.listenerArn},autoRollback:n.autoRollback??!0})}async executeDeployment(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);let o={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${i?"[DRY RUN] ":""}Starting blue/green deployment: ${s.name}`),console.log(` Active environment: ${s.activeEnvironment}`),console.log(` Routing type: ${s.routingConfig.type}`);let c=s.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${c}`),console.log(`\\n1. Deploying to ${c} environment`),!i)await new Promise((l)=>setTimeout(l,100));if(console.log(`\\n2. Running health checks on ${c} environment`),s.healthCheckConfig){let l=await this.runHealthChecks(s,c,i);if(o.healthChecksPassed=l,!l){if(o.errors?.push("Health checks failed"),o.endTime=new Date,s.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),o.rolledBackAt=new Date;return this.recordDeployment(n,o),o}}else o.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${c} environment`),!i)s.activeEnvironment=c,o.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${c} environment`),!i)await new Promise((l)=>setTimeout(l,100));return o.success=!0,o.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(n,o),o}async rollback(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);let s={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${i.name}`);let o=i.activeEnvironment==="blue"?"green":"blue";return i.activeEnvironment=o,s.success=!0,s.rolledBackAt=new Date,s.endTime=new Date,console.log(` Switched back to: ${o}`),this.recordDeployment(n,s),s}async runHealthChecks(n,i,s){let o=n.healthCheckConfig;if(console.log(` Health check path: ${o.path||"/"}`),console.log(` Healthy threshold: ${o.healthyThreshold}`),console.log(` Interval: ${o.interval}s`),s)return console.log(" [SKIPPED - DRY RUN]"),!0;let c=0,l=o.healthyThreshold+2;for(let u=0;u<l;u++)if(await new Promise((h)=>setTimeout(h,50)),Math.random()>0.1){if(c++,console.log(` Check ${u+1}: ✓ Healthy (${c}/${o.healthyThreshold})`),c>=o.healthyThreshold)return!0}else c=0,console.log(` Check ${u+1}: ✗ Unhealthy`);return!1}recordDeployment(n,i){if(!this.deploymentHistory.has(n))this.deploymentHistory.set(n,[]);this.deploymentHistory.get(n).push(i)}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(n){return this.deploymentHistory.get(n)||[]}generateALBListenerCF(n){let i=n.activeEnvironment==="blue"?n.blueEnvironment:n.greenEnvironment;return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:n.routingConfig.listenerArn,Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",TargetGroupArn:i.targetGroupArn}]}}}generateRoute53RecordSetCF(n,i){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.routingConfig.hostedZoneId,Name:i,Type:"A",SetIdentifier:"blue",Weight:n.activeEnvironment==="blue"?100:0,AliasTarget:{HostedZoneId:n.routingConfig.hostedZoneId,DNSName:n.blueEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}},{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.routingConfig.hostedZoneId,Name:i,Type:"A",SetIdentifier:"green",Weight:n.activeEnvironment==="green"?100:0,AliasTarget:{HostedZoneId:n.routingConfig.hostedZoneId,DNSName:n.greenEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}}]}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var nE=new Yg;class yo{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;static Strategies={CONSERVATIVE:[{name:"Initial Canary",trafficPercentage:10,durationMinutes:10},{name:"Quarter Traffic",trafficPercentage:25,durationMinutes:10},{name:"Half Traffic",trafficPercentage:50,durationMinutes:15},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],BALANCED:[{name:"Initial Canary",trafficPercentage:20,durationMinutes:5},{name:"Half Traffic",trafficPercentage:50,durationMinutes:10},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],AGGRESSIVE:[{name:"Half Traffic",trafficPercentage:50,durationMinutes:5},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],LINEAR_10:[{name:"Canary 10%",trafficPercentage:10,durationMinutes:5},{name:"Canary 20%",trafficPercentage:20,durationMinutes:5},{name:"Canary 30%",trafficPercentage:30,durationMinutes:5},{name:"Canary 40%",trafficPercentage:40,durationMinutes:5},{name:"Canary 50%",trafficPercentage:50,durationMinutes:5},{name:"Canary 60%",trafficPercentage:60,durationMinutes:5},{name:"Canary 70%",trafficPercentage:70,durationMinutes:5},{name:"Canary 80%",trafficPercentage:80,durationMinutes:5},{name:"Canary 90%",trafficPercentage:90,durationMinutes:5},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}]};createDeployment(n){let i=`canary-${Date.now()}-${this.deploymentCounter++}`,s={id:i,...n};return this.deployments.set(i,s),s}createLambdaCanaryDeployment(n){let i=n.strategy||"BALANCED",s=yo.Strategies[i].map((o)=>({...o,alarmThresholds:{errorRate:n.errorRateThreshold||1,latencyP99:n.latencyThreshold||1000}}));return this.createDeployment({name:n.name,baselineVersion:{version:"baseline",functionVersionArn:n.baselineVersionArn,weight:100},canaryVersion:{version:"canary",functionVersionArn:n.canaryVersionArn,weight:0},stages:s,currentStage:0,status:"pending",autoPromote:n.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(n){let i=n.strategy||"CONSERVATIVE",s=yo.Strategies[i];return this.createDeployment({name:n.name,baselineVersion:{version:"baseline",taskDefinitionArn:n.baselineTaskDefinitionArn,targetGroupArn:n.baselineTargetGroupArn,weight:100},canaryVersion:{version:"canary",taskDefinitionArn:n.canaryTaskDefinitionArn,targetGroupArn:n.canaryTargetGroupArn,weight:0},stages:s,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);let o={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${i?"[DRY RUN] ":""}Starting canary deployment: ${s.name}`),console.log(` Strategy: ${s.stages.length} stages`),console.log(` Auto-promote: ${s.autoPromote}`),console.log(` Auto-rollback: ${s.autoRollback}`),console.log(""),s.status="in_progress";for(let c=0;c<s.stages.length;c++){let l=s.stages[c];if(s.currentStage=c,console.log(`Stage ${c+1}/${s.stages.length}: ${l.name}`),console.log(` Traffic: ${l.trafficPercentage}% canary, ${100-l.trafficPercentage}% baseline`),console.log(` Duration: ${l.durationMinutes} minutes`),!i)s.baselineVersion.weight=100-l.trafficPercentage,s.canaryVersion.weight=l.trafficPercentage;if(!await this.monitorStage(s,l,i)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),s.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(n,i),o.rolledBack=!0,o.reason="Metrics exceeded thresholds";return o.endTime=new Date,s.status="rolled_back",this.recordDeployment(n,o),o}console.log(" ✓ Stage completed successfully"),o.completedStages++,console.log("")}return s.status="completed",o.success=!0,o.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(n,o),o}async monitorStage(n,i,s){if(console.log(" Monitoring metrics..."),s)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((c)=>setTimeout(c,100));let o={baselineErrorRate:Math.random()*0.5,canaryErrorRate:Math.random()*0.8,baselineLatencyP99:200+Math.random()*100,canaryLatencyP99:180+Math.random()*150,baselineRequestCount:Math.floor(Math.random()*1000)+500,canaryRequestCount:Math.floor((Math.random()*1000+500)*i.trafficPercentage/100)};if(n.metrics=o,console.log(` Baseline: ${o.baselineErrorRate.toFixed(2)}% errors, ${o.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${o.canaryErrorRate.toFixed(2)}% errors, ${o.canaryLatencyP99.toFixed(0)}ms P99`),i.alarmThresholds){let{errorRate:c,latencyP99:l}=i.alarmThresholds;if(c&&o.canaryErrorRate>c)return console.log(` ⚠ Error rate exceeded threshold: ${o.canaryErrorRate.toFixed(2)}% > ${c}%`),!1;if(l&&o.canaryLatencyP99>l)return console.log(` ⚠ Latency P99 exceeded threshold: ${o.canaryLatencyP99.toFixed(0)}ms > ${l}ms`),!1}return!0}async rollback(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);if(console.log(`${i?"[DRY RUN] ":""}Rolling back canary deployment: ${s.name}`),!i)s.baselineVersion.weight=100,s.canaryVersion.weight=0,s.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);console.log(`Promoting canary to baseline: ${i.name}`);let s=i.baselineVersion;i.baselineVersion=i.canaryVersion,i.canaryVersion=s,i.baselineVersion.weight=100,i.canaryVersion.weight=0,i.status="completed",console.log(" Canary promoted successfully")}recordDeployment(n,i){if(!this.deploymentHistory.has(n))this.deploymentHistory.set(n,[]);this.deploymentHistory.get(n).push(i)}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(n){return this.deploymentHistory.get(n)||[]}generateLambdaAliasCF(n,i){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:i,FunctionVersion:n.canaryVersion.version,RoutingConfig:{AdditionalVersionWeights:[{FunctionVersion:n.baselineVersion.version,FunctionWeight:n.baselineVersion.weight/100}]}}}}generateALBListenerRuleCF(n){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:[{TargetGroupArn:n.baselineVersion.targetGroupArn,Weight:n.baselineVersion.weight},{TargetGroupArn:n.canaryVersion.targetGroupArn,Weight:n.canaryVersion.weight}],TargetGroupStickinessConfig:{Enabled:!1}}}]}}}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var iE=new yo;class Zg{tests=new Map;testCounter=0;createTest(n){let i=`abtest-${Date.now()}-${this.testCounter++}`,s={id:i,...n};return this.tests.set(i,s),s}createSimpleABTest(n){let i=n.variantTrafficPercentage||50;return this.createTest({name:n.name,description:n.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-i,targetGroupArn:n.controlTargetGroupArn,weight:100-i},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:i,targetGroupArn:n.variantTargetGroupArn,weight:i}],routingStrategy:{type:n.stickySession?"cookie":"random",cookieName:n.stickySession?"ab_variant":void 0,stickySession:n.stickySession??!1,sessionDuration:1440},startTime:new Date,status:"draft"})}createMultivariateTest(n){let i=n.variants.reduce((s,o)=>s+o.trafficPercentage,0);if(i!==100)throw Error(`Traffic percentages must sum to 100, got ${i}`);return this.createTest({name:n.name,description:n.description,variants:n.variants.map((s,o)=>({id:`variant-${o}`,name:s.name,description:s.description,trafficPercentage:s.trafficPercentage,targetGroupArn:s.targetGroupArn,weight:s.trafficPercentage})),routingStrategy:n.routingStrategy||{type:"random",stickySession:!1},startTime:new Date,status:"draft"})}createHeaderBasedTest(n){return this.createTest({name:n.name,description:`Route based on ${n.headerName} header`,variants:[{id:"control",name:"Control",trafficPercentage:50,targetGroupArn:n.controlTargetGroupArn,weight:50},{id:"variant-a",name:"Variant A",trafficPercentage:50,targetGroupArn:n.variantTargetGroupArn,weight:50}],routingStrategy:{type:"header",headerName:n.headerName,stickySession:!1},startTime:new Date,status:"draft"})}createGeoBasedTest(n){return this.createTest({name:n.name,description:"Route based on geographic location",variants:[{id:"control",name:"Control (Rest of World)",trafficPercentage:50,targetGroupArn:n.controlTargetGroupArn,weight:50},{id:"variant-a",name:`Variant A (${n.regions.join(", ")})`,trafficPercentage:50,targetGroupArn:n.variantTargetGroupArn,weight:50}],routingStrategy:{type:"geo",stickySession:!0,sessionDuration:1440},startTime:new Date,status:"draft"})}startTest(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);if(i.status!=="draft"&&i.status!=="paused")throw Error(`Cannot start test in ${i.status} status`);i.status="active",i.startTime=new Date,console.log(`Started A/B test: ${i.name}`),console.log(` Variants: ${i.variants.length}`),i.variants.forEach((s)=>{console.log(` - ${s.name}: ${s.trafficPercentage}%`)})}pauseTest(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);i.status="paused",console.log(`Paused A/B test: ${i.name}`)}updateTrafficSplit(n,i,s){let o=this.tests.get(n);if(!o)throw Error(`Test not found: ${n}`);let c=o.variants.find((u)=>u.id===i);if(!c)throw Error(`Variant not found: ${i}`);let l=c.trafficPercentage;c.trafficPercentage=s,c.weight=s,console.log(`Updated ${c.name} traffic: ${l}% → ${s}%`)}analyzeResults(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);if(!i.metrics)i.metrics=this.collectMetrics(i);let s=i.variants[0],o=0;for(let f of i.variants){let b=i.metrics.variants[f.id];if(b&&b.conversionRate>o)o=b.conversionRate,s=f}let c=i.metrics.variants.control||i.metrics.variants[i.variants[0].id],l=i.metrics.variants[s.id],u=(l.conversionRate-c.conversionRate)/c.conversionRate*100,h=100,y=l.requests>h&&c.requests>h&&Math.abs(u)>10;return{testId:n,winningVariant:s.name,confidence:y?95:75,improvement:u,statisticalSignificance:y,metrics:i.metrics,recommendation:this.generateRecommendation(u,y,s.name)}}declareWinner(n,i){let s=this.tests.get(n);if(!s)throw Error(`Test not found: ${n}`);let o=s.variants.find((c)=>c.id===i);if(!o)throw Error(`Variant not found: ${i}`);s.variants.forEach((c)=>{if(c.id===i)c.trafficPercentage=100,c.weight=100;else c.trafficPercentage=0,c.weight=0}),s.status="completed",s.endTime=new Date,s.winner=i,console.log(`Declared winner: ${o.name}`),console.log(` All traffic now routed to ${o.name}`)}collectMetrics(n){let i={},s=0;for(let o of n.variants){let c=Math.floor(Math.random()*1000)+500,l=Math.floor(c*(Math.random()*0.1+0.05)),u=l/c*100;i[o.id]={requests:c,conversions:l,conversionRate:u,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:l*(Math.random()*50+100)},s+=c}return{variants:i,totalRequests:s,startTime:n.startTime,lastUpdated:new Date}}generateRecommendation(n,i,s){if(!i)return"Continue test - sample size too small or no significant difference detected";if(n>20)return`Strong winner detected - ${s} shows ${n.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(n>10)return`Moderate improvement - ${s} shows ${n.toFixed(1)}% improvement. Consider deploying.`;if(n>0)return`Minor improvement - ${s} shows ${n.toFixed(1)}% improvement. May not be worth the complexity.`;return"No improvement detected - consider reverting to control variant"}getTest(n){return this.tests.get(n)}listTests(){return Array.from(this.tests.values())}generateALBListenerRuleCF(n){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:n.variants.map((i)=>({TargetGroupArn:i.targetGroupArn,Weight:i.weight})),TargetGroupStickinessConfig:{Enabled:n.routingStrategy.stickySession||!1,DurationSeconds:n.routingStrategy.sessionDuration?n.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(n){return`'use strict';
3600
+ `}class zg{backupPlans=new Map;backupVaults=new Map;restoreJobs=new Map;continuousBackups=new Map;planCounter=0;restoreCounter=0;continuousBackupCounter=0;createVault(n){this.backupVaults.set(n.name,n)}getVault(n){return this.backupVaults.get(n)}createBackupPlan(n){let i=`backup-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.backupPlans.set(i,s),s}getBackupPlan(n){return this.backupPlans.get(n)}listBackupPlans(){return Array.from(this.backupPlans.values())}createRDSBackupPlan(n){let{dbInstanceArn:i,schedule:s="0 2 * * *",retentionDays:o=7,vaultName:c="default-vault"}=n;return this.createBackupPlan({name:"RDS Daily Backup",schedule:s,retentionDays:o,vaultName:c,resources:[{resourceArn:i,resourceType:"rds",region:"us-east-1"}],lifecycle:{moveTocoldStorageAfterDays:30,deleteAfterDays:o}})}createDynamoDBBackupPlan(n){let{tableArn:i,schedule:s="0 3 * * *",retentionDays:o=35,crossRegionCopy:c}=n;return this.createBackupPlan({name:"DynamoDB Daily Backup",schedule:s,retentionDays:o,vaultName:"dynamodb-vault",resources:[{resourceArn:i,resourceType:"dynamodb",region:"us-east-1"}],lifecycle:{deleteAfterDays:o},tags:c?{CrossRegionCopy:c.join(",")}:void 0})}createEFSBackupPlan(n){let{fileSystemArn:i,schedule:s="0 1 * * *",retentionDays:o=30}=n;return this.createBackupPlan({name:"EFS Daily Backup",schedule:s,retentionDays:o,vaultName:"efs-vault",resources:[{resourceArn:i,resourceType:"efs",region:"us-east-1"}],lifecycle:{deleteAfterDays:o}})}enableContinuousBackup(n,i=35){let s=`continuous-backup-${Date.now()}-${this.continuousBackupCounter++}`,o={id:s,resourceId:n,enabled:!0,retentionDays:i};return this.continuousBackups.set(s,o),o}getContinuousBackup(n){return this.continuousBackups.get(n)}enablePointInTimeRecovery(n,i){return{enabled:!0,earliestRestorableTime:new Date(Date.now()-604800000),latestRestorableTime:new Date}}async restoreFromBackup(n){let{backupId:i,resourceType:s,targetRegion:o}=n,c={id:`restore-${Date.now()}-${this.restoreCounter++}`,backupId:i,resourceType:s,status:"pending",startTime:new Date,targetRegion:o};return this.restoreJobs.set(c.id,c),setTimeout(()=>{c.status="running"},100),setTimeout(()=>{c.status="completed",c.endTime=new Date},1000),c}async restoreToPointInTime(n){let{sourceResourceArn:i,targetResourceName:s,restoreTime:o,resourceType:c}=n,l={id:`pitr-${Date.now()}-${this.restoreCounter++}`,backupId:`pitr-${o.getTime()}`,resourceType:c,status:"pending",startTime:new Date};return this.restoreJobs.set(l.id,l),console.log(`Restoring ${c} from ${i} to ${s} at ${o.toISOString()}`),setTimeout(()=>{l.status="completed",l.endTime=new Date},2000),l}getRestoreJob(n){return this.restoreJobs.get(n)}listRestoreJobs(){return Array.from(this.restoreJobs.values())}setupCrossRegionReplication(n){let{sourceVault:i,sourceRegion:s,targetRegions:o}=n;console.log("Setting up cross-region replication:"),console.log(` Source: ${i} in ${s}`),console.log(` Targets: ${o.join(", ")}`)}generateBackupVaultCF(n){return{Type:"AWS::Backup::BackupVault",Properties:{BackupVaultName:n.name,...n.encryptionKeyArn&&{EncryptionKeyArn:n.encryptionKeyArn},...n.accessPolicy&&{AccessPolicy:n.accessPolicy}}}}generateBackupPlanCF(n){return{Type:"AWS::Backup::BackupPlan",Properties:{BackupPlan:{BackupPlanName:n.name,BackupPlanRule:[{RuleName:"DailyBackup",TargetBackupVault:n.vaultName,ScheduleExpression:`cron(${n.schedule})`,StartWindowMinutes:60,CompletionWindowMinutes:120,Lifecycle:n.lifecycle?{...n.lifecycle.moveTocoldStorageAfterDays&&{MoveToColdStorageAfterDays:n.lifecycle.moveTocoldStorageAfterDays},...n.lifecycle.deleteAfterDays&&{DeleteAfterDays:n.lifecycle.deleteAfterDays}}:void 0}]},...n.tags&&{BackupPlanTags:n.tags}}}}generateBackupSelectionCF(n){return{Type:"AWS::Backup::BackupSelection",Properties:{BackupPlanId:{Ref:`BackupPlan${n.id}`},BackupSelection:{SelectionName:`${n.name}Selection`,IamRoleArn:"arn:aws:iam::123456789012:role/service-role/AWSBackupDefaultServiceRole",Resources:n.resources.map((i)=>i.resourceArn)}}}}clear(){this.backupPlans.clear(),this.backupVaults.clear(),this.restoreJobs.clear(),this.continuousBackups.clear(),this.planCounter=0,this.restoreCounter=0,this.continuousBackupCounter=0}}var XC=new zg;class Kg{drPlans=new Map;failoverTests=new Map;planCounter=0;testCounter=0;createDRPlan(n){let i=`dr-plan-${Date.now()}-${this.planCounter++}`,s={id:i,...n};return this.drPlans.set(i,s),s}createRDSDRPlan(n){let{primaryDbArn:i,secondaryDbArn:s,primaryRegion:o,secondaryRegion:c,rto:l=60,rpo:u=5}=n;return this.createDRPlan({name:"RDS Multi-Region DR",primaryRegion:o,secondaryRegion:c,rto:l,rpo:u,resources:[{resourceId:"primary-db",resourceType:"rds",primaryArn:i,secondaryArn:s,replicationEnabled:!0}],runbook:this.generateRDSRunbook(o,c),testSchedule:"0 0 1 * *"})}createDynamoDBDRPlan(n){let{tableArn:i,regions:s,rto:o=15,rpo:c=1}=n;return this.createDRPlan({name:"DynamoDB Global Tables DR",primaryRegion:s[0],secondaryRegion:s[1],rto:o,rpo:c,resources:[{resourceId:"dynamodb-table",resourceType:"dynamodb",primaryArn:i,replicationEnabled:!0}],runbook:this.generateDynamoDBRunbook(s)})}generateRDSRunbook(n,i){return{estimatedDuration:60,requiredApprovals:["cto","engineering-lead"],steps:[{order:1,name:"Verify Primary Database Failure",description:"Confirm that the primary database is truly unavailable and not experiencing temporary issues",action:"aws rds describe-db-instances --region "+n,automatable:!0,estimatedDuration:2,rollbackable:!1},{order:2,name:"Check Replication Lag",description:"Verify that the read replica is up to date",action:"Check ReplicaLag metric in CloudWatch",automatable:!0,estimatedDuration:1,rollbackable:!1},{order:3,name:"Promote Read Replica",description:"Promote the read replica in the secondary region to be the new primary",action:"aws rds promote-read-replica --db-instance-identifier replica --region "+i,automatable:!0,estimatedDuration:10,rollbackable:!1},{order:4,name:"Update DNS Records",description:"Update Route53 records to point to the new primary database",action:"Update Route53 failover record set",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:5,name:"Update Application Configuration",description:"Update application connection strings if needed",action:"Deploy configuration update to ECS/Lambda",automatable:!0,estimatedDuration:10,rollbackable:!0},{order:6,name:"Verify Application Connectivity",description:"Test that applications can connect to the new primary",action:"Run smoke tests",automatable:!0,estimatedDuration:5,rollbackable:!1},{order:7,name:"Monitor for Issues",description:"Monitor CloudWatch metrics and application logs",action:"Monitor for 30 minutes",automatable:!1,estimatedDuration:30,rollbackable:!1}]}}generateDynamoDBRunbook(n){return{estimatedDuration:15,steps:[{order:1,name:"Verify Primary Region Failure",description:"Confirm that the primary region is experiencing an outage",action:"Check AWS Health Dashboard",automatable:!0,estimatedDuration:2,rollbackable:!1},{order:2,name:"Update Route53 Failover",description:"Update Route53 to direct traffic to secondary region",action:"Update Route53 health check and failover records",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:3,name:"Update Application Endpoints",description:"Update Lambda/ECS to use secondary region DynamoDB endpoint",action:"Deploy configuration update",automatable:!0,estimatedDuration:5,rollbackable:!0},{order:4,name:"Verify Data Consistency",description:"Verify that data is consistent in secondary region",action:"Run data validation queries",automatable:!0,estimatedDuration:3,rollbackable:!1}]}}async executeFailover(n,i=!1){let s=this.drPlans.get(n);if(!s)throw Error(`DR plan not found: ${n}`);let o=Date.now(),c=0;console.log(`${i?"[DRY RUN] ":""}Executing failover for plan: ${s.name}`),console.log(`Primary: ${s.primaryRegion} -> Secondary: ${s.secondaryRegion}`),console.log(`RTO: ${s.rto} minutes, RPO: ${s.rpo} minutes`),console.log("");for(let l of s.runbook.steps){if(console.log(`Step ${l.order}: ${l.name}`),console.log(` ${l.description}`),console.log(` Action: ${l.action}`),console.log(` Estimated: ${l.estimatedDuration} minutes`),i)console.log(" [SKIPPED - DRY RUN]");else if(l.automatable)console.log(" [AUTOMATED]");else console.log(" [MANUAL - WAITING]");c++,console.log("")}return{success:!0,duration:(Date.now()-o)/1000/60,completedSteps:c}}scheduleFailoverTest(n,i){let s={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:n,status:"scheduled",startTime:i};return this.failoverTests.set(s.id,s),s}async runFailoverTest(n){let i=this.drPlans.get(n);if(!i)throw Error(`DR plan not found: ${n}`);let s={id:`failover-test-${Date.now()}-${this.testCounter++}`,planId:n,status:"running",startTime:new Date,results:[]};this.failoverTests.set(s.id,s),console.log(`Running failover test for plan: ${i.name}`),console.log("This is a non-destructive test using test resources"),console.log("");for(let o of i.runbook.steps){let c=Date.now();console.log(`Testing step ${o.order}: ${o.name}`);let l={step:o.name,status:"success",duration:(Date.now()-c)/1000,message:`Successfully validated step ${o.order}`};s.results.push(l)}return s.status="completed",s.endTime=new Date,s}getDRPlan(n){return this.drPlans.get(n)}listDRPlans(){return Array.from(this.drPlans.values())}getFailoverTest(n){return this.failoverTests.get(n)}listFailoverTests(){return Array.from(this.failoverTests.values())}validateDRPlan(n){let i=[],s=[];if(n.rto<n.rpo)s.push("RTO cannot be less than RPO");if(n.rto>240)i.push("RTO exceeds 4 hours - consider improving recovery time");if(n.rpo>60)i.push("RPO exceeds 1 hour - consider more frequent backups");if(n.resources.length===0)s.push("No resources defined in DR plan");for(let l of n.resources){if(!l.replicationEnabled)i.push(`Resource ${l.resourceId} does not have replication enabled`);if(!l.secondaryArn&&l.resourceType!=="dynamodb")i.push(`Resource ${l.resourceId} does not have secondary resource defined`)}if(n.runbook.steps.length===0)s.push("No recovery steps defined in runbook");let o=n.runbook.steps.reduce((l,u)=>l+u.estimatedDuration,0);if(o>n.rto)i.push(`Estimated recovery duration (${o}m) exceeds RTO (${n.rto}m)`);let c=n.runbook.steps.filter((l)=>!l.automatable);if(c.length>0)i.push(`${c.length} manual steps in runbook - consider automation`);return{valid:s.length===0,warnings:i,errors:s}}clear(){this.drPlans.clear(),this.failoverTests.clear(),this.planCounter=0,this.testCounter=0}}var YC=new Kg;class Wg{configRules=new Map;configRecorders=new Map;deliveryChannels=new Map;ruleCounter=0;createConfigRecorder(n){return this.configRecorders.set(n.name,n),n}createDeliveryChannel(n){return this.deliveryChannels.set(n.name,n),n}createConfigRule(n){let i=`config-rule-${Date.now()}-${this.ruleCounter++}`,s={id:i,...n};return this.configRules.set(i,s),s}createS3EncryptionRule(){return this.createConfigRule({name:"s3-bucket-server-side-encryption-enabled",description:"Checks that S3 buckets have server-side encryption enabled",source:"AWS_MANAGED",identifier:"S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createS3PublicAccessBlockRule(){return this.createConfigRule({name:"s3-bucket-public-read-prohibited",description:"Checks that S3 buckets do not allow public read access",source:"AWS_MANAGED",identifier:"S3_BUCKET_PUBLIC_READ_PROHIBITED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createS3VersioningRule(){return this.createConfigRule({name:"s3-bucket-versioning-enabled",description:"Checks whether versioning is enabled for S3 buckets",source:"AWS_MANAGED",identifier:"S3_BUCKET_VERSIONING_ENABLED",scope:{complianceResourceTypes:["AWS::S3::Bucket"]}})}createRdsEncryptionRule(){return this.createConfigRule({name:"rds-storage-encrypted",description:"Checks whether storage encryption is enabled for RDS DB instances",source:"AWS_MANAGED",identifier:"RDS_STORAGE_ENCRYPTED",scope:{complianceResourceTypes:["AWS::RDS::DBInstance"]}})}createRdsSnapshotEncryptionRule(){return this.createConfigRule({name:"rds-snapshots-public-prohibited",description:"Checks if RDS snapshots are public",source:"AWS_MANAGED",identifier:"RDS_SNAPSHOTS_PUBLIC_PROHIBITED",scope:{complianceResourceTypes:["AWS::RDS::DBSnapshot","AWS::RDS::DBClusterSnapshot"]}})}createRdsBackupRule(n=7){return this.createConfigRule({name:"db-backup-enabled",description:"Checks whether RDS DB instances have backups enabled",source:"AWS_MANAGED",identifier:"DB_BACKUP_ENABLED",inputParameters:{backupRetentionPeriod:n},scope:{complianceResourceTypes:["AWS::RDS::DBInstance"]}})}createEc2InstanceProfileRule(){return this.createConfigRule({name:"ec2-instance-managed-by-systems-manager",description:"Checks if EC2 instances are managed by Systems Manager",source:"AWS_MANAGED",identifier:"EC2_INSTANCE_MANAGED_BY_SSM",scope:{complianceResourceTypes:["AWS::EC2::Instance"]}})}createEbsEncryptionRule(){return this.createConfigRule({name:"encrypted-volumes",description:"Checks whether EBS volumes are encrypted",source:"AWS_MANAGED",identifier:"ENCRYPTED_VOLUMES",scope:{complianceResourceTypes:["AWS::EC2::Volume"]}})}createIamPasswordPolicyRule(){return this.createConfigRule({name:"iam-password-policy",description:"Checks whether the IAM password policy meets specified requirements",source:"AWS_MANAGED",identifier:"IAM_PASSWORD_POLICY",inputParameters:{RequireUppercaseCharacters:!0,RequireLowercaseCharacters:!0,RequireSymbols:!0,RequireNumbers:!0,MinimumPasswordLength:14,PasswordReusePrevention:24,MaxPasswordAge:90}})}createIamMfaRule(){return this.createConfigRule({name:"iam-user-mfa-enabled",description:"Checks whether IAM users have MFA enabled",source:"AWS_MANAGED",identifier:"IAM_USER_MFA_ENABLED"})}createRootAccountMfaRule(){return this.createConfigRule({name:"root-account-mfa-enabled",description:"Checks whether the root account has MFA enabled",source:"AWS_MANAGED",identifier:"ROOT_ACCOUNT_MFA_ENABLED"})}createVpcFlowLogsRule(){return this.createConfigRule({name:"vpc-flow-logs-enabled",description:"Checks whether VPC Flow Logs is enabled",source:"AWS_MANAGED",identifier:"VPC_FLOW_LOGS_ENABLED",scope:{complianceResourceTypes:["AWS::EC2::VPC"]}})}createCloudTrailEnabledRule(){return this.createConfigRule({name:"cloudtrail-enabled",description:"Checks whether CloudTrail is enabled",source:"AWS_MANAGED",identifier:"CLOUD_TRAIL_ENABLED",maxExecutionFrequency:"TwentyFour_Hours"})}createCloudWatchAlarmRule(){return this.createConfigRule({name:"cloudwatch-alarm-action-check",description:"Checks whether CloudWatch alarms have actions configured",source:"AWS_MANAGED",identifier:"CLOUDWATCH_ALARM_ACTION_CHECK",inputParameters:{alarmActionRequired:!0,insufficientDataActionRequired:!1,okActionRequired:!1},scope:{complianceResourceTypes:["AWS::CloudWatch::Alarm"]}})}createCustomLambdaRule(n){return this.createConfigRule({name:n.name,description:n.description,source:"CUSTOM_LAMBDA",lambdaFunctionArn:n.lambdaFunctionArn,scope:n.resourceTypes?{complianceResourceTypes:n.resourceTypes}:void 0,maxExecutionFrequency:n.maxExecutionFrequency,inputParameters:n.inputParameters})}createCompliancePreset(n){let i=[];switch(n){case"hipaa":i.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createRdsBackupRule(7),this.createVpcFlowLogsRule());break;case"pci-dss":i.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamPasswordPolicyRule(),this.createIamMfaRule(),this.createRootAccountMfaRule(),this.createVpcFlowLogsRule());break;case"sox":i.push(this.createS3VersioningRule(),this.createCloudTrailEnabledRule(),this.createRdsBackupRule(30),this.createIamPasswordPolicyRule());break;case"gdpr":i.push(this.createS3EncryptionRule(),this.createRdsEncryptionRule(),this.createEbsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createRdsSnapshotEncryptionRule());break;case"basic":i.push(this.createS3EncryptionRule(),this.createS3PublicAccessBlockRule(),this.createRdsEncryptionRule(),this.createCloudTrailEnabledRule(),this.createIamMfaRule(),this.createRootAccountMfaRule());break}return i}getConfigRule(n){return this.configRules.get(n)}listConfigRules(){return Array.from(this.configRules.values())}getConfigRecorder(n){return this.configRecorders.get(n)}listConfigRecorders(){return Array.from(this.configRecorders.values())}getDeliveryChannel(n){return this.deliveryChannels.get(n)}listDeliveryChannels(){return Array.from(this.deliveryChannels.values())}generateConfigRuleCF(n){let i={Type:"AWS::Config::ConfigRule",Properties:{ConfigRuleName:n.name,Description:n.description,Source:{Owner:n.source==="AWS_MANAGED"?"AWS":"CUSTOM_LAMBDA"}}};if(n.source==="AWS_MANAGED"&&n.identifier)i.Properties.Source.SourceIdentifier=n.identifier;if(n.source==="CUSTOM_LAMBDA"&&n.lambdaFunctionArn)i.Properties.Source.SourceIdentifier=n.lambdaFunctionArn,i.Properties.Source.SourceDetails=[{EventSource:"aws.config",MessageType:"ConfigurationItemChangeNotification"}];if(n.inputParameters)i.Properties.InputParameters=JSON.stringify(n.inputParameters);if(n.scope){if(i.Properties.Scope={},n.scope.complianceResourceTypes)i.Properties.Scope.ComplianceResourceTypes=n.scope.complianceResourceTypes;if(n.scope.tagKey)i.Properties.Scope.TagKey=n.scope.tagKey;if(n.scope.tagValue)i.Properties.Scope.TagValue=n.scope.tagValue}if(n.maxExecutionFrequency)i.Properties.MaximumExecutionFrequency=n.maxExecutionFrequency;return i}generateConfigRecorderCF(n){return{Type:"AWS::Config::ConfigurationRecorder",Properties:{Name:n.name,RoleArn:n.roleArn,RecordingGroup:n.recordingGroup||{AllSupported:!0,IncludeGlobalResourceTypes:!0}}}}generateDeliveryChannelCF(n){return{Type:"AWS::Config::DeliveryChannel",Properties:{Name:n.name,S3BucketName:n.s3BucketName,...n.s3KeyPrefix&&{S3KeyPrefix:n.s3KeyPrefix},...n.snsTopicArn&&{SnsTopicARN:n.snsTopicArn},...n.configSnapshotDeliveryProperties&&{ConfigSnapshotDeliveryProperties:n.configSnapshotDeliveryProperties}}}}clear(){this.configRules.clear(),this.configRecorders.clear(),this.deliveryChannels.clear(),this.ruleCounter=0}}var ZC=new Wg;class Jg{trails=new Map;trailCounter=0;createTrail(n){let i=`trail-${Date.now()}-${this.trailCounter++}`,s={id:i,...n};return this.trails.set(i,s),s}createOrganizationTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"organization-trail",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:n.kmsKeyId,cloudWatchLogsLogGroupArn:n.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:n.cloudWatchLogsRoleArn})}createSecurityAuditTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"security-audit",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,kmsKeyId:n.kmsKeyId,cloudWatchLogsLogGroupArn:n.cloudWatchLogsLogGroupArn,cloudWatchLogsRoleArn:n.cloudWatchLogsRoleArn,eventSelectors:[{readWriteType:"All",includeManagementEvents:!0,excludeManagementEventSources:[]}],insightSelectors:[{insightType:"ApiCallRateInsight"},{insightType:"ApiErrorRateInsight"}]})}createDataEventsTrail(n){let i=[];if(n.s3DataBuckets&&n.s3DataBuckets.length>0)i.push({type:"AWS::S3::Object",values:n.s3DataBuckets.map((s)=>`arn:aws:s3:::${s}/*`)});if(n.lambdaFunctions&&n.lambdaFunctions.length>0)i.push({type:"AWS::Lambda::Function",values:n.lambdaFunctions});return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,s3KeyPrefix:"data-events",includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"All",includeManagementEvents:!1,dataResources:i}]})}createAdvancedTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,advancedEventSelectors:n.selectors})}createReadOnlyTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"ReadOnly",includeManagementEvents:!0}]})}createWriteOnlyTrail(n){return this.createTrail({name:n.name,s3BucketName:n.s3BucketName,includeGlobalServiceEvents:!0,isMultiRegionTrail:!0,enableLogFileValidation:!0,eventSelectors:[{readWriteType:"WriteOnly",includeManagementEvents:!0}]})}getTrail(n){return this.trails.get(n)}listTrails(){return Array.from(this.trails.values())}generateTrailCF(n){let i={Type:"AWS::CloudTrail::Trail",Properties:{TrailName:n.name,S3BucketName:n.s3BucketName,IsLogging:!0,IncludeGlobalServiceEvents:n.includeGlobalServiceEvents??!0,IsMultiRegionTrail:n.isMultiRegionTrail??!0,EnableLogFileValidation:n.enableLogFileValidation??!0}};if(n.s3KeyPrefix)i.Properties.S3KeyPrefix=n.s3KeyPrefix;if(n.cloudWatchLogsLogGroupArn)i.Properties.CloudWatchLogsLogGroupArn=n.cloudWatchLogsLogGroupArn;if(n.cloudWatchLogsRoleArn)i.Properties.CloudWatchLogsRoleArn=n.cloudWatchLogsRoleArn;if(n.snsTopicName)i.Properties.SnsTopicName=n.snsTopicName;if(n.kmsKeyId)i.Properties.KMSKeyId=n.kmsKeyId;if(n.eventSelectors)i.Properties.EventSelectors=n.eventSelectors.map((s)=>({ReadWriteType:s.readWriteType,IncludeManagementEvents:s.includeManagementEvents??!0,...s.dataResources&&{DataResources:s.dataResources.map((o)=>({Type:o.type,Values:o.values}))},...s.excludeManagementEventSources&&{ExcludeManagementEventSources:s.excludeManagementEventSources}}));if(n.insightSelectors)i.Properties.InsightSelectors=n.insightSelectors.map((s)=>({InsightType:s.insightType}));if(n.advancedEventSelectors)i.Properties.AdvancedEventSelectors=n.advancedEventSelectors.map((s)=>({Name:s.name,FieldSelectors:s.fieldSelectors.map((o)=>({Field:o.field,...o.equals&&{Equals:o.equals},...o.startsWith&&{StartsWith:o.startsWith},...o.endsWith&&{EndsWith:o.endsWith},...o.notEquals&&{NotEquals:o.notEquals},...o.notStartsWith&&{NotStartsWith:o.notStartsWith},...o.notEndsWith&&{NotEndsWith:o.notEndsWith}}))}));return i}generateBucketPolicy(n,i){return{Version:"2012-10-17",Statement:[{Sid:"AWSCloudTrailAclCheck",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:GetBucketAcl",Resource:`arn:aws:s3:::${n}`},{Sid:"AWSCloudTrailWrite",Effect:"Allow",Principal:{Service:"cloudtrail.amazonaws.com"},Action:"s3:PutObject",Resource:i.map((s)=>`arn:aws:s3:::${n}/AWSLogs/${s}/*`),Condition:{StringEquals:{"s3:x-amz-acl":"bucket-owner-full-control"}}}]}}clear(){this.trails.clear(),this.trailCounter=0}}var eE=new Jg;class Xg{detectors=new Map;threatIntelSets=new Map;ipSets=new Map;filters=new Map;detectorCounter=0;threatIntelCounter=0;ipSetCounter=0;filterCounter=0;createDetector(n){let i=`detector-${Date.now()}-${this.detectorCounter++}`,s={id:i,...n};return this.detectors.set(i,s),s}createComprehensiveDetector(){return this.createDetector({enable:!0,findingPublishingFrequency:"FIFTEEN_MINUTES",dataSources:{s3Logs:{enable:!0},kubernetes:{auditLogs:{enable:!0}},malwareProtection:{scanEc2InstanceWithFindings:{ebsVolumes:{enable:!0}}}},features:[{name:"S3_DATA_EVENTS",status:"ENABLED"},{name:"EKS_AUDIT_LOGS",status:"ENABLED"},{name:"EBS_MALWARE_PROTECTION",status:"ENABLED"},{name:"RDS_LOGIN_EVENTS",status:"ENABLED"},{name:"LAMBDA_NETWORK_LOGS",status:"ENABLED"}]})}createBasicDetector(){return this.createDetector({enable:!0,findingPublishingFrequency:"SIX_HOURS"})}createThreatIntelSet(n){let i=`threat-intel-${Date.now()}-${this.threatIntelCounter++}`,s={id:i,...n};return this.threatIntelSets.set(i,s),s}createIPSet(n){let i=`ip-set-${Date.now()}-${this.ipSetCounter++}`,s={id:i,...n};return this.ipSets.set(i,s),s}createFindingFilter(n){let i=`filter-${Date.now()}-${this.filterCounter++}`,s={id:i,...n};return this.filters.set(i,s),s}createLowSeverityArchiveFilter(n){return this.createFindingFilter({detectorId:n,name:"archive-low-severity",description:"Automatically archive low severity findings",action:"ARCHIVE",rank:1,findingCriteria:{criterion:{severity:{lt:4}}}})}createFindingTypeFilter(n,i,s){return this.createFindingFilter({detectorId:n,name:`filter-finding-types-${s.toLowerCase()}`,description:`${s==="ARCHIVE"?"Archive":"Keep"} specific finding types`,action:s,rank:2,findingCriteria:{criterion:{type:{eq:i}}}})}createTrustedIPFilter(n,i){return this.createFindingFilter({detectorId:n,name:"trusted-ip-addresses",description:"Archive findings from trusted IP addresses",action:"ARCHIVE",rank:3,findingCriteria:{criterion:{"resource.instanceDetails.networkInterfaces.privateIpAddress":{eq:i}}}})}getDetector(n){return this.detectors.get(n)}listDetectors(){return Array.from(this.detectors.values())}getThreatIntelSet(n){return this.threatIntelSets.get(n)}listThreatIntelSets(){return Array.from(this.threatIntelSets.values())}getIPSet(n){return this.ipSets.get(n)}listIPSets(){return Array.from(this.ipSets.values())}getFindingFilter(n){return this.filters.get(n)}listFindingFilters(){return Array.from(this.filters.values())}generateDetectorCF(n){let i={Type:"AWS::GuardDuty::Detector",Properties:{Enable:n.enable}};if(n.findingPublishingFrequency)i.Properties.FindingPublishingFrequency=n.findingPublishingFrequency;if(n.dataSources){if(i.Properties.DataSources={},n.dataSources.s3Logs)i.Properties.DataSources.S3Logs={Enable:n.dataSources.s3Logs.enable};if(n.dataSources.kubernetes)i.Properties.DataSources.Kubernetes={AuditLogs:{Enable:n.dataSources.kubernetes.auditLogs.enable}};if(n.dataSources.malwareProtection)i.Properties.DataSources.MalwareProtection={ScanEc2InstanceWithFindings:{EbsVolumes:{Enable:n.dataSources.malwareProtection.scanEc2InstanceWithFindings.ebsVolumes.enable}}}}if(n.features)i.Properties.Features=n.features.map((s)=>({Name:s.name,Status:s.status,...s.additionalConfiguration&&{AdditionalConfiguration:s.additionalConfiguration}}));return i}generateThreatIntelSetCF(n){return{Type:"AWS::GuardDuty::ThreatIntelSet",Properties:{DetectorId:n.detectorId,Name:n.name,Format:n.format,Location:n.location,Activate:n.activate}}}generateIPSetCF(n){return{Type:"AWS::GuardDuty::IPSet",Properties:{DetectorId:n.detectorId,Name:n.name,Format:n.format,Location:n.location,Activate:n.activate}}}generateFilterCF(n){return{Type:"AWS::GuardDuty::Filter",Properties:{DetectorId:n.detectorId,Name:n.name,Description:n.description,Action:n.action,Rank:n.rank,FindingCriteria:{Criterion:n.findingCriteria.criterion}}}}clear(){this.detectors.clear(),this.threatIntelSets.clear(),this.ipSets.clear(),this.filters.clear(),this.detectorCounter=0,this.threatIntelCounter=0,this.ipSetCounter=0,this.filterCounter=0}}var tE=new Xg;class jr{hubs=new Map;hubCounter=0;ruleCounter=0;static Standards={AWS_FOUNDATIONAL_SECURITY:{arn:"arn:aws:securityhub:::ruleset/aws-foundational-security-best-practices/v/1.0.0",name:"AWS Foundational Security Best Practices",description:"AWS recommended security best practices"},CIS_AWS_FOUNDATIONS_1_2:{arn:"arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.2.0",name:"CIS AWS Foundations Benchmark v1.2.0",description:"CIS AWS Foundations Benchmark v1.2.0"},CIS_AWS_FOUNDATIONS_1_4:{arn:"arn:aws:securityhub:::ruleset/cis-aws-foundations-benchmark/v/1.4.0",name:"CIS AWS Foundations Benchmark v1.4.0",description:"CIS AWS Foundations Benchmark v1.4.0"},PCI_DSS:{arn:"arn:aws:securityhub:us-east-1::standards/pci-dss/v/3.2.1",name:"PCI DSS v3.2.1",description:"Payment Card Industry Data Security Standard"},NIST_800_53:{arn:"arn:aws:securityhub:us-east-1::standards/nist-800-53/v/5.0.0",name:"NIST SP 800-53 Rev. 5",description:"NIST Special Publication 800-53 Revision 5"}};createHub(n){let i=`hub-${Date.now()}-${this.hubCounter++}`,s={id:i,...n};return this.hubs.set(i,s),s}createComprehensiveHub(){return this.createHub({enable:!0,controlFindingGenerator:"SECURITY_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...jr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0},{id:"cis-1-4",...jr.Standards.CIS_AWS_FOUNDATIONS_1_4,enabled:!0},{id:"pci-dss",...jr.Standards.PCI_DSS,enabled:!0}]})}createBasicHub(){return this.createHub({enable:!0,controlFindingGenerator:"STANDARD_CONTROL",enableDefaultStandards:!0,standards:[{id:"aws-foundational",...jr.Standards.AWS_FOUNDATIONAL_SECURITY,enabled:!0}]})}createLowSeveritySuppressionRule(){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Suppress Low Severity Informational Findings",description:"Automatically suppress informational findings",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Automatically suppressed low severity finding",updatedBy:"SecurityHub Automation"}}}],criteria:{severityLabel:[{value:"INFORMATIONAL",comparison:"EQUALS"}],recordState:[{value:"ACTIVE",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:1}}createResourceTypeNotificationRule(n){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Notify on Critical Resource Findings",description:"Set findings for critical resources to NOTIFIED status",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"NOTIFIED"},note:{text:"Critical resource finding requires attention",updatedBy:"SecurityHub Automation"}}}],criteria:{resourceType:n.map((i)=>({value:i,comparison:"EQUALS"})),severityLabel:[{value:"HIGH",comparison:"EQUALS"},{value:"CRITICAL",comparison:"EQUALS"}],workflowStatus:[{value:"NEW",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:2}}createComplianceFailureRule(){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:"Flag Compliance Failures",description:"Increase severity for compliance failures",actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{severity:{label:"HIGH"},workflow:{status:"NOTIFIED"},note:{text:"Compliance failure detected - requires immediate attention",updatedBy:"SecurityHub Automation"}}}],criteria:{complianceStatus:[{value:"FAILED",comparison:"EQUALS"}],recordState:[{value:"ACTIVE",comparison:"EQUALS"}]},ruleStatus:"ENABLED",ruleOrder:3}}createFalsePositiveSuppressionRule(n,i){return{id:`rule-${Date.now()}-${this.ruleCounter++}`,ruleName:`Suppress False Positives - ${n}`,description:`Automatically suppress known false positives from ${n}`,actions:[{type:"FINDING_FIELDS_UPDATE",findingFieldsUpdate:{workflow:{status:"SUPPRESSED"},note:{text:"Known false positive - automatically suppressed",updatedBy:"SecurityHub Automation"}}}],criteria:{productName:[{value:n,comparison:"EQUALS"}],title:i.map((s)=>({value:s,comparison:"PREFIX"}))},ruleStatus:"ENABLED",ruleOrder:10}}getHub(n){return this.hubs.get(n)}listHubs(){return Array.from(this.hubs.values())}generateHubCF(n){let i={Type:"AWS::SecurityHub::Hub",Properties:{}};if(n.controlFindingGenerator)i.Properties.ControlFindingGenerator=n.controlFindingGenerator;if(n.enableDefaultStandards!==void 0)i.Properties.EnableDefaultStandards=n.enableDefaultStandards;return i}generateStandardCF(n){let i={Type:"AWS::SecurityHub::Standard",Properties:{StandardsArn:n.arn}};if(n.disabledControls&&n.disabledControls.length>0)i.Properties.DisabledStandardsControls=n.disabledControls.map((s)=>({StandardsControlArn:s,Reason:"Disabled by configuration"}));return i}generateAutomationRuleCF(n){return{Type:"AWS::SecurityHub::AutomationRule",Properties:{RuleName:n.ruleName,Description:n.description,Actions:n.actions.map((i)=>({Type:i.type,FindingFieldsUpdate:i.findingFieldsUpdate})),Criteria:n.criteria,RuleStatus:n.ruleStatus,RuleOrder:n.ruleOrder}}}clear(){this.hubs.clear(),this.hubCounter=0,this.ruleCounter=0}}var rE=new jr;class Yg{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;createDeployment(n){let i=`bg-deployment-${Date.now()}-${this.deploymentCounter++}`,s={id:i,...n};return this.deployments.set(i,s),s}createALBDeployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:n.listenerArn,switchoverTimeSeconds:0},autoPromote:n.autoPromote,healthCheckConfig:n.healthCheckConfig})}createRoute53Deployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"route53",hostedZoneId:n.hostedZoneId,switchoverTimeSeconds:n.switchoverTimeSeconds||60}})}createECSDeployment(n){return this.createDeployment({name:n.name,blueEnvironment:{name:"blue",targetGroupArn:n.blueTargetGroupArn,taskDefinitionArn:n.blueTaskDefinitionArn,weight:100},greenEnvironment:{name:"green",targetGroupArn:n.greenTargetGroupArn,taskDefinitionArn:n.greenTaskDefinitionArn,weight:0},activeEnvironment:"blue",routingConfig:{type:"alb",listenerArn:n.listenerArn},autoRollback:n.autoRollback??!0})}async executeDeployment(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);let o={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!1,errors:[]};console.log(`${i?"[DRY RUN] ":""}Starting blue/green deployment: ${s.name}`),console.log(` Active environment: ${s.activeEnvironment}`),console.log(` Routing type: ${s.routingConfig.type}`);let c=s.activeEnvironment==="blue"?"green":"blue";if(console.log(` Switching to: ${c}`),console.log(`\\n1. Deploying to ${c} environment`),!i)await new Promise((l)=>setTimeout(l,100));if(console.log(`\\n2. Running health checks on ${c} environment`),s.healthCheckConfig){let l=await this.runHealthChecks(s,c,i);if(o.healthChecksPassed=l,!l){if(o.errors?.push("Health checks failed"),o.endTime=new Date,s.autoRollback)console.log(" Auto-rollback enabled - keeping current environment active"),o.rolledBackAt=new Date;return this.recordDeployment(n,o),o}}else o.healthChecksPassed=!0;if(console.log(`\\n3. Switching traffic to ${c} environment`),!i)s.activeEnvironment=c,o.switchedAt=new Date;if(console.log(`\\n4. Monitoring ${c} environment`),!i)await new Promise((l)=>setTimeout(l,100));return o.success=!0,o.endTime=new Date,console.log("\\n✓ Deployment completed successfully"),this.recordDeployment(n,o),o}async rollback(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);let s={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,healthChecksPassed:!0,errors:[]};console.log(`Rolling back deployment: ${i.name}`);let o=i.activeEnvironment==="blue"?"green":"blue";return i.activeEnvironment=o,s.success=!0,s.rolledBackAt=new Date,s.endTime=new Date,console.log(` Switched back to: ${o}`),this.recordDeployment(n,s),s}async runHealthChecks(n,i,s){let o=n.healthCheckConfig;if(console.log(` Health check path: ${o.path||"/"}`),console.log(` Healthy threshold: ${o.healthyThreshold}`),console.log(` Interval: ${o.interval}s`),s)return console.log(" [SKIPPED - DRY RUN]"),!0;let c=0,l=o.healthyThreshold+2;for(let u=0;u<l;u++)if(await new Promise((h)=>setTimeout(h,50)),Math.random()>0.1){if(c++,console.log(` Check ${u+1}: ✓ Healthy (${c}/${o.healthyThreshold})`),c>=o.healthyThreshold)return!0}else c=0,console.log(` Check ${u+1}: ✗ Unhealthy`);return!1}recordDeployment(n,i){if(!this.deploymentHistory.has(n))this.deploymentHistory.set(n,[]);this.deploymentHistory.get(n).push(i)}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(n){return this.deploymentHistory.get(n)||[]}generateALBListenerCF(n){let i=n.activeEnvironment==="blue"?n.blueEnvironment:n.greenEnvironment;return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:n.routingConfig.listenerArn,Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",TargetGroupArn:i.targetGroupArn}]}}}generateRoute53RecordSetCF(n,i){return[{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.routingConfig.hostedZoneId,Name:i,Type:"A",SetIdentifier:"blue",Weight:n.activeEnvironment==="blue"?100:0,AliasTarget:{HostedZoneId:n.routingConfig.hostedZoneId,DNSName:n.blueEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}},{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.routingConfig.hostedZoneId,Name:i,Type:"A",SetIdentifier:"green",Weight:n.activeEnvironment==="green"?100:0,AliasTarget:{HostedZoneId:n.routingConfig.hostedZoneId,DNSName:n.greenEnvironment.targetGroupArn,EvaluateTargetHealth:!0}}}]}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var nE=new Yg;class yo{deployments=new Map;deploymentHistory=new Map;deploymentCounter=0;resultCounter=0;static Strategies={CONSERVATIVE:[{name:"Initial Canary",trafficPercentage:10,durationMinutes:10},{name:"Quarter Traffic",trafficPercentage:25,durationMinutes:10},{name:"Half Traffic",trafficPercentage:50,durationMinutes:15},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],BALANCED:[{name:"Initial Canary",trafficPercentage:20,durationMinutes:5},{name:"Half Traffic",trafficPercentage:50,durationMinutes:10},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],AGGRESSIVE:[{name:"Half Traffic",trafficPercentage:50,durationMinutes:5},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}],LINEAR_10:[{name:"Canary 10%",trafficPercentage:10,durationMinutes:5},{name:"Canary 20%",trafficPercentage:20,durationMinutes:5},{name:"Canary 30%",trafficPercentage:30,durationMinutes:5},{name:"Canary 40%",trafficPercentage:40,durationMinutes:5},{name:"Canary 50%",trafficPercentage:50,durationMinutes:5},{name:"Canary 60%",trafficPercentage:60,durationMinutes:5},{name:"Canary 70%",trafficPercentage:70,durationMinutes:5},{name:"Canary 80%",trafficPercentage:80,durationMinutes:5},{name:"Canary 90%",trafficPercentage:90,durationMinutes:5},{name:"Full Traffic",trafficPercentage:100,durationMinutes:5}]};createDeployment(n){let i=`canary-${Date.now()}-${this.deploymentCounter++}`,s={id:i,...n};return this.deployments.set(i,s),s}createLambdaCanaryDeployment(n){let i=n.strategy||"BALANCED",s=yo.Strategies[i].map((o)=>({...o,alarmThresholds:{errorRate:n.errorRateThreshold||1,latencyP99:n.latencyThreshold||1000}}));return this.createDeployment({name:n.name,baselineVersion:{version:"baseline",functionVersionArn:n.baselineVersionArn,weight:100},canaryVersion:{version:"canary",functionVersionArn:n.canaryVersionArn,weight:0},stages:s,currentStage:0,status:"pending",autoPromote:n.autoPromote??!0,autoRollback:!0})}createECSCanaryDeployment(n){let i=n.strategy||"CONSERVATIVE",s=yo.Strategies[i];return this.createDeployment({name:n.name,baselineVersion:{version:"baseline",taskDefinitionArn:n.baselineTaskDefinitionArn,targetGroupArn:n.baselineTargetGroupArn,weight:100},canaryVersion:{version:"canary",taskDefinitionArn:n.canaryTaskDefinitionArn,targetGroupArn:n.canaryTargetGroupArn,weight:0},stages:s,currentStage:0,status:"pending",autoRollback:!0})}async executeDeployment(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);let o={success:!1,deploymentId:`result-${Date.now()}-${this.resultCounter++}`,startTime:new Date,completedStages:0,rolledBack:!1};console.log(`${i?"[DRY RUN] ":""}Starting canary deployment: ${s.name}`),console.log(` Strategy: ${s.stages.length} stages`),console.log(` Auto-promote: ${s.autoPromote}`),console.log(` Auto-rollback: ${s.autoRollback}`),console.log(""),s.status="in_progress";for(let c=0;c<s.stages.length;c++){let l=s.stages[c];if(s.currentStage=c,console.log(`Stage ${c+1}/${s.stages.length}: ${l.name}`),console.log(` Traffic: ${l.trafficPercentage}% canary, ${100-l.trafficPercentage}% baseline`),console.log(` Duration: ${l.durationMinutes} minutes`),!i)s.baselineVersion.weight=100-l.trafficPercentage,s.canaryVersion.weight=l.trafficPercentage;if(!await this.monitorStage(s,l,i)){if(console.log(" ✗ Stage failed - metrics exceeded thresholds"),s.autoRollback)console.log("\\n Rolling back deployment..."),await this.rollback(n,i),o.rolledBack=!0,o.reason="Metrics exceeded thresholds";return o.endTime=new Date,s.status="rolled_back",this.recordDeployment(n,o),o}console.log(" ✓ Stage completed successfully"),o.completedStages++,console.log("")}return s.status="completed",o.success=!0,o.endTime=new Date,console.log("✓ Canary deployment completed successfully"),this.recordDeployment(n,o),o}async monitorStage(n,i,s){if(console.log(" Monitoring metrics..."),s)return console.log(" [SKIPPED - DRY RUN]"),!0;await new Promise((c)=>setTimeout(c,100));let o={baselineErrorRate:Math.random()*0.5,canaryErrorRate:Math.random()*0.8,baselineLatencyP99:200+Math.random()*100,canaryLatencyP99:180+Math.random()*150,baselineRequestCount:Math.floor(Math.random()*1000)+500,canaryRequestCount:Math.floor((Math.random()*1000+500)*i.trafficPercentage/100)};if(n.metrics=o,console.log(` Baseline: ${o.baselineErrorRate.toFixed(2)}% errors, ${o.baselineLatencyP99.toFixed(0)}ms P99`),console.log(` Canary: ${o.canaryErrorRate.toFixed(2)}% errors, ${o.canaryLatencyP99.toFixed(0)}ms P99`),i.alarmThresholds){let{errorRate:c,latencyP99:l}=i.alarmThresholds;if(c&&o.canaryErrorRate>c)return console.log(` ⚠ Error rate exceeded threshold: ${o.canaryErrorRate.toFixed(2)}% > ${c}%`),!1;if(l&&o.canaryLatencyP99>l)return console.log(` ⚠ Latency P99 exceeded threshold: ${o.canaryLatencyP99.toFixed(0)}ms > ${l}ms`),!1}return!0}async rollback(n,i=!1){let s=this.deployments.get(n);if(!s)throw Error(`Deployment not found: ${n}`);if(console.log(`${i?"[DRY RUN] ":""}Rolling back canary deployment: ${s.name}`),!i)s.baselineVersion.weight=100,s.canaryVersion.weight=0,s.status="rolled_back";console.log(" Traffic restored to baseline: 100%")}promoteCanary(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);console.log(`Promoting canary to baseline: ${i.name}`);let s=i.baselineVersion;i.baselineVersion=i.canaryVersion,i.canaryVersion=s,i.baselineVersion.weight=100,i.canaryVersion.weight=0,i.status="completed",console.log(" Canary promoted successfully")}recordDeployment(n,i){if(!this.deploymentHistory.has(n))this.deploymentHistory.set(n,[]);this.deploymentHistory.get(n).push(i)}getDeployment(n){return this.deployments.get(n)}listDeployments(){return Array.from(this.deployments.values())}getDeploymentHistory(n){return this.deploymentHistory.get(n)||[]}generateLambdaAliasCF(n,i){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:{Ref:"LambdaFunction"},Name:i,FunctionVersion:n.canaryVersion.version,RoutingConfig:{AdditionalVersionWeights:[{FunctionVersion:n.baselineVersion.version,FunctionWeight:n.baselineVersion.weight/100}]}}}}generateALBListenerRuleCF(n){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:[{TargetGroupArn:n.baselineVersion.targetGroupArn,Weight:n.baselineVersion.weight},{TargetGroupArn:n.canaryVersion.targetGroupArn,Weight:n.canaryVersion.weight}],TargetGroupStickinessConfig:{Enabled:!1}}}]}}}clear(){this.deployments.clear(),this.deploymentHistory.clear(),this.deploymentCounter=0,this.resultCounter=0}}var iE=new yo;class Zg{tests=new Map;testCounter=0;createTest(n){let i=`abtest-${Date.now()}-${this.testCounter++}`,s={id:i,...n};return this.tests.set(i,s),s}createSimpleABTest(n){let i=n.variantTrafficPercentage||50;return this.createTest({name:n.name,description:n.description,variants:[{id:"control",name:"Control",description:"Original version",trafficPercentage:100-i,targetGroupArn:n.controlTargetGroupArn,weight:100-i},{id:"variant-a",name:"Variant A",description:"Test version",trafficPercentage:i,targetGroupArn:n.variantTargetGroupArn,weight:i}],routingStrategy:{type:n.stickySession?"cookie":"random",cookieName:n.stickySession?"ab_variant":void 0,stickySession:n.stickySession??!1,sessionDuration:1440},startTime:new Date,status:"draft"})}createMultivariateTest(n){let i=n.variants.reduce((s,o)=>s+o.trafficPercentage,0);if(i!==100)throw Error(`Traffic percentages must sum to 100, got ${i}`);return this.createTest({name:n.name,description:n.description,variants:n.variants.map((s,o)=>({id:`variant-${o}`,name:s.name,description:s.description,trafficPercentage:s.trafficPercentage,targetGroupArn:s.targetGroupArn,weight:s.trafficPercentage})),routingStrategy:n.routingStrategy||{type:"random",stickySession:!1},startTime:new Date,status:"draft"})}createHeaderBasedTest(n){return this.createTest({name:n.name,description:`Route based on ${n.headerName} header`,variants:[{id:"control",name:"Control",trafficPercentage:50,targetGroupArn:n.controlTargetGroupArn,weight:50},{id:"variant-a",name:"Variant A",trafficPercentage:50,targetGroupArn:n.variantTargetGroupArn,weight:50}],routingStrategy:{type:"header",headerName:n.headerName,stickySession:!1},startTime:new Date,status:"draft"})}createGeoBasedTest(n){return this.createTest({name:n.name,description:"Route based on geographic location",variants:[{id:"control",name:"Control (Rest of World)",trafficPercentage:50,targetGroupArn:n.controlTargetGroupArn,weight:50},{id:"variant-a",name:`Variant A (${n.regions.join(", ")})`,trafficPercentage:50,targetGroupArn:n.variantTargetGroupArn,weight:50}],routingStrategy:{type:"geo",stickySession:!0,sessionDuration:1440},startTime:new Date,status:"draft"})}startTest(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);if(i.status!=="draft"&&i.status!=="paused")throw Error(`Cannot start test in ${i.status} status`);i.status="active",i.startTime=new Date,console.log(`Started A/B test: ${i.name}`),console.log(` Variants: ${i.variants.length}`),i.variants.forEach((s)=>{console.log(` - ${s.name}: ${s.trafficPercentage}%`)})}pauseTest(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);i.status="paused",console.log(`Paused A/B test: ${i.name}`)}updateTrafficSplit(n,i,s){let o=this.tests.get(n);if(!o)throw Error(`Test not found: ${n}`);let c=o.variants.find((u)=>u.id===i);if(!c)throw Error(`Variant not found: ${i}`);let l=c.trafficPercentage;c.trafficPercentage=s,c.weight=s,console.log(`Updated ${c.name} traffic: ${l}% → ${s}%`)}analyzeResults(n){let i=this.tests.get(n);if(!i)throw Error(`Test not found: ${n}`);if(!i.metrics)i.metrics=this.collectMetrics(i);let s=i.variants[0],o=0;for(let f of i.variants){let S=i.metrics.variants[f.id];if(S&&S.conversionRate>o)o=S.conversionRate,s=f}let c=i.metrics.variants.control||i.metrics.variants[i.variants[0].id],l=i.metrics.variants[s.id],u=(l.conversionRate-c.conversionRate)/c.conversionRate*100,h=100,y=l.requests>h&&c.requests>h&&Math.abs(u)>10;return{testId:n,winningVariant:s.name,confidence:y?95:75,improvement:u,statisticalSignificance:y,metrics:i.metrics,recommendation:this.generateRecommendation(u,y,s.name)}}declareWinner(n,i){let s=this.tests.get(n);if(!s)throw Error(`Test not found: ${n}`);let o=s.variants.find((c)=>c.id===i);if(!o)throw Error(`Variant not found: ${i}`);s.variants.forEach((c)=>{if(c.id===i)c.trafficPercentage=100,c.weight=100;else c.trafficPercentage=0,c.weight=0}),s.status="completed",s.endTime=new Date,s.winner=i,console.log(`Declared winner: ${o.name}`),console.log(` All traffic now routed to ${o.name}`)}collectMetrics(n){let i={},s=0;for(let o of n.variants){let c=Math.floor(Math.random()*1000)+500,l=Math.floor(c*(Math.random()*0.1+0.05)),u=l/c*100;i[o.id]={requests:c,conversions:l,conversionRate:u,averageLatency:150+Math.random()*100,errorRate:Math.random()*0.5,revenue:l*(Math.random()*50+100)},s+=c}return{variants:i,totalRequests:s,startTime:n.startTime,lastUpdated:new Date}}generateRecommendation(n,i,s){if(!i)return"Continue test - sample size too small or no significant difference detected";if(n>20)return`Strong winner detected - ${s} shows ${n.toFixed(1)}% improvement. Recommend deploying to all traffic.`;if(n>10)return`Moderate improvement - ${s} shows ${n.toFixed(1)}% improvement. Consider deploying.`;if(n>0)return`Minor improvement - ${s} shows ${n.toFixed(1)}% improvement. May not be worth the complexity.`;return"No improvement detected - consider reverting to control variant"}getTest(n){return this.tests.get(n)}listTests(){return Array.from(this.tests.values())}generateALBListenerRuleCF(n){return{Type:"AWS::ElasticLoadBalancingV2::ListenerRule",Properties:{ListenerArn:{Ref:"LoadBalancerListener"},Priority:1,Conditions:[{Field:"path-pattern",Values:["/*"]}],Actions:[{Type:"forward",ForwardConfig:{TargetGroups:n.variants.map((i)=>({TargetGroupArn:i.targetGroupArn,Weight:i.weight})),TargetGroupStickinessConfig:{Enabled:n.routingStrategy.stickySession||!1,DurationSeconds:n.routingStrategy.sessionDuration?n.routingStrategy.sessionDuration*60:void 0}}}]}}}generateLambdaEdgeFunction(n){return`'use strict';
3601
3601
 
3602
3602
  exports.handler = (event, _context, _callback) => {
3603
3603
  const request = event.Records[0].cf.request;
@@ -3773,7 +3773,7 @@ Scanning image: ${s}`),console.log(`Scanner: ${i.scanner}`);let o=`scan-result-$
3773
3773
  Scan Results:`),console.log(` Total vulnerabilities: ${l.total}`),console.log(` Critical: ${l.critical}`),console.log(` High: ${l.high}`),console.log(` Medium: ${l.medium}`),console.log(` Low: ${l.low}`),console.log(` Status: ${u?"✓ PASSED":"✗ FAILED"}`),h}simulateVulnerabilities(n){let i=[];if(n.scanner==="trivy"||n.scanner==="ecr")i.push({id:"vuln-1",cve:"CVE-2024-1234",severity:"HIGH",packageName:"openssl",installedVersion:"1.1.1k",fixedVersion:"1.1.1l",title:"OpenSSL buffer overflow",description:"Buffer overflow vulnerability in OpenSSL",references:["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-1234"],cvss:7.5}),i.push({id:"vuln-2",cve:"CVE-2024-5678",severity:"MEDIUM",packageName:"curl",installedVersion:"7.68.0",fixedVersion:"7.79.0",title:"curl remote code execution",description:"Remote code execution in curl",references:["https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-5678"],cvss:5.3});return i}evaluateScanResult(n,i){if(!n.failOnSeverity)return!0;switch(n.failOnSeverity){case"CRITICAL":return i.critical===0;case"HIGH":return i.critical===0&&i.high===0;case"MEDIUM":return i.critical===0&&i.high===0&&i.medium===0;case"LOW":return i.total===0;default:return!0}}createPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,...n};return this.policies.set(i,s),s}createStrictPolicy(n){return this.createPolicy({name:n,allowedSeverities:[],maxCritical:0,maxHigh:0,blockOnFailure:!0,exemptions:[]})}createPermissivePolicy(n){return this.createPolicy({name:n,allowedSeverities:["CRITICAL","HIGH","MEDIUM","LOW"],maxCritical:5,maxHigh:10,blockOnFailure:!1,exemptions:[]})}getConfig(n){return this.configs.get(n)}listConfigs(){return Array.from(this.configs.values())}getResult(n){return this.results.get(n)}listResults(){return Array.from(this.results.values())}generateECRScanCF(n){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:n.repository,ImageScanningConfiguration:{ScanOnPush:n.scanOnPush},ImageTagMutability:"IMMUTABLE",EncryptionConfiguration:{EncryptionType:"AES256"}}}}clear(){this.configs.clear(),this.results.clear(),this.policies.clear(),this.configCounter=0,this.resultCounter=0,this.policyCounter=0}}var IE=new pm;class gm{configs=new Map;multiStageConfigs=new Map;optimizations=new Map;analyses=new Map;configCounter=0;multiStageCounter=0;optimizationCounter=0;analysisCounter=0;createBuildConfig(n){let i=`build-config-${Date.now()}-${this.configCounter++}`,s={id:i,...n};return this.configs.set(i,s),s}createOptimizedBuildConfig(n){let i={type:n.enableCache?"registry":"inline",cacheFrom:n.registry?[`${n.registry}/cache`]:void 0,cacheTo:n.registry?`${n.registry}/cache`:void 0,maxCacheAge:7};return this.createBuildConfig({name:n.name,dockerfile:n.dockerfile,context:".",cacheStrategy:i,buildArgs:{BUILDKIT_INLINE_CACHE:"1"}})}createMultiStageConfig(n){let i=`multi-stage-${Date.now()}-${this.multiStageCounter++}`,s={id:i,...n};return this.multiStageConfigs.set(i,s),s}createNodeMultiStageBuild(n){let i=n.nodeVersion||"18-alpine";return this.createMultiStageConfig({name:n.name,targetStage:n.targetStage||"production",stages:[{name:"dependencies",baseImage:`node:${i}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci --only=production"]},{name:"build",baseImage:`node:${i}`,workdir:"/app",commands:["COPY package*.json ./","RUN npm ci","COPY . .","RUN npm run build"]},{name:"production",baseImage:`node:${i}`,workdir:"/app",copyFrom:["dependencies:/app/node_modules","build:/app/dist"],commands:["COPY package*.json ./","ENV NODE_ENV=production",'CMD ["node", "dist/index.js"]']}]})}generateDockerfile(n){let i=this.multiStageConfigs.get(n);if(!i)throw Error(`Multi-stage config not found: ${n}`);let s=[];for(let o of i.stages){if(s.push(`# Stage: ${o.name}`),s.push(`FROM ${o.baseImage} AS ${o.name}`),o.workdir)s.push(`WORKDIR ${o.workdir}`);if(o.env)for(let[c,l]of Object.entries(o.env))s.push(`ENV ${c}=${l}`);for(let c of o.commands)s.push(c);s.push("")}return s.join(`
3774
3774
  `)}analyzeImage(n,i){let s=`analysis-${Date.now()}-${this.analysisCounter++}`,o=i.map((h)=>({...h,cacheable:this.isLayerCacheable(h.command)})),c=o.reduce((h,y)=>h+y.size,0),l=o.filter((h)=>!h.cacheable&&h.size>100).length,u={id:s,imageId:n,layers:o,totalSize:c,unnecessaryLayers:l};return this.analyses.set(s,u),u}isLayerCacheable(n){let i=["FROM","RUN","COPY","ADD","WORKDIR","ENV"],s=["CMD","ENTRYPOINT","LABEL"];for(let o of i)if(n.startsWith(o))return!0;for(let o of s)if(n.startsWith(o))return!1;return!1}generateOptimizations(n){let i=this.analyses.get(n);if(!i)throw Error(`Analysis not found: ${n}`);let s=`optimization-${Date.now()}-${this.optimizationCounter++}`,o=[],c=i.layers.filter((f)=>f.command.startsWith("RUN"));if(c.length>5)o.push({type:"layer_reduction",priority:"high",title:"Combine RUN commands",description:`${c.length} RUN commands found. Combine them to reduce layers.`,example:"RUN apt-get update && apt-get install -y package1 package2",impact:"Reduce image size by 20-30% and improve build time"});let l=i.layers[0];if(l.command.includes("ubuntu")||l.command.includes("debian"))o.push({type:"base_image",priority:"medium",title:"Use Alpine base image",description:"Switch to Alpine Linux for smaller image size",example:"FROM node:18-alpine",impact:"Reduce image size by 50-70%"});let u=i.layers.filter((f)=>f.command.startsWith("COPY"));if(u.length>0&&u[0].index>3)o.push({type:"cache_optimization",priority:"high",title:"Copy dependencies first",description:"Copy package files before source code to leverage layer caching",example:`COPY package*.json ./
3775
3775
  RUN npm install
3776
- COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let h={sizeBefore:i.totalSize,sizeAfter:i.totalSize*0.6,timeBefore:300,timeAfter:120},y={id:s,name:`Optimization for ${i.imageId}`,recommendations:o,estimatedSavings:h};return this.optimizations.set(s,y),y}getBuildConfig(n){return this.configs.get(n)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(n){return this.multiStageConfigs.get(n)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(n){return this.optimizations.get(n)}listOptimizations(){return Array.from(this.optimizations.values())}clear(){this.configs.clear(),this.multiStageConfigs.clear(),this.optimizations.clear(),this.analyses.clear(),this.configCounter=0,this.multiStageCounter=0,this.optimizationCounter=0,this.analysisCounter=0}}var SE=new gm;class mm{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(n){let i=`registry-${Date.now()}-${this.registryCounter++}`,s={id:i,...n};return this.registries.set(i,s),s}createECRRepository(n){return this.createRegistry({name:n.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${n.region||"us-east-1"}.amazonaws.com/${n.name}`,region:n.region||"us-east-1",encryption:{encryptionType:n.encryption||"AES256",kmsKeyId:n.kmsKeyId},scanning:{scanOnPush:n.scanOnPush??!0}})}createManagedRepository(n){let i=this.createECRRepository({name:n.name,region:n.region,scanOnPush:!0,encryption:"KMS"});return i.lifecycle={id:`lifecycle-${Date.now()}`,rules:[{rulePriority:1,description:"Keep only last N images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:n.maxImageCount||10},action:{type:"expire"}},{rulePriority:2,description:"Remove images older than N days",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:n.maxImageAgeDays||30,countUnit:"days"},action:{type:"expire"}}]},i}enableReplication(n,i){let s=this.registries.get(n);if(!s)throw Error(`Registry not found: ${n}`);return s.replication={enabled:!0,destinations:i},s}createCredentials(n){let i=`creds-${Date.now()}-${this.credentialsCounter++}`,s={id:i,...n};return this.credentials.set(i,s),s}getRegistry(n){return this.registries.get(n)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(n){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:n.name,ImageScanningConfiguration:{ScanOnPush:n.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:n.encryption?.encryptionType||"AES256",...n.encryption?.kmsKeyId&&{KmsKey:n.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...n.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:n.lifecycle.rules})}}}}}generateReplicationConfigCF(n){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:n.destinations.map((i)=>({Destinations:[{Region:i.region,...i.registryId&&{RegistryId:i.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var CE=new mm;class hm{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(n){let i=`mesh-${Date.now()}-${this.meshCounter++}`,s={id:i,...n};return this.meshes.set(i,s),s}createAppMesh(n){return this.createMesh({name:n.name,meshType:"app_mesh",services:n.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(n){let i=`vnode-${Date.now()}-${this.nodeCounter++}`,s={id:i,...n};return this.virtualNodes.set(i,s),s}createHTTPVirtualNode(n){return this.createVirtualNode({name:n.name,serviceName:n.serviceName,listeners:[{port:n.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3},timeout:{perRequest:15000,idle:300000}}],serviceDiscovery:{type:"aws_cloud_map",namespace:n.namespace,serviceName:n.serviceName}})}createVirtualRouter(n){let i=`vrouter-${Date.now()}-${this.routerCounter++}`,s={id:i,...n};return this.virtualRouters.set(i,s),s}createCanaryRoute(n){return this.createVirtualRouter({name:n.name,listeners:[{port:n.port,protocol:n.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:n.stableTarget,weight:100-n.canaryWeight},{virtualNode:n.canaryTarget,weight:n.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(n){let i=`vgateway-${Date.now()}-${this.gatewayCounter++}`,s={id:i,...n};return this.virtualGateways.set(i,s),s}createIngressGateway(n){let i={port:n.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(n.enableTLS&&n.certificateArn)i.tls={mode:"STRICT",certificate:{acm:n.certificateArn}};return this.createVirtualGateway({name:n.name,listeners:[i],logging:{accessLog:{file:{path:"/dev/stdout"}}}})}getMesh(n){return this.meshes.get(n)}listMeshes(){return Array.from(this.meshes.values())}getVirtualNode(n){return this.virtualNodes.get(n)}listVirtualNodes(){return Array.from(this.virtualNodes.values())}generateMeshCF(n){return{Type:"AWS::AppMesh::Mesh",Properties:{MeshName:n.name,Spec:{EgressFilter:{Type:"ALLOW_ALL"}}}}}generateVirtualNodeCF(n,i){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:i,VirtualNodeName:n.name,Spec:{Listeners:n.listeners.map((s)=>({PortMapping:{Port:s.port,Protocol:s.protocol},...s.healthCheck&&{HealthCheck:{Protocol:s.healthCheck.protocol,...s.healthCheck.path&&{Path:s.healthCheck.path},IntervalMillis:s.healthCheck.interval*1000,TimeoutMillis:s.healthCheck.timeout*1000,HealthyThreshold:s.healthCheck.healthyThreshold,UnhealthyThreshold:s.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:n.serviceDiscovery.namespace,ServiceName:n.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(n,i){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:i,VirtualRouterName:n.name,Spec:{Listeners:n.listeners.map((s)=>({PortMapping:{Port:s.port,Protocol:s.protocol}}))}}}}clear(){this.meshes.clear(),this.virtualNodes.clear(),this.virtualRouters.clear(),this.virtualGateways.clear(),this.meshCounter=0,this.nodeCounter=0,this.routerCounter=0,this.gatewayCounter=0}}var EE=new hm;class fm{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(n){let i=`layer-${Date.now()}-${this.layerCounter++}`,s=1,o={id:i,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:1`,version:1,...n};return this.layers.set(i,o),o}createNodeDependenciesLayer(n){return this.createLayer({layerName:n.layerName,description:"Node.js dependencies layer",compatibleRuntimes:[`nodejs${n.nodeVersion}`],content:{type:"s3",s3Bucket:n.s3Bucket,s3Key:n.s3Key},size:5242880})}createUtilitiesLayer(n){return this.createLayer({layerName:n.layerName,description:"Shared utilities and helpers",compatibleRuntimes:n.runtimes,content:{type:"s3",s3Bucket:n.s3Bucket,s3Key:n.s3Key},size:1048576})}publishVersion(n){let i=this.layers.get(n);if(!i)throw Error(`Layer not found: ${n}`);let s=`version-${Date.now()}-${this.versionCounter++}`,o=i.version+1,c={id:s,layerName:i.layerName,version:o,createdAt:new Date,compatibleRuntimes:i.compatibleRuntimes,size:i.size,codeHash:this.generateHash()};return this.versions.set(s,c),i.version=o,i.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${i.layerName}:${o}`,c}addPermission(n){let i=`permission-${Date.now()}-${this.permissionCounter++}`,s={id:i,layerName:n.layerName,version:n.version,principal:n.principal,action:"lambda:GetLayerVersion",organizationId:n.organizationId};return this.permissions.set(i,s),s}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(n){return this.layers.get(n)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(n){return Array.from(this.versions.values()).filter((i)=>i.layerName===n)}generateLayerCF(n){return{Type:"AWS::Lambda::LayerVersion",Properties:{LayerName:n.layerName,Description:n.description,Content:n.content.type==="s3"?{S3Bucket:n.content.s3Bucket,S3Key:n.content.s3Key,...n.content.s3ObjectVersion&&{S3ObjectVersion:n.content.s3ObjectVersion}}:{ZipFile:n.content.zipFile},CompatibleRuntimes:n.compatibleRuntimes,...n.licenseInfo&&{LicenseInfo:n.licenseInfo}}}}generateLayerPermissionCF(n){return{Type:"AWS::Lambda::LayerVersionPermission",Properties:{LayerVersionArn:`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:${n.version}`,Action:n.action,Principal:n.principal,...n.organizationId&&{OrganizationId:n.organizationId}}}}clear(){this.layers.clear(),this.versions.clear(),this.permissions.clear(),this.layerCounter=0,this.versionCounter=0,this.permissionCounter=0}}var bE=new fm;class Am{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(n){let i=`version-${Date.now()}-${this.versionCounter++}`,s=this.getNextVersionNumber(n.functionName),o={id:i,functionName:n.functionName,version:s.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${n.functionName}:${s}`,codeHash:this.generateHash(),description:n.description,runtime:n.runtime,memorySize:n.memorySize,timeout:n.timeout,publishedAt:new Date};return this.versions.set(i,o),o}getNextVersionNumber(n){let i=Array.from(this.versions.values()).filter((s)=>s.functionName===n).map((s)=>parseInt(s.version));return i.length>0?Math.max(...i)+1:1}createAlias(n){let i=`alias-${Date.now()}-${this.aliasCounter++}`,s={id:i,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${n.functionName}:${n.aliasName}`,revisionId:this.generateHash(),...n};return this.aliases.set(i,s),s}createProductionAlias(n){return this.createAlias({functionName:n.functionName,aliasName:"production",functionVersion:n.version,description:"Production alias"})}createStagingAlias(n){return this.createAlias({functionName:n.functionName,aliasName:"staging",functionVersion:n.version,description:"Staging alias"})}updateAlias(n,i){let s=this.aliases.get(n);if(!s)throw Error(`Alias not found: ${n}`);return s.functionVersion=i,s.revisionId=this.generateHash(),s}configureWeightedRouting(n,i){let s=this.aliases.get(n);if(!s)throw Error(`Alias not found: ${n}`);return s.routingConfig={additionalVersionWeights:i},s}createCanaryDeployment(n){let i=`deployment-${Date.now()}-${this.deploymentCounter++}`,s=Array.from(this.aliases.values()).find((c)=>c.functionName===n.functionName&&c.aliasName===n.aliasName);if(!s)s=this.createAlias({functionName:n.functionName,aliasName:n.aliasName,functionVersion:n.fromVersion});this.configureWeightedRouting(s.id,{[n.toVersion]:n.canaryWeight});let o={id:i,functionName:n.functionName,fromVersion:n.fromVersion,toVersion:n.toVersion,aliasName:n.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(i,o),o}completeDeployment(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);let s=Array.from(this.aliases.values()).find((o)=>o.functionName===i.functionName&&o.aliasName===i.aliasName);if(s)s.functionVersion=i.toVersion,s.routingConfig=void 0;return i.status="completed",i.completedAt=new Date,i}rollbackDeployment(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);let s=Array.from(this.aliases.values()).find((o)=>o.functionName===i.functionName&&o.aliasName===i.aliasName);if(s)s.functionVersion=i.fromVersion,s.routingConfig=void 0;return i.status="failed",i.completedAt=new Date,i}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(n){return this.versions.get(n)}listVersions(n){let i=Array.from(this.versions.values());return n?i.filter((s)=>s.functionName===n):i}getAlias(n){return this.aliases.get(n)}listAliases(n){let i=Array.from(this.aliases.values());return n?i.filter((s)=>s.functionName===n):i}generateVersionCF(n){return{Type:"AWS::Lambda::Version",Properties:{FunctionName:n.functionName,Description:n.description}}}generateAliasCF(n){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:n.functionName,Name:n.aliasName,FunctionVersion:n.functionVersion,Description:n.description,...n.routingConfig&&{RoutingConfig:{AdditionalVersionWeights:Object.entries(n.routingConfig.additionalVersionWeights||{}).map(([i,s])=>({FunctionVersion:i,FunctionWeight:s}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var vE=new Am;class ym{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(n){let i=`concurrency-${Date.now()}-${this.configCounter++}`,s={id:i,functionName:n.functionName,reservedConcurrency:n.reservedConcurrency};return this.configs.set(i,s),s}setProvisionedConcurrency(n){let i=`provisioned-${Date.now()}-${this.provisionedCounter++}`,s={id:i,functionName:n.functionName,qualifier:n.qualifier,provisionedConcurrentExecutions:n.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(i,s),setTimeout(()=>{s.status="ready",s.allocatedConcurrency=n.provisionedConcurrentExecutions,s.availableConcurrency=n.provisionedConcurrentExecutions},100),s}configureWarmPool(n){return this.setProvisionedConcurrency({functionName:n.functionName,qualifier:n.alias,provisionedConcurrentExecutions:n.minInstances})}createSchedule(n){let i=`schedule-${Date.now()}-${this.scheduleCounter++}`,s={id:i,...n};return this.schedules.set(i,s),s}createBusinessHoursSchedule(n){return this.createSchedule({name:`${n.functionName}-business-hours`,functionName:n.functionName,qualifier:n.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:n.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:n.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:n.offHoursConcurrency}]})}configureAutoScaling(n){let i=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,s={id:i,...n};return this.autoScalingConfigs.set(i,s),s}configurePredictiveScaling(n){return this.configureAutoScaling({functionName:n.functionName,qualifier:n.qualifier,minCapacity:n.baselineCapacity,maxCapacity:n.peakCapacity,targetUtilization:0.7,scaleInCooldown:300,scaleOutCooldown:60})}getConfig(n){return this.configs.get(n)}listConfigs(){return Array.from(this.configs.values())}getProvisionedConfig(n){return this.provisionedConfigs.get(n)}listProvisionedConfigs(){return Array.from(this.provisionedConfigs.values())}generateReservedConcurrencyCF(n){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:n.functionName,ReservedConcurrentExecutions:n.reservedConcurrency}}}generateProvisionedConcurrencyCF(n){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:n.functionName,Name:n.qualifier,ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:n.provisionedConcurrentExecutions}}}}generateAutoScalingTargetCF(n){return{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{ServiceNamespace:"lambda",ResourceId:`function:${n.functionName}:${n.qualifier}`,ScalableDimension:"lambda:function:ProvisionedConcurrentExecutions",MinCapacity:n.minCapacity,MaxCapacity:n.maxCapacity}}}generateAutoScalingPolicyCF(n){return{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${n.functionName}-autoscaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:`${n.functionName}AutoScalingTarget`},TargetTrackingScalingPolicyConfiguration:{TargetValue:n.targetUtilization*100,PredefinedMetricSpecification:{PredefinedMetricType:"LambdaProvisionedConcurrencyUtilization"},ScaleInCooldown:n.scaleInCooldown||300,ScaleOutCooldown:n.scaleOutCooldown||60}}}}clear(){this.configs.clear(),this.provisionedConfigs.clear(),this.schedules.clear(),this.autoScalingConfigs.clear(),this.configCounter=0,this.provisionedCounter=0,this.scheduleCounter=0,this.autoScalingCounter=0}}var TE=new ym;class Im{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(n){let i=`destination-${Date.now()}-${this.destinationCounter++}`,s={id:i,...n};return this.destinations.set(i,s),s}configureSQSDestination(n){let i={type:"sqs",arn:n.queueArn};return this.configureDestinations({functionName:n.functionName,successDestination:n.onSuccess?i:void 0,failureDestination:n.onFailure?i:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(n){let i={type:"sns",arn:n.topicArn};return this.configureDestinations({functionName:n.functionName,successDestination:n.onSuccess?i:void 0,failureDestination:n.onFailure?i:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(n){let i={type:"eventbridge",arn:n.eventBusArn};return this.configureDestinations({functionName:n.functionName,successDestination:n.onSuccess?i:void 0,failureDestination:n.onFailure?i:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(n){let i={type:"lambda",arn:n.destinationFunctionArn};return this.configureDestinations({functionName:n.functionName,successDestination:n.onSuccess?i:void 0,failureDestination:n.onFailure?i:void 0,maxEventAge:21600,maxRetries:2})}configureDLQWithNotification(n){return this.configureDestinations({functionName:n.functionName,failureDestination:{type:"sqs",arn:n.dlqArn},maxEventAge:3600,maxRetries:0})}createEventBridgeIntegration(n){let i=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,s={id:i,functionName:n.functionName,eventBusArn:n.eventBusArn,detailType:n.detailType||"Lambda Function Invocation Result",source:n.source||`lambda.${n.functionName}`};return this.eventBridgeDestinations.set(i,s),s}sendToDestination(n){let i=Array.from(this.destinations.values()).find((l)=>l.functionName===n.functionName);if(!i)return null;let s=n.status==="success"?i.successDestination:i.failureDestination;if(!s)return null;let o=`record-${Date.now()}-${this.recordCounter++}`,c={id:o,timestamp:new Date,functionName:n.functionName,requestId:n.requestId,status:n.status,destinationType:s.type,destinationArn:s.arn,payload:n.payload,error:n.error};return this.records.set(o,c),c}getDestination(n){return this.destinations.get(n)}listDestinations(n){let i=Array.from(this.destinations.values());return n?i.filter((s)=>s.functionName===n):i}getDestinationRecords(n){let i=Array.from(this.records.values());return n?i.filter((s)=>s.functionName===n):i}generateEventInvokeConfigCF(n){return{Type:"AWS::Lambda::EventInvokeConfig",Properties:{FunctionName:n.functionName,Qualifier:n.qualifier||"$LATEST",MaximumEventAgeInSeconds:n.maxEventAge||21600,MaximumRetryAttempts:n.maxRetries??2,...n.successDestination&&{DestinationConfig:{OnSuccess:{Destination:n.successDestination.arn}}},...n.failureDestination&&{DestinationConfig:{OnFailure:{Destination:n.failureDestination.arn}}}}}}generateEventBridgeRuleCF(n){return{Type:"AWS::Events::Rule",Properties:{EventBusName:n.eventBusArn.split("/").pop(),EventPattern:{source:[n.source],"detail-type":[n.detailType]},State:"ENABLED",Targets:[{Arn:`arn:aws:lambda:us-east-1:123456789012:function:${n.functionName}`,Id:n.id}]}}}clear(){this.destinations.clear(),this.records.clear(),this.eventBridgeDestinations.clear(),this.destinationCounter=0,this.recordCounter=0,this.eventBridgeCounter=0}}var wE=new Im;class Sm{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(n){let i=`vpc-config-${Date.now()}-${this.configCounter++}`,s={id:i,...n};this.vpcConfigs.set(i,s);for(let o of n.subnetIds)this.createNetworkInterface({functionName:n.functionName,subnetId:o});return s}configurePrivateVPC(n){return this.configureVPC({functionName:n.functionName,vpcId:n.vpcId,subnetIds:n.privateSubnetIds,securityGroupIds:[n.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(n){if(n.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:n.functionName,vpcId:n.vpcId,subnetIds:n.subnetIds,securityGroupIds:n.securityGroupIds})}createVPCEndpoint(n){let i=`endpoint-${Date.now()}-${this.endpointCounter++}`,s={id:i,...n};return this.endpoints.set(i,s),s}createS3Endpoint(n){return this.createVPCEndpoint({vpcId:n.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(n){return this.createVPCEndpoint({vpcId:n.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(n){return this.createVPCEndpoint({vpcId:n.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:n.subnetIds,securityGroupIds:n.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(n){let i=`eni-${Date.now()}-${this.eniCounter++}`,s={id:i,functionName:n.functionName,networkInterfaceId:`eni-${Math.random().toString(36).substring(2,15)}`,subnetId:n.subnetId,privateIpAddress:`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`,status:"creating",attachedAt:new Date};return this.networkInterfaces.set(i,s),setTimeout(()=>{s.status="available"},100),s}analyzeConnectivity(n){let i=`connectivity-${Date.now()}-${this.connectivityCounter++}`,s=Array.from(this.vpcConfigs.values()).find((y)=>y.functionName===n.functionName),o=Array.from(this.endpoints.values()).filter((y)=>y.vpcId===s?.vpcId).map((y)=>y.serviceName),c=[],l=n.hasNATGateway??!1,u=n.hasInternetGateway??!1;if(!l&&!u)c.push("Add NAT Gateway for internet access");if(!o.includes("com.amazonaws.us-east-1.s3"))c.push("Add S3 VPC endpoint to reduce NAT costs");if(!o.includes("com.amazonaws.us-east-1.dynamodb"))c.push("Add DynamoDB VPC endpoint for private access");let h={id:i,functionName:n.functionName,hasInternetAccess:l||u,hasNATGateway:l,hasVPCEndpoints:o.length>0,endpoints:o,recommendations:c};return this.connectivity.set(i,h),h}getVPCConfig(n){return this.vpcConfigs.get(n)}listVPCConfigs(n){let i=Array.from(this.vpcConfigs.values());return n?i.filter((s)=>s.functionName===n):i}getNetworkInterfaces(n){return Array.from(this.networkInterfaces.values()).filter((i)=>i.functionName===n)}listVPCEndpoints(n){let i=Array.from(this.endpoints.values());return n?i.filter((s)=>s.vpcId===n):i}generateVPCConfigCF(n){return{VpcConfig:{SubnetIds:n.subnetIds,SecurityGroupIds:n.securityGroupIds,...n.ipv6Allowed&&{Ipv6AllowedForDualStack:!0}}}}generateVPCEndpointCF(n){return{Type:"AWS::EC2::VPCEndpoint",Properties:{VpcId:n.vpcId,ServiceName:n.serviceName,VpcEndpointType:n.endpointType,...n.subnetIds&&{SubnetIds:n.subnetIds},...n.securityGroupIds&&{SecurityGroupIds:n.securityGroupIds},...n.privateDnsEnabled!==void 0&&{PrivateDnsEnabled:n.privateDnsEnabled}}}}generateSecurityGroupCF(n){return{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:n.groupName,GroupDescription:`Security group for Lambda ${n.groupName}`,VpcId:n.vpcId,...n.ingressRules&&{SecurityGroupIngress:n.ingressRules.map((i)=>({IpProtocol:i.protocol,FromPort:i.fromPort,ToPort:i.toPort,...i.cidrIp&&{CidrIp:i.cidrIp},...i.sourceSecurityGroupId&&{SourceSecurityGroupId:i.sourceSecurityGroupId}}))},...n.egressRules&&{SecurityGroupEgress:n.egressRules.map((i)=>({IpProtocol:i.protocol,FromPort:i.fromPort,ToPort:i.toPort,CidrIp:i.cidrIp||"0.0.0.0/0"}))}}}}clear(){this.vpcConfigs.clear(),this.endpoints.clear(),this.networkInterfaces.clear(),this.connectivity.clear(),this.configCounter=0,this.endpointCounter=0,this.eniCounter=0,this.connectivityCounter=0}}var RE=new Sm;class Cm{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(n){let i=`dlq-${Date.now()}-${this.configCounter++}`,s={id:i,...n};return this.dlqConfigs.set(i,s),s}configureSQSDLQ(n){return this.configureDLQ({functionName:n.functionName,targetArn:n.queueArn,targetType:"sqs",maxReceiveCount:n.maxReceiveCount||3,retentionPeriod:n.retentionPeriod||1209600})}configureSNSDLQ(n){return this.configureDLQ({functionName:n.functionName,targetArn:n.topicArn,targetType:"sns"})}configureDLQWithAlarm(n){let i=this.configureSQSDLQ({functionName:n.functionName,queueArn:n.queueArn});return this.createDLQAlarm({dlqConfigId:i.id,alarmName:`${n.functionName}-dlq-alarm`,threshold:n.alarmThreshold,evaluationPeriods:1,notificationTopicArn:n.notificationTopicArn,enabled:!0}),i}sendToDLQ(n){let i=`message-${Date.now()}-${this.messageCounter++}`,s={id:i,timestamp:new Date,...n};return this.messages.set(i,s),s}createDLQAlarm(n){let i=`alarm-${Date.now()}-${this.alarmCounter++}`,s={id:i,...n};return this.alarms.set(i,s),s}createAgeAlarm(n){let i=this.dlqConfigs.get(n.dlqConfigId);if(!i)throw Error(`DLQ config not found: ${n.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:n.dlqConfigId,alarmName:`${i.functionName}-dlq-age-alarm`,threshold:n.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:n.notificationTopicArn,enabled:!0})}async reprocessMessage(n){let i=this.messages.get(n);if(!i)throw Error(`Message not found: ${n}`);let s=Array.from(this.dlqConfigs.values()).find((l)=>l.functionName===i.functionName);if(!s)throw Error(`DLQ config not found for function: ${i.functionName}`);let o=`reprocess-${Date.now()}-${this.reprocessCounter++}`,c={id:o,dlqConfigId:s.id,messageId:n,status:"pending",startedAt:new Date};return this.reprocessing.set(o,c),setTimeout(()=>{c.status="processing",setTimeout(()=>{let l=Math.random()>0.3;if(c.status=l?"success":"failed",c.completedAt=new Date,!l)c.error="Reprocessing failed - same error occurred";else this.messages.delete(n)},100)},50),c}async batchReprocess(n){let i=this.dlqConfigs.get(n.dlqConfigId);if(!i)throw Error(`DLQ config not found: ${n.dlqConfigId}`);let s=Array.from(this.messages.values()).filter((o)=>o.functionName===i.functionName).slice(0,n.maxMessages||10).map((o)=>this.reprocessMessage(o.id));return Promise.all(s)}getDLQStats(n){let i=this.dlqConfigs.get(n);if(!i)throw Error(`DLQ config not found: ${n}`);let s=Array.from(this.messages.values()).filter((u)=>u.functionName===i.functionName),o={},c=0;for(let u of s)o[u.errorType]=(o[u.errorType]||0)+1,c+=u.attemptCount;let l=s.map((u)=>u.timestamp);return{totalMessages:s.length,oldestMessage:l.length>0?new Date(Math.min(...l.map((u)=>u.getTime()))):void 0,newestMessage:l.length>0?new Date(Math.max(...l.map((u)=>u.getTime()))):void 0,averageAttempts:s.length>0?c/s.length:0,errorTypes:o}}getDLQConfig(n){return this.dlqConfigs.get(n)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(n){let i=this.dlqConfigs.get(n);if(!i)return[];return Array.from(this.messages.values()).filter((s)=>s.functionName===i.functionName)}generateDLQCF(n){return{DeadLetterConfig:{TargetArn:n.targetArn}}}generateSQSDLQCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:`${n.functionName}-dlq`,MessageRetentionPeriod:n.retentionPeriod||1209600,...n.maxReceiveCount&&{RedrivePolicy:{deadLetterTargetArn:n.targetArn,maxReceiveCount:n.maxReceiveCount}}}}}generateDLQAlarmCF(n){let i=this.dlqConfigs.get(n.dlqConfigId);if(!i)throw Error(`DLQ config not found: ${n.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:n.alarmName,AlarmDescription:`DLQ alarm for ${i.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:n.evaluationPeriods,Threshold:n.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:i.targetArn.split(":").pop()}],...n.notificationTopicArn&&{AlarmActions:[n.notificationTopicArn]}}}}clear(){this.dlqConfigs.clear(),this.messages.clear(),this.alarms.clear(),this.reprocessing.clear(),this.configCounter=0,this.messageCounter=0,this.alarmCounter=0,this.reprocessCounter=0}}var DE=new Cm;class Em{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"weighted",...n};return this.policies.set(i,s),s}createLatencyPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"latency",...n};return this.policies.set(i,s),s}createFailoverPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"failover",...n};return this.policies.set(i,s),s}createGeolocationPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"geolocation",...n};return this.policies.set(i,s),s}createGeoproximityPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"geoproximity",...n};return this.policies.set(i,s),s}createHTTPHealthCheck(n){let i=`health-check-${Date.now()}-${this.healthCheckCounter++}`,s={id:i,type:n.port===443?"https":"http",requestInterval:n.requestInterval||30,failureThreshold:n.failureThreshold||3,healthCheckStatus:"Unknown",port:n.port||(n.port===443?443:80),...n};return this.healthChecks.set(i,s),setTimeout(()=>{s.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),s}createTCPHealthCheck(n){let i=`health-check-${Date.now()}-${this.healthCheckCounter++}`,s={id:i,type:"tcp",fullyQualifiedDomainName:n.ipAddress,requestInterval:n.requestInterval||30,failureThreshold:n.failureThreshold||3,healthCheckStatus:"Unknown",...n};return this.healthChecks.set(i,s),setTimeout(()=>{s.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),s}createCalculatedHealthCheck(n){let i=`health-check-${Date.now()}-${this.healthCheckCounter++}`,s={id:i,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...n};return this.healthChecks.set(i,s),setTimeout(()=>{let o=n.childHealthChecks.filter((c)=>this.healthChecks.get(c)?.healthCheckStatus==="Healthy").length;s.healthCheckStatus=o>=n.healthThreshold?"Healthy":"Unhealthy"},150),s}createTrafficPolicy(n){let i=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,s={id:i,version:1,...n};return this.trafficPolicies.set(i,s),s}createFailoverTrafficPolicy(n){return this.createTrafficPolicy({name:n.name,document:{recordType:n.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:n.primaryEndpoint},secondary:{type:"value",value:n.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(n){let i={},s=[];return n.locations.forEach((o,c)=>{let l=`endpoint${c}`;i[l]={type:"value",value:o.endpoint},s.push({endpointReference:l,region:o.region,latitude:o.latitude,longitude:o.longitude,bias:o.bias})}),this.createTrafficPolicy({name:n.name,document:{recordType:"A",startRule:"geoproximity",endpoints:i,rules:{geoproximity:{ruleType:"geoproximity",locations:s}}}})}getPolicy(n){return this.policies.get(n)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(n){return this.healthChecks.get(n)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(n){return this.healthChecks.get(n)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(n){let i={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:n.type.toUpperCase(),RequestInterval:n.requestInterval,FailureThreshold:n.failureThreshold,...n.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:n.name}]}};if(n.type==="calculated"){let s=n;i.Properties.HealthCheckConfig.ChildHealthChecks=s.childHealthChecks,i.Properties.HealthCheckConfig.HealthThreshold=s.healthThreshold}else{if(n.ipAddress)i.Properties.HealthCheckConfig.IPAddress=n.ipAddress;if(n.fullyQualifiedDomainName)i.Properties.HealthCheckConfig.FullyQualifiedDomainName=n.fullyQualifiedDomainName;if(n.port)i.Properties.HealthCheckConfig.Port=n.port;if(n.resourcePath)i.Properties.HealthCheckConfig.ResourcePath=n.resourcePath;if(n.enableSNI)i.Properties.HealthCheckConfig.EnableSNI=!0}return i}generateWeightedRecordSetCF(n){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.name,Type:n.type,TTL:n.ttl,ResourceRecords:n.resourceRecords,Weight:n.weight,SetIdentifier:n.setIdentifier,...n.healthCheckId&&{HealthCheckId:n.healthCheckId}}}}generateFailoverRecordSetCF(n){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.name,Type:n.type,TTL:n.ttl,ResourceRecords:n.resourceRecords,Failover:n.failover,SetIdentifier:n.setIdentifier,...n.healthCheckId&&{HealthCheckId:n.healthCheckId}}}}clear(){this.policies.clear(),this.healthChecks.clear(),this.trafficPolicies.clear(),this.policyCounter=0,this.healthCheckCounter=0,this.trafficPolicyCounter=0}}var PE=new Em;class bm{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(n){let i=`dnssec-${Date.now()}-${this.configCounter++}`,s={id:i,hostedZoneId:n.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(i,s),n.kmsKeyArn)this.createKSK({name:`ksk-${n.hostedZoneId}`,hostedZoneId:n.hostedZoneId,kmsKeyArn:n.kmsKeyArn});return setTimeout(()=>{s.status="SIGNED",s.signingStatus="DNSSEC signing complete"},100),s}disableDNSSEC(n){let i=this.configs.get(n);if(!i)throw Error(`DNSSEC config not found: ${n}`);return i.status="DELETING",i.signingStatus="Removing DNSSEC signing",setTimeout(()=>{i.status="NOT_SIGNING",i.signingStatus="DNSSEC signing removed"},100),i}createKSK(n){let i=`ksk-${Date.now()}-${this.kskCounter++}`,s={id:i,status:"ACTIVE",flag:257,keyManagementServiceArn:n.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...n};s.dnskeyRecord=`${s.flag} 3 8 ${s.publicKey}`;let o=this.generateDigest(s.dnskeyRecord);return s.digestValue=o,s.dsRecord=`${s.keyTag} 8 ${s.digestAlgorithm} ${o}`,this.ksks.set(i,s),s}deactivateKSK(n){let i=this.ksks.get(n);if(!i)throw Error(`KSK not found: ${n}`);return i.status="INACTIVE",i}validateDNSSEC(n){let i=`validation-${Date.now()}-${this.validationCounter++}`,s=n.checkDNSKEY!==!1?Math.random()>0.1:!1,o=n.checkRRSIG!==!1?Math.random()>0.1:!1,c=s&&o,l=[];if(!s)l.push("DNSKEY record not found");if(!o)l.push("RRSIG record not found");let u;if(!s&&!o)u="INSECURE";else if(s&&o&&c)u="VALID";else if(s||o)u="BOGUS",l.push("Invalid signature or incomplete DNSSEC chain");else u="INVALID";let h={id:i,domain:n.domain,validationStatus:u,dnskeyPresent:s,rrsigPresent:o,validSignature:c,errors:l};return this.validations.set(i,h),h}getDNSSECConfig(n){return this.configs.get(n)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(n){return this.ksks.get(n)}listKSKs(n){let i=Array.from(this.ksks.values());return n?i.filter((s)=>s.hostedZoneId===n):i}getDSRecord(n){let i=this.ksks.get(n);if(!i||!i.dsRecord)throw Error("DS record not available");return i.dsRecord}generatePublicKey(){let n="";for(let i=0;i<256;i++)n+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return n}generateDigest(n){let i="";for(let s=0;s<64;s++)i+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return i}generateDNSSECCF(n){return{Type:"AWS::Route53::DNSSEC",Properties:{HostedZoneId:n.hostedZoneId}}}generateKSKCF(n){return{Type:"AWS::Route53::KeySigningKey",Properties:{Name:n.name,HostedZoneId:n.hostedZoneId,KeyManagementServiceArn:n.keyManagementServiceArn,Status:n.status}}}clear(){this.configs.clear(),this.ksks.clear(),this.validations.clear(),this.configCounter=0,this.kskCounter=0,this.validationCounter=0}}var NE=new bm;class vm{endpoints=new Map;rules=new Map;firewalls=new Map;ruleGroups=new Map;domainLists=new Map;endpointCounter=0;ruleCounter=0;firewallCounter=0;ruleGroupCounter=0;domainListCounter=0;createResolverEndpoint(n){let i=`endpoint-${Date.now()}-${this.endpointCounter++}`,s={id:i,status:"CREATING",...n};return this.endpoints.set(i,s),setTimeout(()=>{s.status="OPERATIONAL",s.ipAddresses.forEach((o)=>{if(!o.ip)o.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),s}createInboundEndpoint(n){return this.createResolverEndpoint({name:n.name,direction:"INBOUND",ipAddresses:n.subnetIds.map((i)=>({subnetId:i})),securityGroupIds:n.securityGroupIds})}createOutboundEndpoint(n){return this.createResolverEndpoint({name:n.name,direction:"OUTBOUND",ipAddresses:n.subnetIds.map((i)=>({subnetId:i})),securityGroupIds:n.securityGroupIds})}createResolverRule(n){let i=`rule-${Date.now()}-${this.ruleCounter++}`,s={id:i,status:"CREATING",...n};return this.rules.set(i,s),setTimeout(()=>{s.status="COMPLETE"},100),s}createForwardRule(n){return this.createResolverRule({name:n.name,ruleType:"FORWARD",domainName:n.domainName,targetIps:n.targetIps,resolverEndpointId:n.resolverEndpointId})}createSystemRule(n){return this.createResolverRule({name:n.name,ruleType:"SYSTEM",domainName:n.domainName})}createFirewallDomainList(n){let i=`domain-list-${Date.now()}-${this.domainListCounter++}`,s={id:i,status:"CREATING",...n};return this.domainLists.set(i,s),setTimeout(()=>{s.status="COMPLETE"},100),s}createFirewallRuleGroup(n){let i=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,s={id:i,name:n.name,rules:n.rules.map((o,c)=>({id:`rule-${i}-${c}`,...o})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(i,s),s}createBlockRule(n){return this.createFirewallRuleGroup({name:n.name,rules:[{name:n.name,priority:n.priority,action:"BLOCK",blockResponse:n.blockResponse||"NODATA",blockOverrideDomain:n.blockOverrideDomain,firewallDomainListId:n.domainListId}]})}createAllowRule(n){return this.createFirewallRuleGroup({name:n.name,rules:[{name:n.name,priority:n.priority,action:"ALLOW",firewallDomainListId:n.domainListId}]})}createDNSFirewall(n){let i=`firewall-${Date.now()}-${this.firewallCounter++}`,s={id:i,name:n.name,firewallRuleGroupAssociations:n.ruleGroupAssociations.map((o,c)=>({id:`assoc-${i}-${c}`,vpcId:n.vpcId,firewallRuleGroupId:o.firewallRuleGroupId,priority:o.priority,mutationProtection:o.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(i,s),s}createMalwareProtectionFirewall(n){let i=this.createFirewallDomainList({name:`${n.name}-malware-domains`,domains:n.maliciousDomains}),s=this.createBlockRule({name:`${n.name}-block-malware`,priority:100,domainListId:i.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:n.name,vpcId:n.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:s.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(n){return this.endpoints.get(n)}listEndpoints(n){let i=Array.from(this.endpoints.values());return n?i.filter((s)=>s.direction===n):i}getRule(n){return this.rules.get(n)}listRules(){return Array.from(this.rules.values())}getFirewall(n){return this.firewalls.get(n)}listFirewalls(){return Array.from(this.firewalls.values())}generateResolverEndpointCF(n){return{Type:"AWS::Route53Resolver::ResolverEndpoint",Properties:{Name:n.name,Direction:n.direction,IpAddresses:n.ipAddresses.map((i)=>({SubnetId:i.subnetId,...i.ip&&{Ip:i.ip}})),SecurityGroupIds:n.securityGroupIds}}}generateResolverRuleCF(n){return{Type:"AWS::Route53Resolver::ResolverRule",Properties:{Name:n.name,RuleType:n.ruleType,DomainName:n.domainName,...n.targetIps&&{TargetIps:n.targetIps.map((i)=>({Ip:i.ip,Port:i.port||53}))},...n.resolverEndpointId&&{ResolverEndpointId:n.resolverEndpointId}}}}generateFirewallRuleGroupCF(n){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:n.name,FirewallRules:n.rules.map((i)=>({Name:i.name,Priority:i.priority,Action:i.action,FirewallDomainListId:i.firewallDomainListId,...i.blockResponse&&{BlockResponse:i.blockResponse},...i.blockOverrideDomain&&{BlockOverrideDomain:i.blockOverrideDomain},...i.blockOverrideTTL&&{BlockOverrideTtl:i.blockOverrideTTL}}))}}}clear(){this.endpoints.clear(),this.rules.clear(),this.firewalls.clear(),this.ruleGroups.clear(),this.domainLists.clear(),this.endpointCounter=0,this.ruleCounter=0,this.firewallCounter=0,this.ruleGroupCounter=0,this.domainListCounter=0}}var kE=new vm;class Tm{bounces=new Map;complaints=new Map;handlers=new Map;suppressionList=new Map;metrics=new Map;bounceCounter=0;complaintCounter=0;handlerCounter=0;suppressionCounter=0;metricsCounter=0;recordBounce(n){let i=`bounce-${Date.now()}-${this.bounceCounter++}`,s={id:i,...n};if(this.bounces.set(i,s),n.bounceType==="Permanent")this.addToSuppressionList({emailAddress:n.recipient,reason:"BOUNCE"});return s}recordComplaint(n){let i=`complaint-${Date.now()}-${this.complaintCounter++}`,s={id:i,...n};this.complaints.set(i,s);for(let o of n.recipients)this.addToSuppressionList({emailAddress:o,reason:"COMPLAINT"});return s}createBounceHandler(n){let i=`handler-${Date.now()}-${this.handlerCounter++}`,s={id:i,...n};return this.handlers.set(i,s),s}createAutomaticBounceHandler(n){return this.createBounceHandler({name:n.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:n.notificationTopicArn})}addToSuppressionList(n){let i=`suppression-${Date.now()}-${this.suppressionCounter++}`,s=n.expirationDays?new Date(Date.now()+n.expirationDays*24*60*60*1000):void 0,o={id:i,emailAddress:n.emailAddress,reason:n.reason,suppressedAt:new Date,expiresAt:s,bounceCount:n.reason==="BOUNCE"?1:0,complaintCount:n.reason==="COMPLAINT"?1:0};return this.suppressionList.set(n.emailAddress,o),o}removeFromSuppressionList(n){return this.suppressionList.delete(n)}isSuppressed(n){let i=this.suppressionList.get(n);if(!i)return!1;if(i.expiresAt&&i.expiresAt<new Date)return this.suppressionList.delete(n),!1;return!0}getBounceStatistics(n,i){let s=Array.from(this.bounces.values()).filter((b)=>b.timestamp>=n&&b.timestamp<=i),o=s.length,c=s.filter((b)=>b.bounceType==="Permanent").length,l=s.filter((b)=>b.bounceType==="Transient").length,u=o*10,h=o/u*100,y=new Map;for(let b of s)y.set(b.recipient,(y.get(b.recipient)||0)+1);let f=Array.from(y.entries()).map(([b,C])=>({email:b,count:C})).sort((b,C)=>C.count-b.count).slice(0,10);return{totalBounces:o,permanentBounces:c,transientBounces:l,bounceRate:h,topRecipients:f}}getComplaintStatistics(n,i){let s=Array.from(this.complaints.values()).filter((y)=>y.timestamp>=n&&y.timestamp<=i),o=s.length,c=new Set;for(let y of s)for(let f of y.recipients)c.add(f);let l=c.size,u=o*1000,h=o/u*100;return{totalComplaints:o,uniqueComplainters:l,complaintRate:h}}calculateReputationMetrics(){let n=`metrics-${Date.now()}-${this.metricsCounter++}`,i=new Date,s=new Date(i.getTime()-86400000),o=this.getBounceStatistics(s,i),c=this.getComplaintStatistics(s,i),l;if(o.bounceRate>10||c.complaintRate>0.5)l="Shutdown";else if(o.bounceRate>5||c.complaintRate>0.1)l="Probation";else if(o.bounceRate>2||c.complaintRate>0.05)l="Warning";else l="Good";let u={id:n,timestamp:i,bounceRate:o.bounceRate,complaintRate:c.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:o.totalBounces*10,reputationStatus:l};return this.metrics.set(n,u),u}getBounces(n){let i=Array.from(this.bounces.values());return n?i.filter((s)=>s.messageId===n):i}getComplaints(n){let i=Array.from(this.complaints.values());return n?i.filter((s)=>s.messageId===n):i}listSuppressionList(n){let i=Array.from(this.suppressionList.values());return n?i.filter((s)=>s.reason===n):i}generateSNSSubscriptionCF(n){return{Type:"AWS::SNS::Subscription",Properties:{TopicArn:n.topicArn,Endpoint:n.endpoint,Protocol:n.protocol}}}generateEventDestinationCF(n){return{Type:"AWS::SES::ConfigurationSetEventDestination",Properties:{ConfigurationSetName:n.configurationSetName,EventDestination:{Name:n.eventDestinationName,Enabled:!0,MatchingEventTypes:n.eventTypes,...n.snsTopicArn&&{SnsDestination:{TopicARN:n.snsTopicArn}},...n.cloudWatchDestination&&{CloudWatchDestination:n.cloudWatchDestination}}}}}clear(){this.bounces.clear(),this.complaints.clear(),this.handlers.clear(),this.suppressionList.clear(),this.metrics.clear(),this.bounceCounter=0,this.complaintCounter=0,this.handlerCounter=0,this.suppressionCounter=0,this.metricsCounter=0}}var BE=new Tm;class wm{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(n){let i=`event-${Date.now()}-${this.eventCounter++}`,s={id:i,...n};if(this.events.set(i,s),n.tags?.campaignId)this.updateCampaignStats(n.tags.campaignId,n.eventType);return s}trackOpen(n){return this.trackEvent({...n,eventType:"open",timestamp:new Date})}trackClick(n){return this.trackEvent({...n,eventType:"click",timestamp:new Date})}createCampaign(n){let i=`campaign-${Date.now()}-${this.campaignCounter++}`,s={id:i,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...n};return this.campaigns.set(i,s),s}updateCampaignStats(n,i){let s=this.campaigns.get(n);if(!s)return;switch(i){case"send":s.sentCount++;break;case"delivery":s.deliveredCount++;break;case"open":s.openCount++;break;case"click":s.clickCount++;break;case"bounce":s.bounceCount++;break;case"complaint":s.complaintCount++;break}}generateReport(n){let i=`report-${Date.now()}-${this.reportCounter++}`,s=Array.from(this.events.values()).filter((R)=>{let _=R.timestamp>=n.startDate&&R.timestamp<=n.endDate,B=!n.campaignId||R.tags?.campaignId===n.campaignId;return _&&B}),o=s.filter((R)=>R.eventType==="send").length,c=s.filter((R)=>R.eventType==="delivery").length,l=s.filter((R)=>R.eventType==="open").length,u=s.filter((R)=>R.eventType==="click").length,h=s.filter((R)=>R.eventType==="bounce").length,y=s.filter((R)=>R.eventType==="complaint").length,f=o>0?c/o*100:0,b=c>0?l/c*100:0,C=c>0?u/c*100:0,T=l>0?u/l*100:0,w=o>0?h/o*100:0,E=c>0?y/c*100:0,I=new Map;for(let R of s)if(R.eventType==="click"){let _=R;I.set(_.link,(I.get(_.link)||0)+1)}let N=Array.from(I.entries()).map(([R,_])=>({link:R,clicks:_})).sort((R,_)=>_.clicks-R.clicks).slice(0,10),D={desktop:0,mobile:0,tablet:0,unknown:0};for(let R of s)if(R.eventType==="open"||R.eventType==="click"){let _=R.userAgent.toLowerCase();if(_.includes("mobile"))D.mobile++;else if(_.includes("tablet"))D.tablet++;else if(_.includes("mozilla"))D.desktop++;else D.unknown++}let x={id:i,campaignId:n.campaignId,startDate:n.startDate,endDate:n.endDate,totalSent:o,totalDelivered:c,totalOpened:l,totalClicked:u,totalBounced:h,totalComplaints:y,deliveryRate:f,openRate:b,clickRate:C,clickToOpenRate:T,bounceRate:w,complaintRate:E,topLinks:N,deviceBreakdown:D,locationBreakdown:{}};return this.reports.set(i,x),x}createABTest(n){let i=`abtest-${Date.now()}-${this.abTestCounter++}`,s={id:i,name:n.name,variants:n.variants.map((o,c)=>({id:`variant-${i}-${c}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...o})),status:"draft"};return this.abTests.set(i,s),s}startABTest(n){let i=this.abTests.get(n);if(!i)throw Error(`A/B test not found: ${n}`);return i.status="running",i.startedAt=new Date,i}completeABTest(n){let i=this.abTests.get(n);if(!i)throw Error(`A/B test not found: ${n}`);let s=i.variants[0],o=0;for(let c of i.variants){let l=c.sentCount>0?c.openCount/c.sentCount:0;if(l>o)o=l,s=c}return i.status="completed",i.completedAt=new Date,i.winner=s.id,i}getCampaign(n){return this.campaigns.get(n)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(n){let i=Array.from(this.events.values());if(n?.messageId)i=i.filter((s)=>s.messageId===n.messageId);if(n?.eventType)i=i.filter((s)=>s.eventType===n.eventType);if(n?.startDate)i=i.filter((s)=>s.timestamp>=n.startDate);if(n?.endDate)i=i.filter((s)=>s.timestamp<=n.endDate);return i}generateTrackingConfigurationCF(n){return{Type:"AWS::SES::ConfigurationSet",Properties:{Name:n.configurationSetName,...n.openTracking&&{TrackingOptions:{CustomRedirectDomain:"tracking.example.com"}}}}}clear(){this.events.clear(),this.campaigns.clear(),this.reports.clear(),this.abTests.clear(),this.eventCounter=0,this.campaignCounter=0,this.reportCounter=0,this.abTestCounter=0}}var _E=new wm;class Rm{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let n=`dashboard-${Date.now()}-${this.dashboardCounter++}`,i=Math.random()*5,s=Math.random()*0.5,o=Math.floor(Math.random()*10),c=Math.max(0,100-i*10-s*100-o*2),l=[];if(i>2)l.push("Reduce bounce rate by cleaning email list");if(s>0.1)l.push("Review email content and unsubscribe process");if(o>5)l.push("Improve email relevance and targeting");let u={id:n,timestamp:new Date,overallScore:c,bounceRate:i,complaintRate:s,spamReports:o,blacklistStatus:this.checkBlacklists(),dkimStatus:"VERIFIED",spfStatus:"PASS",dmarcStatus:"PASS",sendingLimits:{maxSendRate:14,max24HourSend:50000,sentLast24Hours:12000,remainingQuota:38000,quotaResetTime:new Date(Date.now()+86400000)},recommendations:l};return this.dashboards.set(n,u),u}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((n)=>({listName:n,listed:Math.random()>0.95,delistUrl:`https://www.${n.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(n){let i=`warmup-${Date.now()}-${this.warmupCounter++}`,s=[],o=(n.targetDailyLimit-n.initialDailyLimit)/n.durationDays;for(let l=0;l<n.durationDays;l++)s.push(Math.floor(n.initialDailyLimit+o*l));let c={id:i,name:n.name,startDate:new Date,currentDay:1,totalDays:n.durationDays,dailyLimits:s,currentLimit:s[0],status:"active"};return this.warmupPlans.set(i,c),c}createAggressiveWarmupPlan(n){return this.createWarmupPlan({name:n.name,initialDailyLimit:500,targetDailyLimit:50000,durationDays:14})}createConservativeWarmupPlan(n){return this.createWarmupPlan({name:n.name,initialDailyLimit:200,targetDailyLimit:50000,durationDays:30})}advanceWarmupPlan(n){let i=this.warmupPlans.get(n);if(!i)throw Error(`Warmup plan not found: ${n}`);if(i.currentDay<i.totalDays)i.currentDay++,i.currentLimit=i.dailyLimits[i.currentDay-1];if(i.currentDay>=i.totalDays)i.status="completed";return i}trackDomainReputation(n){let i=`domain-${Date.now()}-${this.domainCounter++}`,s=n.delivered/n.totalSent*100,o=n.delivered>0?n.opened/n.delivered*100:0,c=n.delivered>0?n.clicked/n.delivered*100:0,l=n.bounced/n.totalSent*100,u=n.delivered>0?n.complained/n.delivered*100:0,h=o*0.4+c*0.6,y=Math.max(0,100-l*10-u*100+h*0.2),f={id:i,domain:n.domain,reputationScore:y,totalSent:n.totalSent,deliveryRate:s,openRate:o,clickRate:c,bounceRate:l,complaintRate:u,engagementScore:h};return this.domainReputations.set(n.domain,f),f}getDomainReputation(n){return this.domainReputations.get(n)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(n){return this.warmupPlans.get(n)}listWarmupPlans(){return Array.from(this.warmupPlans.values())}clear(){this.dashboards.clear(),this.warmupPlans.clear(),this.domainReputations.clear(),this.dashboardCounter=0,this.warmupCounter=0,this.domainCounter=0}}var xE=new Rm;class Dm{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(n){let i=`template-${Date.now()}-${this.templateCounter++}`,s=this.extractVariables(n.subject+n.htmlPart+n.textPart),o={id:i,variables:s,createdAt:new Date,updatedAt:new Date,version:1,...n};return this.templates.set(i,o),this.addVersion({templateId:i,version:1,subject:n.subject,htmlPart:n.htmlPart,textPart:n.textPart,createdBy:"system"}),o}createWelcomeTemplate(n){return this.createTemplate({name:n.name,subject:"Welcome to {{companyName}}!",htmlPart:`
3776
+ COPY . .`,impact:"Improve build time by 60-80% on subsequent builds"});let h={sizeBefore:i.totalSize,sizeAfter:i.totalSize*0.6,timeBefore:300,timeAfter:120},y={id:s,name:`Optimization for ${i.imageId}`,recommendations:o,estimatedSavings:h};return this.optimizations.set(s,y),y}getBuildConfig(n){return this.configs.get(n)}listBuildConfigs(){return Array.from(this.configs.values())}getMultiStageConfig(n){return this.multiStageConfigs.get(n)}listMultiStageConfigs(){return Array.from(this.multiStageConfigs.values())}getOptimization(n){return this.optimizations.get(n)}listOptimizations(){return Array.from(this.optimizations.values())}clear(){this.configs.clear(),this.multiStageConfigs.clear(),this.optimizations.clear(),this.analyses.clear(),this.configCounter=0,this.multiStageCounter=0,this.optimizationCounter=0,this.analysisCounter=0}}var SE=new gm;class mm{registries=new Map;credentials=new Map;registryCounter=0;credentialsCounter=0;createRegistry(n){let i=`registry-${Date.now()}-${this.registryCounter++}`,s={id:i,...n};return this.registries.set(i,s),s}createECRRepository(n){return this.createRegistry({name:n.name,registryType:"ecr",repositoryUri:`123456789012.dkr.ecr.${n.region||"us-east-1"}.amazonaws.com/${n.name}`,region:n.region||"us-east-1",encryption:{encryptionType:n.encryption||"AES256",kmsKeyId:n.kmsKeyId},scanning:{scanOnPush:n.scanOnPush??!0}})}createManagedRepository(n){let i=this.createECRRepository({name:n.name,region:n.region,scanOnPush:!0,encryption:"KMS"});return i.lifecycle={id:`lifecycle-${Date.now()}`,rules:[{rulePriority:1,description:"Keep only last N images",selection:{tagStatus:"any",countType:"imageCountMoreThan",countNumber:n.maxImageCount||10},action:{type:"expire"}},{rulePriority:2,description:"Remove images older than N days",selection:{tagStatus:"untagged",countType:"sinceImagePushed",countNumber:n.maxImageAgeDays||30,countUnit:"days"},action:{type:"expire"}}]},i}enableReplication(n,i){let s=this.registries.get(n);if(!s)throw Error(`Registry not found: ${n}`);return s.replication={enabled:!0,destinations:i},s}createCredentials(n){let i=`creds-${Date.now()}-${this.credentialsCounter++}`,s={id:i,...n};return this.credentials.set(i,s),s}getRegistry(n){return this.registries.get(n)}listRegistries(){return Array.from(this.registries.values())}generateECRRepositoryCF(n){return{Type:"AWS::ECR::Repository",Properties:{RepositoryName:n.name,ImageScanningConfiguration:{ScanOnPush:n.scanning?.scanOnPush??!1},EncryptionConfiguration:{EncryptionType:n.encryption?.encryptionType||"AES256",...n.encryption?.kmsKeyId&&{KmsKey:n.encryption.kmsKeyId}},ImageTagMutability:"MUTABLE",...n.lifecycle&&{LifecyclePolicy:{LifecyclePolicyText:JSON.stringify({rules:n.lifecycle.rules})}}}}}generateReplicationConfigCF(n){return{Type:"AWS::ECR::ReplicationConfiguration",Properties:{ReplicationConfiguration:{Rules:n.destinations.map((i)=>({Destinations:[{Region:i.region,...i.registryId&&{RegistryId:i.registryId}}]}))}}}}clear(){this.registries.clear(),this.credentials.clear(),this.registryCounter=0,this.credentialsCounter=0}}var CE=new mm;class hm{meshes=new Map;virtualNodes=new Map;virtualRouters=new Map;virtualGateways=new Map;meshCounter=0;nodeCounter=0;routerCounter=0;gatewayCounter=0;createMesh(n){let i=`mesh-${Date.now()}-${this.meshCounter++}`,s={id:i,...n};return this.meshes.set(i,s),s}createAppMesh(n){return this.createMesh({name:n.name,meshType:"app_mesh",services:n.services,virtualNodes:[],virtualRouters:[],virtualGateways:[]})}createVirtualNode(n){let i=`vnode-${Date.now()}-${this.nodeCounter++}`,s={id:i,...n};return this.virtualNodes.set(i,s),s}createHTTPVirtualNode(n){return this.createVirtualNode({name:n.name,serviceName:n.serviceName,listeners:[{port:n.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3},timeout:{perRequest:15000,idle:300000}}],serviceDiscovery:{type:"aws_cloud_map",namespace:n.namespace,serviceName:n.serviceName}})}createVirtualRouter(n){let i=`vrouter-${Date.now()}-${this.routerCounter++}`,s={id:i,...n};return this.virtualRouters.set(i,s),s}createCanaryRoute(n){return this.createVirtualRouter({name:n.name,listeners:[{port:n.port,protocol:n.protocol}],routes:[{name:"canary-route",match:{prefix:"/"},action:{weightedTargets:[{virtualNode:n.stableTarget,weight:100-n.canaryWeight},{virtualNode:n.canaryTarget,weight:n.canaryWeight}]},retryPolicy:{maxRetries:3,perRetryTimeout:5000,httpRetryEvents:["server-error","gateway-error"],tcpRetryEvents:["connection-error"]}}]})}createVirtualGateway(n){let i=`vgateway-${Date.now()}-${this.gatewayCounter++}`,s={id:i,...n};return this.virtualGateways.set(i,s),s}createIngressGateway(n){let i={port:n.port,protocol:"http",healthCheck:{protocol:"http",path:"/health",interval:30,timeout:10,healthyThreshold:2,unhealthyThreshold:3}};if(n.enableTLS&&n.certificateArn)i.tls={mode:"STRICT",certificate:{acm:n.certificateArn}};return this.createVirtualGateway({name:n.name,listeners:[i],logging:{accessLog:{file:{path:"/dev/stdout"}}}})}getMesh(n){return this.meshes.get(n)}listMeshes(){return Array.from(this.meshes.values())}getVirtualNode(n){return this.virtualNodes.get(n)}listVirtualNodes(){return Array.from(this.virtualNodes.values())}generateMeshCF(n){return{Type:"AWS::AppMesh::Mesh",Properties:{MeshName:n.name,Spec:{EgressFilter:{Type:"ALLOW_ALL"}}}}}generateVirtualNodeCF(n,i){return{Type:"AWS::AppMesh::VirtualNode",Properties:{MeshName:i,VirtualNodeName:n.name,Spec:{Listeners:n.listeners.map((s)=>({PortMapping:{Port:s.port,Protocol:s.protocol},...s.healthCheck&&{HealthCheck:{Protocol:s.healthCheck.protocol,...s.healthCheck.path&&{Path:s.healthCheck.path},IntervalMillis:s.healthCheck.interval*1000,TimeoutMillis:s.healthCheck.timeout*1000,HealthyThreshold:s.healthCheck.healthyThreshold,UnhealthyThreshold:s.healthCheck.unhealthyThreshold}}})),ServiceDiscovery:{AWSCloudMap:{NamespaceName:n.serviceDiscovery.namespace,ServiceName:n.serviceDiscovery.serviceName}}}}}}generateVirtualRouterCF(n,i){return{Type:"AWS::AppMesh::VirtualRouter",Properties:{MeshName:i,VirtualRouterName:n.name,Spec:{Listeners:n.listeners.map((s)=>({PortMapping:{Port:s.port,Protocol:s.protocol}}))}}}}clear(){this.meshes.clear(),this.virtualNodes.clear(),this.virtualRouters.clear(),this.virtualGateways.clear(),this.meshCounter=0,this.nodeCounter=0,this.routerCounter=0,this.gatewayCounter=0}}var EE=new hm;class fm{layers=new Map;versions=new Map;permissions=new Map;layerCounter=0;versionCounter=0;permissionCounter=0;createLayer(n){let i=`layer-${Date.now()}-${this.layerCounter++}`,s=1,o={id:i,layerArn:`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:1`,version:1,...n};return this.layers.set(i,o),o}createNodeDependenciesLayer(n){return this.createLayer({layerName:n.layerName,description:"Node.js dependencies layer",compatibleRuntimes:[`nodejs${n.nodeVersion}`],content:{type:"s3",s3Bucket:n.s3Bucket,s3Key:n.s3Key},size:5242880})}createUtilitiesLayer(n){return this.createLayer({layerName:n.layerName,description:"Shared utilities and helpers",compatibleRuntimes:n.runtimes,content:{type:"s3",s3Bucket:n.s3Bucket,s3Key:n.s3Key},size:1048576})}publishVersion(n){let i=this.layers.get(n);if(!i)throw Error(`Layer not found: ${n}`);let s=`version-${Date.now()}-${this.versionCounter++}`,o=i.version+1,c={id:s,layerName:i.layerName,version:o,createdAt:new Date,compatibleRuntimes:i.compatibleRuntimes,size:i.size,codeHash:this.generateHash()};return this.versions.set(s,c),i.version=o,i.layerArn=`arn:aws:lambda:us-east-1:123456789012:layer:${i.layerName}:${o}`,c}addPermission(n){let i=`permission-${Date.now()}-${this.permissionCounter++}`,s={id:i,layerName:n.layerName,version:n.version,principal:n.principal,action:"lambda:GetLayerVersion",organizationId:n.organizationId};return this.permissions.set(i,s),s}generateHash(){return Math.random().toString(36).substring(2,15)}getLayer(n){return this.layers.get(n)}listLayers(){return Array.from(this.layers.values())}getLayerVersions(n){return Array.from(this.versions.values()).filter((i)=>i.layerName===n)}generateLayerCF(n){return{Type:"AWS::Lambda::LayerVersion",Properties:{LayerName:n.layerName,Description:n.description,Content:n.content.type==="s3"?{S3Bucket:n.content.s3Bucket,S3Key:n.content.s3Key,...n.content.s3ObjectVersion&&{S3ObjectVersion:n.content.s3ObjectVersion}}:{ZipFile:n.content.zipFile},CompatibleRuntimes:n.compatibleRuntimes,...n.licenseInfo&&{LicenseInfo:n.licenseInfo}}}}generateLayerPermissionCF(n){return{Type:"AWS::Lambda::LayerVersionPermission",Properties:{LayerVersionArn:`arn:aws:lambda:us-east-1:123456789012:layer:${n.layerName}:${n.version}`,Action:n.action,Principal:n.principal,...n.organizationId&&{OrganizationId:n.organizationId}}}}clear(){this.layers.clear(),this.versions.clear(),this.permissions.clear(),this.layerCounter=0,this.versionCounter=0,this.permissionCounter=0}}var bE=new fm;class Am{versions=new Map;aliases=new Map;deployments=new Map;versionCounter=0;aliasCounter=0;deploymentCounter=0;publishVersion(n){let i=`version-${Date.now()}-${this.versionCounter++}`,s=this.getNextVersionNumber(n.functionName),o={id:i,functionName:n.functionName,version:s.toString(),functionArn:`arn:aws:lambda:us-east-1:123456789012:function:${n.functionName}:${s}`,codeHash:this.generateHash(),description:n.description,runtime:n.runtime,memorySize:n.memorySize,timeout:n.timeout,publishedAt:new Date};return this.versions.set(i,o),o}getNextVersionNumber(n){let i=Array.from(this.versions.values()).filter((s)=>s.functionName===n).map((s)=>parseInt(s.version));return i.length>0?Math.max(...i)+1:1}createAlias(n){let i=`alias-${Date.now()}-${this.aliasCounter++}`,s={id:i,aliasArn:`arn:aws:lambda:us-east-1:123456789012:function:${n.functionName}:${n.aliasName}`,revisionId:this.generateHash(),...n};return this.aliases.set(i,s),s}createProductionAlias(n){return this.createAlias({functionName:n.functionName,aliasName:"production",functionVersion:n.version,description:"Production alias"})}createStagingAlias(n){return this.createAlias({functionName:n.functionName,aliasName:"staging",functionVersion:n.version,description:"Staging alias"})}updateAlias(n,i){let s=this.aliases.get(n);if(!s)throw Error(`Alias not found: ${n}`);return s.functionVersion=i,s.revisionId=this.generateHash(),s}configureWeightedRouting(n,i){let s=this.aliases.get(n);if(!s)throw Error(`Alias not found: ${n}`);return s.routingConfig={additionalVersionWeights:i},s}createCanaryDeployment(n){let i=`deployment-${Date.now()}-${this.deploymentCounter++}`,s=Array.from(this.aliases.values()).find((c)=>c.functionName===n.functionName&&c.aliasName===n.aliasName);if(!s)s=this.createAlias({functionName:n.functionName,aliasName:n.aliasName,functionVersion:n.fromVersion});this.configureWeightedRouting(s.id,{[n.toVersion]:n.canaryWeight});let o={id:i,functionName:n.functionName,fromVersion:n.fromVersion,toVersion:n.toVersion,aliasName:n.aliasName,strategy:"canary",status:"in_progress",startedAt:new Date};return this.deployments.set(i,o),o}completeDeployment(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);let s=Array.from(this.aliases.values()).find((o)=>o.functionName===i.functionName&&o.aliasName===i.aliasName);if(s)s.functionVersion=i.toVersion,s.routingConfig=void 0;return i.status="completed",i.completedAt=new Date,i}rollbackDeployment(n){let i=this.deployments.get(n);if(!i)throw Error(`Deployment not found: ${n}`);let s=Array.from(this.aliases.values()).find((o)=>o.functionName===i.functionName&&o.aliasName===i.aliasName);if(s)s.functionVersion=i.fromVersion,s.routingConfig=void 0;return i.status="failed",i.completedAt=new Date,i}generateHash(){return Math.random().toString(36).substring(2,15)}getVersion(n){return this.versions.get(n)}listVersions(n){let i=Array.from(this.versions.values());return n?i.filter((s)=>s.functionName===n):i}getAlias(n){return this.aliases.get(n)}listAliases(n){let i=Array.from(this.aliases.values());return n?i.filter((s)=>s.functionName===n):i}generateVersionCF(n){return{Type:"AWS::Lambda::Version",Properties:{FunctionName:n.functionName,Description:n.description}}}generateAliasCF(n){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:n.functionName,Name:n.aliasName,FunctionVersion:n.functionVersion,Description:n.description,...n.routingConfig&&{RoutingConfig:{AdditionalVersionWeights:Object.entries(n.routingConfig.additionalVersionWeights||{}).map(([i,s])=>({FunctionVersion:i,FunctionWeight:s}))}}}}}clear(){this.versions.clear(),this.aliases.clear(),this.deployments.clear(),this.versionCounter=0,this.aliasCounter=0,this.deploymentCounter=0}}var vE=new Am;class ym{configs=new Map;provisionedConfigs=new Map;schedules=new Map;autoScalingConfigs=new Map;configCounter=0;provisionedCounter=0;scheduleCounter=0;autoScalingCounter=0;setReservedConcurrency(n){let i=`concurrency-${Date.now()}-${this.configCounter++}`,s={id:i,functionName:n.functionName,reservedConcurrency:n.reservedConcurrency};return this.configs.set(i,s),s}setProvisionedConcurrency(n){let i=`provisioned-${Date.now()}-${this.provisionedCounter++}`,s={id:i,functionName:n.functionName,qualifier:n.qualifier,provisionedConcurrentExecutions:n.provisionedConcurrentExecutions,status:"pending",lastModified:new Date};return this.provisionedConfigs.set(i,s),setTimeout(()=>{s.status="ready",s.allocatedConcurrency=n.provisionedConcurrentExecutions,s.availableConcurrency=n.provisionedConcurrentExecutions},100),s}configureWarmPool(n){return this.setProvisionedConcurrency({functionName:n.functionName,qualifier:n.alias,provisionedConcurrentExecutions:n.minInstances})}createSchedule(n){let i=`schedule-${Date.now()}-${this.scheduleCounter++}`,s={id:i,...n};return this.schedules.set(i,s),s}createBusinessHoursSchedule(n){return this.createSchedule({name:`${n.functionName}-business-hours`,functionName:n.functionName,qualifier:n.qualifier,schedule:[{name:"business-hours",cronExpression:"0 8 * * MON-FRI",targetConcurrency:n.businessHoursConcurrency},{name:"off-hours",cronExpression:"0 18 * * MON-FRI",targetConcurrency:n.offHoursConcurrency},{name:"weekend",cronExpression:"0 0 * * SAT",targetConcurrency:n.offHoursConcurrency}]})}configureAutoScaling(n){let i=`autoscaling-${Date.now()}-${this.autoScalingCounter++}`,s={id:i,...n};return this.autoScalingConfigs.set(i,s),s}configurePredictiveScaling(n){return this.configureAutoScaling({functionName:n.functionName,qualifier:n.qualifier,minCapacity:n.baselineCapacity,maxCapacity:n.peakCapacity,targetUtilization:0.7,scaleInCooldown:300,scaleOutCooldown:60})}getConfig(n){return this.configs.get(n)}listConfigs(){return Array.from(this.configs.values())}getProvisionedConfig(n){return this.provisionedConfigs.get(n)}listProvisionedConfigs(){return Array.from(this.provisionedConfigs.values())}generateReservedConcurrencyCF(n){return{Type:"AWS::Lambda::Function",Properties:{FunctionName:n.functionName,ReservedConcurrentExecutions:n.reservedConcurrency}}}generateProvisionedConcurrencyCF(n){return{Type:"AWS::Lambda::Alias",Properties:{FunctionName:n.functionName,Name:n.qualifier,ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:n.provisionedConcurrentExecutions}}}}generateAutoScalingTargetCF(n){return{Type:"AWS::ApplicationAutoScaling::ScalableTarget",Properties:{ServiceNamespace:"lambda",ResourceId:`function:${n.functionName}:${n.qualifier}`,ScalableDimension:"lambda:function:ProvisionedConcurrentExecutions",MinCapacity:n.minCapacity,MaxCapacity:n.maxCapacity}}}generateAutoScalingPolicyCF(n){return{Type:"AWS::ApplicationAutoScaling::ScalingPolicy",Properties:{PolicyName:`${n.functionName}-autoscaling`,PolicyType:"TargetTrackingScaling",ScalingTargetId:{Ref:`${n.functionName}AutoScalingTarget`},TargetTrackingScalingPolicyConfiguration:{TargetValue:n.targetUtilization*100,PredefinedMetricSpecification:{PredefinedMetricType:"LambdaProvisionedConcurrencyUtilization"},ScaleInCooldown:n.scaleInCooldown||300,ScaleOutCooldown:n.scaleOutCooldown||60}}}}clear(){this.configs.clear(),this.provisionedConfigs.clear(),this.schedules.clear(),this.autoScalingConfigs.clear(),this.configCounter=0,this.provisionedCounter=0,this.scheduleCounter=0,this.autoScalingCounter=0}}var TE=new ym;class Im{destinations=new Map;records=new Map;eventBridgeDestinations=new Map;destinationCounter=0;recordCounter=0;eventBridgeCounter=0;configureDestinations(n){let i=`destination-${Date.now()}-${this.destinationCounter++}`,s={id:i,...n};return this.destinations.set(i,s),s}configureSQSDestination(n){let i={type:"sqs",arn:n.queueArn};return this.configureDestinations({functionName:n.functionName,successDestination:n.onSuccess?i:void 0,failureDestination:n.onFailure?i:void 0,maxEventAge:21600,maxRetries:2})}configureSNSDestination(n){let i={type:"sns",arn:n.topicArn};return this.configureDestinations({functionName:n.functionName,successDestination:n.onSuccess?i:void 0,failureDestination:n.onFailure?i:void 0,maxEventAge:21600,maxRetries:2})}configureEventBridgeDestination(n){let i={type:"eventbridge",arn:n.eventBusArn};return this.configureDestinations({functionName:n.functionName,successDestination:n.onSuccess?i:void 0,failureDestination:n.onFailure?i:void 0,maxEventAge:21600,maxRetries:2})}configureLambdaDestination(n){let i={type:"lambda",arn:n.destinationFunctionArn};return this.configureDestinations({functionName:n.functionName,successDestination:n.onSuccess?i:void 0,failureDestination:n.onFailure?i:void 0,maxEventAge:21600,maxRetries:2})}configureDLQWithNotification(n){return this.configureDestinations({functionName:n.functionName,failureDestination:{type:"sqs",arn:n.dlqArn},maxEventAge:3600,maxRetries:0})}createEventBridgeIntegration(n){let i=`eventbridge-${Date.now()}-${this.eventBridgeCounter++}`,s={id:i,functionName:n.functionName,eventBusArn:n.eventBusArn,detailType:n.detailType||"Lambda Function Invocation Result",source:n.source||`lambda.${n.functionName}`};return this.eventBridgeDestinations.set(i,s),s}sendToDestination(n){let i=Array.from(this.destinations.values()).find((l)=>l.functionName===n.functionName);if(!i)return null;let s=n.status==="success"?i.successDestination:i.failureDestination;if(!s)return null;let o=`record-${Date.now()}-${this.recordCounter++}`,c={id:o,timestamp:new Date,functionName:n.functionName,requestId:n.requestId,status:n.status,destinationType:s.type,destinationArn:s.arn,payload:n.payload,error:n.error};return this.records.set(o,c),c}getDestination(n){return this.destinations.get(n)}listDestinations(n){let i=Array.from(this.destinations.values());return n?i.filter((s)=>s.functionName===n):i}getDestinationRecords(n){let i=Array.from(this.records.values());return n?i.filter((s)=>s.functionName===n):i}generateEventInvokeConfigCF(n){return{Type:"AWS::Lambda::EventInvokeConfig",Properties:{FunctionName:n.functionName,Qualifier:n.qualifier||"$LATEST",MaximumEventAgeInSeconds:n.maxEventAge||21600,MaximumRetryAttempts:n.maxRetries??2,...n.successDestination&&{DestinationConfig:{OnSuccess:{Destination:n.successDestination.arn}}},...n.failureDestination&&{DestinationConfig:{OnFailure:{Destination:n.failureDestination.arn}}}}}}generateEventBridgeRuleCF(n){return{Type:"AWS::Events::Rule",Properties:{EventBusName:n.eventBusArn.split("/").pop(),EventPattern:{source:[n.source],"detail-type":[n.detailType]},State:"ENABLED",Targets:[{Arn:`arn:aws:lambda:us-east-1:123456789012:function:${n.functionName}`,Id:n.id}]}}}clear(){this.destinations.clear(),this.records.clear(),this.eventBridgeDestinations.clear(),this.destinationCounter=0,this.recordCounter=0,this.eventBridgeCounter=0}}var wE=new Im;class Sm{vpcConfigs=new Map;endpoints=new Map;networkInterfaces=new Map;connectivity=new Map;configCounter=0;endpointCounter=0;eniCounter=0;connectivityCounter=0;configureVPC(n){let i=`vpc-config-${Date.now()}-${this.configCounter++}`,s={id:i,...n};this.vpcConfigs.set(i,s);for(let o of n.subnetIds)this.createNetworkInterface({functionName:n.functionName,subnetId:o});return s}configurePrivateVPC(n){return this.configureVPC({functionName:n.functionName,vpcId:n.vpcId,subnetIds:n.privateSubnetIds,securityGroupIds:[n.securityGroupId],ipv6Allowed:!1})}configureMultiAZVPC(n){if(n.subnetIds.length<2)throw Error("Multi-AZ configuration requires at least 2 subnets");return this.configureVPC({functionName:n.functionName,vpcId:n.vpcId,subnetIds:n.subnetIds,securityGroupIds:n.securityGroupIds})}createVPCEndpoint(n){let i=`endpoint-${Date.now()}-${this.endpointCounter++}`,s={id:i,...n};return this.endpoints.set(i,s),s}createS3Endpoint(n){return this.createVPCEndpoint({vpcId:n.vpcId,serviceName:"com.amazonaws.us-east-1.s3",endpointType:"Gateway",privateDnsEnabled:!1})}createDynamoDBEndpoint(n){return this.createVPCEndpoint({vpcId:n.vpcId,serviceName:"com.amazonaws.us-east-1.dynamodb",endpointType:"Gateway",privateDnsEnabled:!1})}createSecretsManagerEndpoint(n){return this.createVPCEndpoint({vpcId:n.vpcId,serviceName:"com.amazonaws.us-east-1.secretsmanager",endpointType:"Interface",subnetIds:n.subnetIds,securityGroupIds:n.securityGroupIds,privateDnsEnabled:!0})}createNetworkInterface(n){let i=`eni-${Date.now()}-${this.eniCounter++}`,s={id:i,functionName:n.functionName,networkInterfaceId:`eni-${Math.random().toString(36).substring(2,15)}`,subnetId:n.subnetId,privateIpAddress:`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`,status:"creating",attachedAt:new Date};return this.networkInterfaces.set(i,s),setTimeout(()=>{s.status="available"},100),s}analyzeConnectivity(n){let i=`connectivity-${Date.now()}-${this.connectivityCounter++}`,s=Array.from(this.vpcConfigs.values()).find((y)=>y.functionName===n.functionName),o=Array.from(this.endpoints.values()).filter((y)=>y.vpcId===s?.vpcId).map((y)=>y.serviceName),c=[],l=n.hasNATGateway??!1,u=n.hasInternetGateway??!1;if(!l&&!u)c.push("Add NAT Gateway for internet access");if(!o.includes("com.amazonaws.us-east-1.s3"))c.push("Add S3 VPC endpoint to reduce NAT costs");if(!o.includes("com.amazonaws.us-east-1.dynamodb"))c.push("Add DynamoDB VPC endpoint for private access");let h={id:i,functionName:n.functionName,hasInternetAccess:l||u,hasNATGateway:l,hasVPCEndpoints:o.length>0,endpoints:o,recommendations:c};return this.connectivity.set(i,h),h}getVPCConfig(n){return this.vpcConfigs.get(n)}listVPCConfigs(n){let i=Array.from(this.vpcConfigs.values());return n?i.filter((s)=>s.functionName===n):i}getNetworkInterfaces(n){return Array.from(this.networkInterfaces.values()).filter((i)=>i.functionName===n)}listVPCEndpoints(n){let i=Array.from(this.endpoints.values());return n?i.filter((s)=>s.vpcId===n):i}generateVPCConfigCF(n){return{VpcConfig:{SubnetIds:n.subnetIds,SecurityGroupIds:n.securityGroupIds,...n.ipv6Allowed&&{Ipv6AllowedForDualStack:!0}}}}generateVPCEndpointCF(n){return{Type:"AWS::EC2::VPCEndpoint",Properties:{VpcId:n.vpcId,ServiceName:n.serviceName,VpcEndpointType:n.endpointType,...n.subnetIds&&{SubnetIds:n.subnetIds},...n.securityGroupIds&&{SecurityGroupIds:n.securityGroupIds},...n.privateDnsEnabled!==void 0&&{PrivateDnsEnabled:n.privateDnsEnabled}}}}generateSecurityGroupCF(n){return{Type:"AWS::EC2::SecurityGroup",Properties:{GroupName:n.groupName,GroupDescription:`Security group for Lambda ${n.groupName}`,VpcId:n.vpcId,...n.ingressRules&&{SecurityGroupIngress:n.ingressRules.map((i)=>({IpProtocol:i.protocol,FromPort:i.fromPort,ToPort:i.toPort,...i.cidrIp&&{CidrIp:i.cidrIp},...i.sourceSecurityGroupId&&{SourceSecurityGroupId:i.sourceSecurityGroupId}}))},...n.egressRules&&{SecurityGroupEgress:n.egressRules.map((i)=>({IpProtocol:i.protocol,FromPort:i.fromPort,ToPort:i.toPort,CidrIp:i.cidrIp||"0.0.0.0/0"}))}}}}clear(){this.vpcConfigs.clear(),this.endpoints.clear(),this.networkInterfaces.clear(),this.connectivity.clear(),this.configCounter=0,this.endpointCounter=0,this.eniCounter=0,this.connectivityCounter=0}}var RE=new Sm;class Cm{dlqConfigs=new Map;messages=new Map;alarms=new Map;reprocessing=new Map;configCounter=0;messageCounter=0;alarmCounter=0;reprocessCounter=0;configureDLQ(n){let i=`dlq-${Date.now()}-${this.configCounter++}`,s={id:i,...n};return this.dlqConfigs.set(i,s),s}configureSQSDLQ(n){return this.configureDLQ({functionName:n.functionName,targetArn:n.queueArn,targetType:"sqs",maxReceiveCount:n.maxReceiveCount||3,retentionPeriod:n.retentionPeriod||1209600})}configureSNSDLQ(n){return this.configureDLQ({functionName:n.functionName,targetArn:n.topicArn,targetType:"sns"})}configureDLQWithAlarm(n){let i=this.configureSQSDLQ({functionName:n.functionName,queueArn:n.queueArn});return this.createDLQAlarm({dlqConfigId:i.id,alarmName:`${n.functionName}-dlq-alarm`,threshold:n.alarmThreshold,evaluationPeriods:1,notificationTopicArn:n.notificationTopicArn,enabled:!0}),i}sendToDLQ(n){let i=`message-${Date.now()}-${this.messageCounter++}`,s={id:i,timestamp:new Date,...n};return this.messages.set(i,s),s}createDLQAlarm(n){let i=`alarm-${Date.now()}-${this.alarmCounter++}`,s={id:i,...n};return this.alarms.set(i,s),s}createAgeAlarm(n){let i=this.dlqConfigs.get(n.dlqConfigId);if(!i)throw Error(`DLQ config not found: ${n.dlqConfigId}`);return this.createDLQAlarm({dlqConfigId:n.dlqConfigId,alarmName:`${i.functionName}-dlq-age-alarm`,threshold:n.maxAgeSeconds,evaluationPeriods:1,notificationTopicArn:n.notificationTopicArn,enabled:!0})}async reprocessMessage(n){let i=this.messages.get(n);if(!i)throw Error(`Message not found: ${n}`);let s=Array.from(this.dlqConfigs.values()).find((l)=>l.functionName===i.functionName);if(!s)throw Error(`DLQ config not found for function: ${i.functionName}`);let o=`reprocess-${Date.now()}-${this.reprocessCounter++}`,c={id:o,dlqConfigId:s.id,messageId:n,status:"pending",startedAt:new Date};return this.reprocessing.set(o,c),setTimeout(()=>{c.status="processing",setTimeout(()=>{let l=Math.random()>0.3;if(c.status=l?"success":"failed",c.completedAt=new Date,!l)c.error="Reprocessing failed - same error occurred";else this.messages.delete(n)},100)},50),c}async batchReprocess(n){let i=this.dlqConfigs.get(n.dlqConfigId);if(!i)throw Error(`DLQ config not found: ${n.dlqConfigId}`);let s=Array.from(this.messages.values()).filter((o)=>o.functionName===i.functionName).slice(0,n.maxMessages||10).map((o)=>this.reprocessMessage(o.id));return Promise.all(s)}getDLQStats(n){let i=this.dlqConfigs.get(n);if(!i)throw Error(`DLQ config not found: ${n}`);let s=Array.from(this.messages.values()).filter((u)=>u.functionName===i.functionName),o={},c=0;for(let u of s)o[u.errorType]=(o[u.errorType]||0)+1,c+=u.attemptCount;let l=s.map((u)=>u.timestamp);return{totalMessages:s.length,oldestMessage:l.length>0?new Date(Math.min(...l.map((u)=>u.getTime()))):void 0,newestMessage:l.length>0?new Date(Math.max(...l.map((u)=>u.getTime()))):void 0,averageAttempts:s.length>0?c/s.length:0,errorTypes:o}}getDLQConfig(n){return this.dlqConfigs.get(n)}listDLQConfigs(){return Array.from(this.dlqConfigs.values())}getDLQMessages(n){let i=this.dlqConfigs.get(n);if(!i)return[];return Array.from(this.messages.values()).filter((s)=>s.functionName===i.functionName)}generateDLQCF(n){return{DeadLetterConfig:{TargetArn:n.targetArn}}}generateSQSDLQCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:`${n.functionName}-dlq`,MessageRetentionPeriod:n.retentionPeriod||1209600,...n.maxReceiveCount&&{RedrivePolicy:{deadLetterTargetArn:n.targetArn,maxReceiveCount:n.maxReceiveCount}}}}}generateDLQAlarmCF(n){let i=this.dlqConfigs.get(n.dlqConfigId);if(!i)throw Error(`DLQ config not found: ${n.dlqConfigId}`);return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:n.alarmName,AlarmDescription:`DLQ alarm for ${i.functionName}`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Sum",Period:300,EvaluationPeriods:n.evaluationPeriods,Threshold:n.threshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:i.targetArn.split(":").pop()}],...n.notificationTopicArn&&{AlarmActions:[n.notificationTopicArn]}}}}clear(){this.dlqConfigs.clear(),this.messages.clear(),this.alarms.clear(),this.reprocessing.clear(),this.configCounter=0,this.messageCounter=0,this.alarmCounter=0,this.reprocessCounter=0}}var DE=new Cm;class Em{policies=new Map;healthChecks=new Map;trafficPolicies=new Map;policyCounter=0;healthCheckCounter=0;trafficPolicyCounter=0;createWeightedPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"weighted",...n};return this.policies.set(i,s),s}createLatencyPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"latency",...n};return this.policies.set(i,s),s}createFailoverPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"failover",...n};return this.policies.set(i,s),s}createGeolocationPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"geolocation",...n};return this.policies.set(i,s),s}createGeoproximityPolicy(n){let i=`policy-${Date.now()}-${this.policyCounter++}`,s={id:i,type:"geoproximity",...n};return this.policies.set(i,s),s}createHTTPHealthCheck(n){let i=`health-check-${Date.now()}-${this.healthCheckCounter++}`,s={id:i,type:n.port===443?"https":"http",requestInterval:n.requestInterval||30,failureThreshold:n.failureThreshold||3,healthCheckStatus:"Unknown",port:n.port||(n.port===443?443:80),...n};return this.healthChecks.set(i,s),setTimeout(()=>{s.healthCheckStatus=Math.random()>0.2?"Healthy":"Unhealthy"},100),s}createTCPHealthCheck(n){let i=`health-check-${Date.now()}-${this.healthCheckCounter++}`,s={id:i,type:"tcp",fullyQualifiedDomainName:n.ipAddress,requestInterval:n.requestInterval||30,failureThreshold:n.failureThreshold||3,healthCheckStatus:"Unknown",...n};return this.healthChecks.set(i,s),setTimeout(()=>{s.healthCheckStatus=Math.random()>0.1?"Healthy":"Unhealthy"},100),s}createCalculatedHealthCheck(n){let i=`health-check-${Date.now()}-${this.healthCheckCounter++}`,s={id:i,type:"calculated",requestInterval:30,failureThreshold:0,healthCheckStatus:"Unknown",...n};return this.healthChecks.set(i,s),setTimeout(()=>{let o=n.childHealthChecks.filter((c)=>this.healthChecks.get(c)?.healthCheckStatus==="Healthy").length;s.healthCheckStatus=o>=n.healthThreshold?"Healthy":"Unhealthy"},150),s}createTrafficPolicy(n){let i=`traffic-policy-${Date.now()}-${this.trafficPolicyCounter++}`,s={id:i,version:1,...n};return this.trafficPolicies.set(i,s),s}createFailoverTrafficPolicy(n){return this.createTrafficPolicy({name:n.name,document:{recordType:n.recordType||"A",startRule:"failover",endpoints:{primary:{type:"value",value:n.primaryEndpoint},secondary:{type:"value",value:n.secondaryEndpoint}},rules:{failover:{ruleType:"failover",primary:"primary",secondary:"secondary"}}}})}createGeoproximityTrafficPolicy(n){let i={},s=[];return n.locations.forEach((o,c)=>{let l=`endpoint${c}`;i[l]={type:"value",value:o.endpoint},s.push({endpointReference:l,region:o.region,latitude:o.latitude,longitude:o.longitude,bias:o.bias})}),this.createTrafficPolicy({name:n.name,document:{recordType:"A",startRule:"geoproximity",endpoints:i,rules:{geoproximity:{ruleType:"geoproximity",locations:s}}}})}getPolicy(n){return this.policies.get(n)}listPolicies(){return Array.from(this.policies.values())}getHealthCheck(n){return this.healthChecks.get(n)}listHealthChecks(){return Array.from(this.healthChecks.values())}getHealthCheckStatus(n){return this.healthChecks.get(n)?.healthCheckStatus||"Unknown"}generateHealthCheckCF(n){let i={Type:"AWS::Route53::HealthCheck",Properties:{HealthCheckConfig:{Type:n.type.toUpperCase(),RequestInterval:n.requestInterval,FailureThreshold:n.failureThreshold,...n.measureLatency&&{MeasureLatency:!0}},HealthCheckTags:[{Key:"Name",Value:n.name}]}};if(n.type==="calculated"){let s=n;i.Properties.HealthCheckConfig.ChildHealthChecks=s.childHealthChecks,i.Properties.HealthCheckConfig.HealthThreshold=s.healthThreshold}else{if(n.ipAddress)i.Properties.HealthCheckConfig.IPAddress=n.ipAddress;if(n.fullyQualifiedDomainName)i.Properties.HealthCheckConfig.FullyQualifiedDomainName=n.fullyQualifiedDomainName;if(n.port)i.Properties.HealthCheckConfig.Port=n.port;if(n.resourcePath)i.Properties.HealthCheckConfig.ResourcePath=n.resourcePath;if(n.enableSNI)i.Properties.HealthCheckConfig.EnableSNI=!0}return i}generateWeightedRecordSetCF(n){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.name,Type:n.type,TTL:n.ttl,ResourceRecords:n.resourceRecords,Weight:n.weight,SetIdentifier:n.setIdentifier,...n.healthCheckId&&{HealthCheckId:n.healthCheckId}}}}generateFailoverRecordSetCF(n){return{Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:n.hostedZoneId,Name:n.name,Type:n.type,TTL:n.ttl,ResourceRecords:n.resourceRecords,Failover:n.failover,SetIdentifier:n.setIdentifier,...n.healthCheckId&&{HealthCheckId:n.healthCheckId}}}}clear(){this.policies.clear(),this.healthChecks.clear(),this.trafficPolicies.clear(),this.policyCounter=0,this.healthCheckCounter=0,this.trafficPolicyCounter=0}}var PE=new Em;class bm{configs=new Map;ksks=new Map;validations=new Map;configCounter=0;kskCounter=0;validationCounter=0;enableDNSSEC(n){let i=`dnssec-${Date.now()}-${this.configCounter++}`,s={id:i,hostedZoneId:n.hostedZoneId,status:"SIGNING",signingStatus:"Initializing DNSSEC signing"};if(this.configs.set(i,s),n.kmsKeyArn)this.createKSK({name:`ksk-${n.hostedZoneId}`,hostedZoneId:n.hostedZoneId,kmsKeyArn:n.kmsKeyArn});return setTimeout(()=>{s.status="SIGNED",s.signingStatus="DNSSEC signing complete"},100),s}disableDNSSEC(n){let i=this.configs.get(n);if(!i)throw Error(`DNSSEC config not found: ${n}`);return i.status="DELETING",i.signingStatus="Removing DNSSEC signing",setTimeout(()=>{i.status="NOT_SIGNING",i.signingStatus="DNSSEC signing removed"},100),i}createKSK(n){let i=`ksk-${Date.now()}-${this.kskCounter++}`,s={id:i,status:"ACTIVE",flag:257,keyManagementServiceArn:n.kmsKeyArn,digestAlgorithm:2,keyTag:Math.floor(Math.random()*65535),publicKey:this.generatePublicKey(),...n};s.dnskeyRecord=`${s.flag} 3 8 ${s.publicKey}`;let o=this.generateDigest(s.dnskeyRecord);return s.digestValue=o,s.dsRecord=`${s.keyTag} 8 ${s.digestAlgorithm} ${o}`,this.ksks.set(i,s),s}deactivateKSK(n){let i=this.ksks.get(n);if(!i)throw Error(`KSK not found: ${n}`);return i.status="INACTIVE",i}validateDNSSEC(n){let i=`validation-${Date.now()}-${this.validationCounter++}`,s=n.checkDNSKEY!==!1?Math.random()>0.1:!1,o=n.checkRRSIG!==!1?Math.random()>0.1:!1,c=s&&o,l=[];if(!s)l.push("DNSKEY record not found");if(!o)l.push("RRSIG record not found");let u;if(!s&&!o)u="INSECURE";else if(s&&o&&c)u="VALID";else if(s||o)u="BOGUS",l.push("Invalid signature or incomplete DNSSEC chain");else u="INVALID";let h={id:i,domain:n.domain,validationStatus:u,dnskeyPresent:s,rrsigPresent:o,validSignature:c,errors:l};return this.validations.set(i,h),h}getDNSSECConfig(n){return this.configs.get(n)}listDNSSECConfigs(){return Array.from(this.configs.values())}getKSK(n){return this.ksks.get(n)}listKSKs(n){let i=Array.from(this.ksks.values());return n?i.filter((s)=>s.hostedZoneId===n):i}getDSRecord(n){let i=this.ksks.get(n);if(!i||!i.dsRecord)throw Error("DS record not available");return i.dsRecord}generatePublicKey(){let n="";for(let i=0;i<256;i++)n+="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charAt(Math.floor(Math.random()*64));return n}generateDigest(n){let i="";for(let s=0;s<64;s++)i+="0123456789ABCDEF".charAt(Math.floor(Math.random()*16));return i}generateDNSSECCF(n){return{Type:"AWS::Route53::DNSSEC",Properties:{HostedZoneId:n.hostedZoneId}}}generateKSKCF(n){return{Type:"AWS::Route53::KeySigningKey",Properties:{Name:n.name,HostedZoneId:n.hostedZoneId,KeyManagementServiceArn:n.keyManagementServiceArn,Status:n.status}}}clear(){this.configs.clear(),this.ksks.clear(),this.validations.clear(),this.configCounter=0,this.kskCounter=0,this.validationCounter=0}}var NE=new bm;class vm{endpoints=new Map;rules=new Map;firewalls=new Map;ruleGroups=new Map;domainLists=new Map;endpointCounter=0;ruleCounter=0;firewallCounter=0;ruleGroupCounter=0;domainListCounter=0;createResolverEndpoint(n){let i=`endpoint-${Date.now()}-${this.endpointCounter++}`,s={id:i,status:"CREATING",...n};return this.endpoints.set(i,s),setTimeout(()=>{s.status="OPERATIONAL",s.ipAddresses.forEach((o)=>{if(!o.ip)o.ip=`10.0.${Math.floor(Math.random()*255)}.${Math.floor(Math.random()*255)}`})},100),s}createInboundEndpoint(n){return this.createResolverEndpoint({name:n.name,direction:"INBOUND",ipAddresses:n.subnetIds.map((i)=>({subnetId:i})),securityGroupIds:n.securityGroupIds})}createOutboundEndpoint(n){return this.createResolverEndpoint({name:n.name,direction:"OUTBOUND",ipAddresses:n.subnetIds.map((i)=>({subnetId:i})),securityGroupIds:n.securityGroupIds})}createResolverRule(n){let i=`rule-${Date.now()}-${this.ruleCounter++}`,s={id:i,status:"CREATING",...n};return this.rules.set(i,s),setTimeout(()=>{s.status="COMPLETE"},100),s}createForwardRule(n){return this.createResolverRule({name:n.name,ruleType:"FORWARD",domainName:n.domainName,targetIps:n.targetIps,resolverEndpointId:n.resolverEndpointId})}createSystemRule(n){return this.createResolverRule({name:n.name,ruleType:"SYSTEM",domainName:n.domainName})}createFirewallDomainList(n){let i=`domain-list-${Date.now()}-${this.domainListCounter++}`,s={id:i,status:"CREATING",...n};return this.domainLists.set(i,s),setTimeout(()=>{s.status="COMPLETE"},100),s}createFirewallRuleGroup(n){let i=`rule-group-${Date.now()}-${this.ruleGroupCounter++}`,s={id:i,name:n.name,rules:n.rules.map((o,c)=>({id:`rule-${i}-${c}`,...o})),shareStatus:"NOT_SHARED"};return this.ruleGroups.set(i,s),s}createBlockRule(n){return this.createFirewallRuleGroup({name:n.name,rules:[{name:n.name,priority:n.priority,action:"BLOCK",blockResponse:n.blockResponse||"NODATA",blockOverrideDomain:n.blockOverrideDomain,firewallDomainListId:n.domainListId}]})}createAllowRule(n){return this.createFirewallRuleGroup({name:n.name,rules:[{name:n.name,priority:n.priority,action:"ALLOW",firewallDomainListId:n.domainListId}]})}createDNSFirewall(n){let i=`firewall-${Date.now()}-${this.firewallCounter++}`,s={id:i,name:n.name,firewallRuleGroupAssociations:n.ruleGroupAssociations.map((o,c)=>({id:`assoc-${i}-${c}`,vpcId:n.vpcId,firewallRuleGroupId:o.firewallRuleGroupId,priority:o.priority,mutationProtection:o.mutationProtection||"DISABLED",status:"COMPLETE"}))};return this.firewalls.set(i,s),s}createMalwareProtectionFirewall(n){let i=this.createFirewallDomainList({name:`${n.name}-malware-domains`,domains:n.maliciousDomains}),s=this.createBlockRule({name:`${n.name}-block-malware`,priority:100,domainListId:i.id,blockResponse:"NXDOMAIN"});return this.createDNSFirewall({name:n.name,vpcId:n.vpcId,ruleGroupAssociations:[{firewallRuleGroupId:s.id,priority:100,mutationProtection:"ENABLED"}]})}getEndpoint(n){return this.endpoints.get(n)}listEndpoints(n){let i=Array.from(this.endpoints.values());return n?i.filter((s)=>s.direction===n):i}getRule(n){return this.rules.get(n)}listRules(){return Array.from(this.rules.values())}getFirewall(n){return this.firewalls.get(n)}listFirewalls(){return Array.from(this.firewalls.values())}generateResolverEndpointCF(n){return{Type:"AWS::Route53Resolver::ResolverEndpoint",Properties:{Name:n.name,Direction:n.direction,IpAddresses:n.ipAddresses.map((i)=>({SubnetId:i.subnetId,...i.ip&&{Ip:i.ip}})),SecurityGroupIds:n.securityGroupIds}}}generateResolverRuleCF(n){return{Type:"AWS::Route53Resolver::ResolverRule",Properties:{Name:n.name,RuleType:n.ruleType,DomainName:n.domainName,...n.targetIps&&{TargetIps:n.targetIps.map((i)=>({Ip:i.ip,Port:i.port||53}))},...n.resolverEndpointId&&{ResolverEndpointId:n.resolverEndpointId}}}}generateFirewallRuleGroupCF(n){return{Type:"AWS::Route53Resolver::FirewallRuleGroup",Properties:{Name:n.name,FirewallRules:n.rules.map((i)=>({Name:i.name,Priority:i.priority,Action:i.action,FirewallDomainListId:i.firewallDomainListId,...i.blockResponse&&{BlockResponse:i.blockResponse},...i.blockOverrideDomain&&{BlockOverrideDomain:i.blockOverrideDomain},...i.blockOverrideTTL&&{BlockOverrideTtl:i.blockOverrideTTL}}))}}}clear(){this.endpoints.clear(),this.rules.clear(),this.firewalls.clear(),this.ruleGroups.clear(),this.domainLists.clear(),this.endpointCounter=0,this.ruleCounter=0,this.firewallCounter=0,this.ruleGroupCounter=0,this.domainListCounter=0}}var kE=new vm;class Tm{bounces=new Map;complaints=new Map;handlers=new Map;suppressionList=new Map;metrics=new Map;bounceCounter=0;complaintCounter=0;handlerCounter=0;suppressionCounter=0;metricsCounter=0;recordBounce(n){let i=`bounce-${Date.now()}-${this.bounceCounter++}`,s={id:i,...n};if(this.bounces.set(i,s),n.bounceType==="Permanent")this.addToSuppressionList({emailAddress:n.recipient,reason:"BOUNCE"});return s}recordComplaint(n){let i=`complaint-${Date.now()}-${this.complaintCounter++}`,s={id:i,...n};this.complaints.set(i,s);for(let o of n.recipients)this.addToSuppressionList({emailAddress:o,reason:"COMPLAINT"});return s}createBounceHandler(n){let i=`handler-${Date.now()}-${this.handlerCounter++}`,s={id:i,...n};return this.handlers.set(i,s),s}createAutomaticBounceHandler(n){return this.createBounceHandler({name:n.name,bounceThreshold:5,complaintThreshold:0.1,suppressionDuration:2592000,autoSuppress:!0,notificationTopicArn:n.notificationTopicArn})}addToSuppressionList(n){let i=`suppression-${Date.now()}-${this.suppressionCounter++}`,s=n.expirationDays?new Date(Date.now()+n.expirationDays*24*60*60*1000):void 0,o={id:i,emailAddress:n.emailAddress,reason:n.reason,suppressedAt:new Date,expiresAt:s,bounceCount:n.reason==="BOUNCE"?1:0,complaintCount:n.reason==="COMPLAINT"?1:0};return this.suppressionList.set(n.emailAddress,o),o}removeFromSuppressionList(n){return this.suppressionList.delete(n)}isSuppressed(n){let i=this.suppressionList.get(n);if(!i)return!1;if(i.expiresAt&&i.expiresAt<new Date)return this.suppressionList.delete(n),!1;return!0}getBounceStatistics(n,i){let s=Array.from(this.bounces.values()).filter((S)=>S.timestamp>=n&&S.timestamp<=i),o=s.length,c=s.filter((S)=>S.bounceType==="Permanent").length,l=s.filter((S)=>S.bounceType==="Transient").length,u=o*10,h=o/u*100,y=new Map;for(let S of s)y.set(S.recipient,(y.get(S.recipient)||0)+1);let f=Array.from(y.entries()).map(([S,b])=>({email:S,count:b})).sort((S,b)=>b.count-S.count).slice(0,10);return{totalBounces:o,permanentBounces:c,transientBounces:l,bounceRate:h,topRecipients:f}}getComplaintStatistics(n,i){let s=Array.from(this.complaints.values()).filter((y)=>y.timestamp>=n&&y.timestamp<=i),o=s.length,c=new Set;for(let y of s)for(let f of y.recipients)c.add(f);let l=c.size,u=o*1000,h=o/u*100;return{totalComplaints:o,uniqueComplainters:l,complaintRate:h}}calculateReputationMetrics(){let n=`metrics-${Date.now()}-${this.metricsCounter++}`,i=new Date,s=new Date(i.getTime()-86400000),o=this.getBounceStatistics(s,i),c=this.getComplaintStatistics(s,i),l;if(o.bounceRate>10||c.complaintRate>0.5)l="Shutdown";else if(o.bounceRate>5||c.complaintRate>0.1)l="Probation";else if(o.bounceRate>2||c.complaintRate>0.05)l="Warning";else l="Good";let u={id:n,timestamp:i,bounceRate:o.bounceRate,complaintRate:c.complaintRate,sendingQuota:50000,maxSendRate:14,sentLast24Hours:o.totalBounces*10,reputationStatus:l};return this.metrics.set(n,u),u}getBounces(n){let i=Array.from(this.bounces.values());return n?i.filter((s)=>s.messageId===n):i}getComplaints(n){let i=Array.from(this.complaints.values());return n?i.filter((s)=>s.messageId===n):i}listSuppressionList(n){let i=Array.from(this.suppressionList.values());return n?i.filter((s)=>s.reason===n):i}generateSNSSubscriptionCF(n){return{Type:"AWS::SNS::Subscription",Properties:{TopicArn:n.topicArn,Endpoint:n.endpoint,Protocol:n.protocol}}}generateEventDestinationCF(n){return{Type:"AWS::SES::ConfigurationSetEventDestination",Properties:{ConfigurationSetName:n.configurationSetName,EventDestination:{Name:n.eventDestinationName,Enabled:!0,MatchingEventTypes:n.eventTypes,...n.snsTopicArn&&{SnsDestination:{TopicARN:n.snsTopicArn}},...n.cloudWatchDestination&&{CloudWatchDestination:n.cloudWatchDestination}}}}}clear(){this.bounces.clear(),this.complaints.clear(),this.handlers.clear(),this.suppressionList.clear(),this.metrics.clear(),this.bounceCounter=0,this.complaintCounter=0,this.handlerCounter=0,this.suppressionCounter=0,this.metricsCounter=0}}var BE=new Tm;class wm{events=new Map;campaigns=new Map;reports=new Map;abTests=new Map;eventCounter=0;campaignCounter=0;reportCounter=0;abTestCounter=0;trackEvent(n){let i=`event-${Date.now()}-${this.eventCounter++}`,s={id:i,...n};if(this.events.set(i,s),n.tags?.campaignId)this.updateCampaignStats(n.tags.campaignId,n.eventType);return s}trackOpen(n){return this.trackEvent({...n,eventType:"open",timestamp:new Date})}trackClick(n){return this.trackEvent({...n,eventType:"click",timestamp:new Date})}createCampaign(n){let i=`campaign-${Date.now()}-${this.campaignCounter++}`,s={id:i,sentCount:0,deliveredCount:0,openCount:0,clickCount:0,bounceCount:0,complaintCount:0,createdAt:new Date,...n};return this.campaigns.set(i,s),s}updateCampaignStats(n,i){let s=this.campaigns.get(n);if(!s)return;switch(i){case"send":s.sentCount++;break;case"delivery":s.deliveredCount++;break;case"open":s.openCount++;break;case"click":s.clickCount++;break;case"bounce":s.bounceCount++;break;case"complaint":s.complaintCount++;break}}generateReport(n){let i=`report-${Date.now()}-${this.reportCounter++}`,s=Array.from(this.events.values()).filter((I)=>{let _=I.timestamp>=n.startDate&&I.timestamp<=n.endDate,B=!n.campaignId||I.tags?.campaignId===n.campaignId;return _&&B}),o=s.filter((I)=>I.eventType==="send").length,c=s.filter((I)=>I.eventType==="delivery").length,l=s.filter((I)=>I.eventType==="open").length,u=s.filter((I)=>I.eventType==="click").length,h=s.filter((I)=>I.eventType==="bounce").length,y=s.filter((I)=>I.eventType==="complaint").length,f=o>0?c/o*100:0,S=c>0?l/c*100:0,b=c>0?u/c*100:0,v=l>0?u/l*100:0,w=o>0?h/o*100:0,E=c>0?y/c*100:0,P=new Map;for(let I of s)if(I.eventType==="click"){let _=I;P.set(_.link,(P.get(_.link)||0)+1)}let R=Array.from(P.entries()).map(([I,_])=>({link:I,clicks:_})).sort((I,_)=>_.clicks-I.clicks).slice(0,10),D={desktop:0,mobile:0,tablet:0,unknown:0};for(let I of s)if(I.eventType==="open"||I.eventType==="click"){let _=I.userAgent.toLowerCase();if(_.includes("mobile"))D.mobile++;else if(_.includes("tablet"))D.tablet++;else if(_.includes("mozilla"))D.desktop++;else D.unknown++}let x={id:i,campaignId:n.campaignId,startDate:n.startDate,endDate:n.endDate,totalSent:o,totalDelivered:c,totalOpened:l,totalClicked:u,totalBounced:h,totalComplaints:y,deliveryRate:f,openRate:S,clickRate:b,clickToOpenRate:v,bounceRate:w,complaintRate:E,topLinks:R,deviceBreakdown:D,locationBreakdown:{}};return this.reports.set(i,x),x}createABTest(n){let i=`abtest-${Date.now()}-${this.abTestCounter++}`,s={id:i,name:n.name,variants:n.variants.map((o,c)=>({id:`variant-${i}-${c}`,sentCount:0,openCount:0,clickCount:0,conversionCount:0,...o})),status:"draft"};return this.abTests.set(i,s),s}startABTest(n){let i=this.abTests.get(n);if(!i)throw Error(`A/B test not found: ${n}`);return i.status="running",i.startedAt=new Date,i}completeABTest(n){let i=this.abTests.get(n);if(!i)throw Error(`A/B test not found: ${n}`);let s=i.variants[0],o=0;for(let c of i.variants){let l=c.sentCount>0?c.openCount/c.sentCount:0;if(l>o)o=l,s=c}return i.status="completed",i.completedAt=new Date,i.winner=s.id,i}getCampaign(n){return this.campaigns.get(n)}listCampaigns(){return Array.from(this.campaigns.values())}getEvents(n){let i=Array.from(this.events.values());if(n?.messageId)i=i.filter((s)=>s.messageId===n.messageId);if(n?.eventType)i=i.filter((s)=>s.eventType===n.eventType);if(n?.startDate)i=i.filter((s)=>s.timestamp>=n.startDate);if(n?.endDate)i=i.filter((s)=>s.timestamp<=n.endDate);return i}generateTrackingConfigurationCF(n){return{Type:"AWS::SES::ConfigurationSet",Properties:{Name:n.configurationSetName,...n.openTracking&&{TrackingOptions:{CustomRedirectDomain:"tracking.example.com"}}}}}clear(){this.events.clear(),this.campaigns.clear(),this.reports.clear(),this.abTests.clear(),this.eventCounter=0,this.campaignCounter=0,this.reportCounter=0,this.abTestCounter=0}}var _E=new wm;class Rm{dashboards=new Map;warmupPlans=new Map;domainReputations=new Map;dashboardCounter=0;warmupCounter=0;domainCounter=0;getReputationDashboard(){let n=`dashboard-${Date.now()}-${this.dashboardCounter++}`,i=Math.random()*5,s=Math.random()*0.5,o=Math.floor(Math.random()*10),c=Math.max(0,100-i*10-s*100-o*2),l=[];if(i>2)l.push("Reduce bounce rate by cleaning email list");if(s>0.1)l.push("Review email content and unsubscribe process");if(o>5)l.push("Improve email relevance and targeting");let u={id:n,timestamp:new Date,overallScore:c,bounceRate:i,complaintRate:s,spamReports:o,blacklistStatus:this.checkBlacklists(),dkimStatus:"VERIFIED",spfStatus:"PASS",dmarcStatus:"PASS",sendingLimits:{maxSendRate:14,max24HourSend:50000,sentLast24Hours:12000,remainingQuota:38000,quotaResetTime:new Date(Date.now()+86400000)},recommendations:l};return this.dashboards.set(n,u),u}checkBlacklists(){return["Spamhaus ZEN","Spamcop","SORBS","Barracuda","URIBL"].map((n)=>({listName:n,listed:Math.random()>0.95,delistUrl:`https://www.${n.toLowerCase().replace(/\s/g,"")}.org/delist`}))}createWarmupPlan(n){let i=`warmup-${Date.now()}-${this.warmupCounter++}`,s=[],o=(n.targetDailyLimit-n.initialDailyLimit)/n.durationDays;for(let l=0;l<n.durationDays;l++)s.push(Math.floor(n.initialDailyLimit+o*l));let c={id:i,name:n.name,startDate:new Date,currentDay:1,totalDays:n.durationDays,dailyLimits:s,currentLimit:s[0],status:"active"};return this.warmupPlans.set(i,c),c}createAggressiveWarmupPlan(n){return this.createWarmupPlan({name:n.name,initialDailyLimit:500,targetDailyLimit:50000,durationDays:14})}createConservativeWarmupPlan(n){return this.createWarmupPlan({name:n.name,initialDailyLimit:200,targetDailyLimit:50000,durationDays:30})}advanceWarmupPlan(n){let i=this.warmupPlans.get(n);if(!i)throw Error(`Warmup plan not found: ${n}`);if(i.currentDay<i.totalDays)i.currentDay++,i.currentLimit=i.dailyLimits[i.currentDay-1];if(i.currentDay>=i.totalDays)i.status="completed";return i}trackDomainReputation(n){let i=`domain-${Date.now()}-${this.domainCounter++}`,s=n.delivered/n.totalSent*100,o=n.delivered>0?n.opened/n.delivered*100:0,c=n.delivered>0?n.clicked/n.delivered*100:0,l=n.bounced/n.totalSent*100,u=n.delivered>0?n.complained/n.delivered*100:0,h=o*0.4+c*0.6,y=Math.max(0,100-l*10-u*100+h*0.2),f={id:i,domain:n.domain,reputationScore:y,totalSent:n.totalSent,deliveryRate:s,openRate:o,clickRate:c,bounceRate:l,complaintRate:u,engagementScore:h};return this.domainReputations.set(n.domain,f),f}getDomainReputation(n){return this.domainReputations.get(n)}listDomainReputations(){return Array.from(this.domainReputations.values())}getWarmupPlan(n){return this.warmupPlans.get(n)}listWarmupPlans(){return Array.from(this.warmupPlans.values())}clear(){this.dashboards.clear(),this.warmupPlans.clear(),this.domainReputations.clear(),this.dashboardCounter=0,this.warmupCounter=0,this.domainCounter=0}}var xE=new Rm;class Dm{templates=new Map;versions=new Map;tests=new Map;templateCounter=0;testCounter=0;createTemplate(n){let i=`template-${Date.now()}-${this.templateCounter++}`,s=this.extractVariables(n.subject+n.htmlPart+n.textPart),o={id:i,variables:s,createdAt:new Date,updatedAt:new Date,version:1,...n};return this.templates.set(i,o),this.addVersion({templateId:i,version:1,subject:n.subject,htmlPart:n.htmlPart,textPart:n.textPart,createdBy:"system"}),o}createWelcomeTemplate(n){return this.createTemplate({name:n.name,subject:"Welcome to {{companyName}}!",htmlPart:`
3777
3777
  <html>
3778
3778
  <body>
3779
3779
  <h1>Welcome, {{userName}}!</h1>
@@ -4033,7 +4033,7 @@ catch {
4033
4033
  ContentType: 'application/json',
4034
4034
  }));
4035
4035
  }
4036
- `;static createThreadingLambda(n){return{[`${n.slug}EmailThreadingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Xt.ThreadingLambdaCode},Environment:{Variables:{EMAIL_BUCKET:n.emailBucket}}}}}}static async getThreads(n){let{s3Client:i,bucket:s,mailbox:o,limit:c=50,offset:l=0}=n,[u,h]=o.includes("@")?o.split("@"):[o,"default"],y=`mailboxes/${h}/${u}/threads.json`;try{let f=await i.send({Bucket:s,Key:y}),b=JSON.parse(f.Body),C=Object.values(b);return C.sort((T,w)=>new Date(w.lastMessageDate).getTime()-new Date(T.lastMessageDate).getTime()),C.slice(l,l+c)}catch{return[]}}static async getThread(n){let{s3Client:i,bucket:s,mailbox:o,threadId:c}=n,[l,u]=o.includes("@")?o.split("@"):[o,"default"],h=`mailboxes/${u}/${l}/threads.json`;try{let y=await i.send({Bucket:s,Key:h});return JSON.parse(y.Body)[c]||null}catch{return null}}}class ea{static SchedulerLambdaCode=`
4036
+ `;static createThreadingLambda(n){return{[`${n.slug}EmailThreadingLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-email-threading`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:60,MemorySize:256,Code:{ZipFile:Xt.ThreadingLambdaCode},Environment:{Variables:{EMAIL_BUCKET:n.emailBucket}}}}}}static async getThreads(n){let{s3Client:i,bucket:s,mailbox:o,limit:c=50,offset:l=0}=n,[u,h]=o.includes("@")?o.split("@"):[o,"default"],y=`mailboxes/${h}/${u}/threads.json`;try{let f=await i.send({Bucket:s,Key:y}),S=JSON.parse(f.Body),b=Object.values(S);return b.sort((v,w)=>new Date(w.lastMessageDate).getTime()-new Date(v.lastMessageDate).getTime()),b.slice(l,l+c)}catch{return[]}}static async getThread(n){let{s3Client:i,bucket:s,mailbox:o,threadId:c}=n,[l,u]=o.includes("@")?o.split("@"):[o,"default"],h=`mailboxes/${u}/${l}/threads.json`;try{let y=await i.send({Bucket:s,Key:h});return JSON.parse(y.Body)[c]||null}catch{return null}}}class ea{static SchedulerLambdaCode=`
4037
4037
  const { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, ListObjectsV2Command } = require('@aws-sdk/client-s3');
4038
4038
  const { SESClient, SendRawEmailCommand } = require('@aws-sdk/client-ses');
4039
4039
 
@@ -4620,7 +4620,7 @@ The {{appName}} Team`,variables:["appName","userName","resetUrl","expiresIn"],ca
4620
4620
 
4621
4621
  <p>Best regards,<br>The {{appName}} Team</p>
4622
4622
  </body>
4623
- </html>`,variables:["invoiceNumber","customerName","period","items","total","paymentUrl","appName"],category:"billing"}};static createTemplateBucket(n){return{[`${n.slug}EmailTemplateBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${n.slug}-email-templates`,VersioningConfiguration:{Status:"Enabled"}}}}}static createTemplateRendererLambda(n){return{[`${n.slug}TemplateRendererLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-template-renderer`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ke.TemplateRendererCode},Environment:{Variables:{TEMPLATE_BUCKET:n.templateBucket}}}}}}static render(n,i){if(!n||!i)return n;let s=n;return s=s.replace(/\{\{\s*([\w.]+)\s*\}\}/g,(o,c)=>{let l=ke.getNestedValue(i,c);return l!==void 0?String(l):o}),s=s.replace(/\{\{#if\s+([\w.]+)\}\}([\s\S]*?)\{\{\/if\}\}/g,(o,c,l)=>ke.getNestedValue(i,c)?l:""),s=s.replace(/\{\{#unless\s+([\w.]+)\}\}([\s\S]*?)\{\{\/unless\}\}/g,(o,c,l)=>!ke.getNestedValue(i,c)?l:""),s=s.replace(/\{\{#each\s+([\w.]+)\}\}([\s\S]*?)\{\{\/each\}\}/g,(o,c,l)=>{let u=ke.getNestedValue(i,c);if(!Array.isArray(u))return"";return u.map((h,y)=>{let f=l;if(f=f.replace(/\{\{this\}\}/g,String(h)),f=f.replace(/\{\{@index\}\}/g,String(y)),typeof h==="object")Object.entries(h).forEach(([b,C])=>{f=f.replace(new RegExp(`\\{\\{\\s*${b}\\s*\\}\\}`,"g"),String(C))});return f}).join("")}),s}static getNestedValue(n,i){return i.split(".").reduce((s,o)=>s?.[o],n)}static extractVariables(n){let i=new Set,s=n.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g);for(let c of s)if(!c[1].startsWith("#")&&!c[1].startsWith("/")&&!c[1].startsWith("@"))i.add(c[1].split(".")[0]);let o=n.matchAll(/\{\{#(?:if|unless|each)\s+([\w.]+)\}\}/g);for(let c of o)i.add(c[1].split(".")[0]);return Array.from(i)}}class ta{static SharedMailboxLambdaCode=`
4623
+ </html>`,variables:["invoiceNumber","customerName","period","items","total","paymentUrl","appName"],category:"billing"}};static createTemplateBucket(n){return{[`${n.slug}EmailTemplateBucket`]:{Type:"AWS::S3::Bucket",Properties:{BucketName:`${n.slug}-email-templates`,VersioningConfiguration:{Status:"Enabled"}}}}}static createTemplateRendererLambda(n){return{[`${n.slug}TemplateRendererLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-template-renderer`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:ke.TemplateRendererCode},Environment:{Variables:{TEMPLATE_BUCKET:n.templateBucket}}}}}}static render(n,i){if(!n||!i)return n;let s=n;return s=s.replace(/\{\{\s*([\w.]+)\s*\}\}/g,(o,c)=>{let l=ke.getNestedValue(i,c);return l!==void 0?String(l):o}),s=s.replace(/\{\{#if\s+([\w.]+)\}\}([\s\S]*?)\{\{\/if\}\}/g,(o,c,l)=>ke.getNestedValue(i,c)?l:""),s=s.replace(/\{\{#unless\s+([\w.]+)\}\}([\s\S]*?)\{\{\/unless\}\}/g,(o,c,l)=>!ke.getNestedValue(i,c)?l:""),s=s.replace(/\{\{#each\s+([\w.]+)\}\}([\s\S]*?)\{\{\/each\}\}/g,(o,c,l)=>{let u=ke.getNestedValue(i,c);if(!Array.isArray(u))return"";return u.map((h,y)=>{let f=l;if(f=f.replace(/\{\{this\}\}/g,String(h)),f=f.replace(/\{\{@index\}\}/g,String(y)),typeof h==="object")Object.entries(h).forEach(([S,b])=>{f=f.replace(new RegExp(`\\{\\{\\s*${S}\\s*\\}\\}`,"g"),String(b))});return f}).join("")}),s}static getNestedValue(n,i){return i.split(".").reduce((s,o)=>s?.[o],n)}static extractVariables(n){let i=new Set,s=n.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g);for(let c of s)if(!c[1].startsWith("#")&&!c[1].startsWith("/")&&!c[1].startsWith("@"))i.add(c[1].split(".")[0]);let o=n.matchAll(/\{\{#(?:if|unless|each)\s+([\w.]+)\}\}/g);for(let c of o)i.add(c[1].split(".")[0]);return Array.from(i)}}class ta{static SharedMailboxLambdaCode=`
4624
4624
  const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3');
4625
4625
  const { DynamoDBClient, GetItemCommand, PutItemCommand, QueryCommand, UpdateItemCommand } = require('@aws-sdk/client-dynamodb');
4626
4626
 
@@ -7261,7 +7261,7 @@ function unmarshallTest(item) {
7261
7261
 
7262
7262
  return test;
7263
7263
  }
7264
- `;static createAbTestsTable(n){return{[`${n.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(n){return{[`${n.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Te.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:n.abTestsTable}}}}}}static selectVariant(n,i){let s=Te.hashString(i+n.id)%100,o=0;for(let c=0;c<n.variants.length;c++)if(o+=n.trafficSplit[c],s<o)return n.variants[c];return n.variants[n.variants.length-1]}static determineWinner(n){if(n.variants.length===0)return null;let i=n.winningCriteria,s=n.variants[0],o=Te.getMetricValue(s,i);for(let c of n.variants.slice(1)){let l=Te.getMetricValue(c,i);if(l>o)o=l,s=c}return s}static calculateSignificance(n,i,s){let o=n.stats.sent,c=i.stats.sent;if(o<30||c<30)return 0;let l=Te.getMetricValue(n,s)/100,u=Te.getMetricValue(i,s)/100,h=(l*o+u*c)/(o+c),y=Math.sqrt(h*(1-h)*(1/o+1/c));if(y===0)return 0;let f=Math.abs(l-u)/y;if(f>=2.576)return 99;if(f>=1.96)return 95;if(f>=1.645)return 90;if(f>=1.28)return 80;return Math.round(f*30)}static getMetricValue(n,i){switch(i){case"delivery_rate":return n.stats.deliveryRate;case"click_rate":return n.stats.clickRate;case"reply_rate":return n.stats.replyRate;case"conversion_rate":return n.stats.conversionRate;default:return n.stats.deliveryRate}}static hashString(n){let i=0;for(let s=0;s<n.length;s++){let o=n.charCodeAt(s);i=(i<<5)-i+o,i=i&i}return Math.abs(i)}}class Pm{queues=new Map;messageGroups=new Map;deduplicationConfigs=new Map;messages=new Map;queueCounter=0;groupCounter=0;deduplicationCounter=0;messageCounter=0;sequenceCounter=0;createFIFOQueue(n){let i=`fifo-queue-${Date.now()}-${this.queueCounter++}`,s=n.name.endsWith(".fifo")?n.name:`${n.name}.fifo`,{name:o,...c}=n,l={id:i,name:s,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${s}`,...c};return this.queues.set(i,l),this.createDeduplicationConfig({queueId:i,contentBasedDeduplication:n.contentBasedDeduplication,deduplicationInterval:300}),l}createHighThroughputFIFO(n){return this.createFIFOQueue({name:n.name,contentBasedDeduplication:n.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(n){return this.createFIFOQueue({name:n.name,contentBasedDeduplication:n.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(n){let i={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...n};return this.deduplicationConfigs.set(n.queueId,i),i}sendMessage(n){let i=this.queues.get(n.queueId);if(!i)throw Error(`Queue not found: ${n.queueId}`);let s=this.deduplicationConfigs.get(n.queueId);if(s){let u=n.messageDeduplicationId||(i.contentBasedDeduplication?this.generateHash(n.messageBody):void 0);if(u&&this.isDuplicate(s,u))return null;if(u)s.deduplicationHashes.set(u,new Date)}let o=`msg-${Date.now()}-${this.messageCounter++}`,c=this.generateSequenceNumber(),l={id:o,messageId:o,messageGroupId:n.messageGroupId,messageDeduplicationId:n.messageDeduplicationId,body:n.messageBody,attributes:n.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:c};return this.messages.set(o,l),this.updateMessageGroup(n.queueId,n.messageGroupId),l}isDuplicate(n,i){let s=n.deduplicationHashes.get(i);if(!s)return!1;if((Date.now()-s.getTime())/1000>n.deduplicationInterval)return n.deduplicationHashes.delete(i),!1;return!0}generateHash(n){let i=0;for(let s=0;s<n.length;s++){let o=n.charCodeAt(s);i=(i<<5)-i+o,i=i&i}return Math.abs(i).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(n,i){let s=`${n}-${i}`,o=this.messageGroups.get(s);if(!o)o={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:i,queueId:n,messagesInFlight:0},this.messageGroups.set(s,o);o.messagesInFlight++,o.lastMessageTimestamp=new Date}getMessageGroups(n){return Array.from(this.messageGroups.values()).filter((i)=>i.queueId===n)}getQueue(n){return this.queues.get(n)}listQueues(){return Array.from(this.queues.values())}getMessages(n,i){let s=Array.from(this.messages.values());if(i)s=s.filter((o)=>o.messageGroupId===i);return s.sort((o,c)=>o.sequenceNumber.localeCompare(c.sequenceNumber))}generateFIFOQueueCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:n.name,FifoQueue:!0,ContentBasedDeduplication:n.contentBasedDeduplication,DeduplicationScope:n.deduplicationScope,FifoThroughputLimit:n.fifoThroughputLimit,MessageRetentionPeriod:n.messageRetentionPeriod,VisibilityTimeout:n.visibilityTimeout,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime,...n.deadLetterTargetArn&&{RedrivePolicy:{deadLetterTargetArn:n.deadLetterTargetArn,maxReceiveCount:n.maxReceiveCount||3}}}}}clear(){this.queues.clear(),this.messageGroups.clear(),this.deduplicationConfigs.clear(),this.messages.clear(),this.queueCounter=0,this.groupCounter=0,this.deduplicationCounter=0,this.messageCounter=0,this.sequenceCounter=0}}var LE=new Pm;class Nm{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(n){let i=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,s={id:i,...n};return this.monitors.set(i,s),s}createAutomatedMonitor(n){return this.createDLQMonitor({name:n.name,queueUrl:n.queueUrl,sourceQueues:n.sourceQueues,maxReceiveCount:3,alarmThreshold:10,autoReprocess:!0,reprocessStrategy:"scheduled",notificationTopicArn:n.notificationTopicArn})}collectMetrics(n){let i={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:n,timestamp:new Date,approximateNumberOfMessages:Math.floor(Math.random()*100),approximateAgeOfOldestMessage:Math.floor(Math.random()*86400),messagesReceived:Math.floor(Math.random()*50),messagesDeleted:Math.floor(Math.random()*30),messagesReprocessed:Math.floor(Math.random()*20)},s=this.metrics.get(n)||[];return s.push(i),this.metrics.set(n,s),this.checkForAlerts(n,i),i}checkForAlerts(n,i){let s=Array.from(this.monitors.values()).find((c)=>c.queueUrl===n);if(!s)return;if(i.approximateNumberOfMessages>=s.alarmThreshold)this.createAlert({monitorId:s.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${s.name} has ${i.approximateNumberOfMessages} messages (threshold: ${s.alarmThreshold})`});let o=3600;if(i.approximateAgeOfOldestMessage>o)this.createAlert({monitorId:s.id,alertType:"old_message",severity:"medium",message:`DLQ ${s.name} has messages older than ${o} seconds`})}createAlert(n){let i=`alert-${Date.now()}-${this.alertCounter++}`,s={id:i,timestamp:new Date,acknowledged:!1,...n};return this.alerts.set(i,s),s}acknowledgeAlert(n){let i=this.alerts.get(n);if(!i)throw Error(`Alert not found: ${n}`);return i.acknowledged=!0,i}createReprocessJob(n){let i=`reprocess-${Date.now()}-${this.jobCounter++}`,s={id:i,queueUrl:n.queueUrl,messageId:n.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(i,s),s}async executeReprocessJob(n){let i=this.reprocessJobs.get(n);if(!i)throw Error(`Reprocess job not found: ${n}`);i.status="processing",i.startedAt=new Date,i.attempts++,await new Promise((o)=>setTimeout(o,100));let s=Math.random()>0.3;if(i.status=s?"success":"failed",i.completedAt=new Date,!s)i.error="Reprocessing failed - original error still present";return i}async batchReprocess(n){let i=[];for(let s=0;s<n.maxMessages;s++){let o=this.createReprocessJob({queueUrl:n.queueUrl,messageId:`msg-${s}`});await this.executeReprocessJob(o.id),i.push(o)}return i}getDLQStatistics(n,i=24){let s=new Date(Date.now()-i*60*60*1000),o=(this.metrics.get(n)||[]).filter((b)=>b.timestamp>=s);if(o.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let c=o[o.length-1],l=o.reduce((b,C)=>b+C.messagesReceived,0),u=o.reduce((b,C)=>b+C.messagesDeleted,0),h=o.reduce((b,C)=>b+C.messagesReprocessed,0),y=o.reduce((b,C)=>b+C.approximateAgeOfOldestMessage,0)/o.length,f=h>0?u/h*100:0;return{totalMessages:c.approximateNumberOfMessages,avgAge:y,messagesReceived:l,messagesDeleted:u,messagesReprocessed:h,successRate:f}}getMonitor(n){return this.monitors.get(n)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(n,i){let s=Array.from(this.alerts.values());if(n)s=s.filter((o)=>o.monitorId===n);if(i!==void 0)s=s.filter((o)=>o.acknowledged===i);return s.sort((o,c)=>c.timestamp.getTime()-o.timestamp.getTime())}getReprocessJobs(n){let i=Array.from(this.reprocessJobs.values());if(n)i=i.filter((s)=>s.queueUrl===n);return i}generateDLQAlarmCF(n){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${n.name}-messages-alarm`,AlarmDescription:`Alert when DLQ ${n.name} exceeds threshold`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:1,Threshold:n.alarmThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:n.queueUrl.split("/").pop()}],...n.notificationTopicArn&&{AlarmActions:[n.notificationTopicArn]}}}}clear(){this.monitors.clear(),this.metrics.clear(),this.alerts.clear(),this.reprocessJobs.clear(),this.monitorCounter=0,this.metricsCounter=0,this.alertCounter=0,this.jobCounter=0}}var $E=new Nm;class km{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(n){let i=`batch-config-${Date.now()}-${this.configCounter++}`,s={id:i,...n};return this.configs.set(i,s),s}createHighThroughputConfig(n){return this.createBatchConfig({queueUrl:n.queueUrl,batchSize:10,maxWaitTime:100,parallelProcessors:10,retryAttempts:3,visibilityTimeout:30})}createLowLatencyConfig(n){return this.createBatchConfig({queueUrl:n.queueUrl,batchSize:1,maxWaitTime:0,parallelProcessors:5,retryAttempts:2,visibilityTimeout:10})}createBatchJob(n){let i=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(n.configId))throw Error(`Batch config not found: ${n.configId}`);let s=[];for(let c=0;c<n.messageCount;c++)s.push({id:`msg-${i}-${c}`,messageId:`${i}-${c}`,body:`Message ${c}`,receiptHandle:`receipt-${i}-${c}`,attributes:{},status:"pending"});let o={id:i,configId:n.configId,messages:s,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(i,o),o}async processBatchJob(n){let i=this.jobs.get(n);if(!i)throw Error(`Batch job not found: ${n}`);let s=this.configs.get(i.configId);if(!s)throw Error(`Batch config not found: ${i.configId}`);i.status="processing",i.startedAt=new Date;let o=this.chunkArray(i.messages,s.batchSize);for(let c of o)await this.processBatch(c,s);return i.processedCount=i.messages.filter((c)=>c.status==="success").length,i.failedCount=i.messages.filter((c)=>c.status==="failed").length,i.status=i.failedCount===0?"completed":"failed",i.completedAt=new Date,this.collectProcessorMetrics(s.id,i),i}async processBatch(n,i){let s=n.map((o)=>this.processMessage(o,i));await Promise.all(s)}async processMessage(n,i){n.status="processing";let s=Date.now();await new Promise((c)=>setTimeout(c,Math.random()*100));let o=Date.now()-s;if(n.processingTime=o,Math.random()>0.1)n.status="success";else n.status="failed",n.error="Processing error"}chunkArray(n,i){let s=[];for(let o=0;o<n.length;o+=i)s.push(n.slice(o,o+i));return s}collectProcessorMetrics(n,i){let s=`metrics-${Date.now()}-${this.metricsCounter++}`,o=i.messages.filter((b)=>b.status==="success").map((b)=>b.processingTime||0).filter((b)=>b>0),c=o.length>0?o.reduce((b,C)=>b+C,0)/o.length:0,l=i.completedAt&&i.startedAt?(i.completedAt.getTime()-i.startedAt.getTime())/1000:1,u=i.processedCount/l,h=i.messages.length>0?i.failedCount/i.messages.length*100:0,y={id:s,configId:n,timestamp:new Date,messagesProcessed:i.processedCount,averageProcessingTime:c,throughput:u,errorRate:h},f=this.metrics.get(n)||[];f.push(y),this.metrics.set(n,f)}getBatchStatistics(n){let i=this.metrics.get(n)||[];if(i.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let s=i.reduce((u,h)=>u+h.messagesProcessed,0),o=i.reduce((u,h)=>u+h.throughput,0)/i.length,c=i.reduce((u,h)=>u+h.errorRate,0)/i.length,l=i.reduce((u,h)=>u+h.averageProcessingTime,0)/i.length;return{totalJobsProcessed:i.length,totalMessagesProcessed:s,averageThroughput:o,averageErrorRate:c,averageProcessingTime:l}}optimizeBatchConfig(n){let i=this.configs.get(n);if(!i)throw Error(`Batch config not found: ${n}`);let s=this.getBatchStatistics(n);if(s.averageErrorRate<5&&i.batchSize<10)i.batchSize=Math.min(10,i.batchSize+1);if(s.averageErrorRate>20&&i.batchSize>1)i.batchSize=Math.max(1,i.batchSize-1);if(s.averageThroughput<5&&i.parallelProcessors<20)i.parallelProcessors++;return i}getConfig(n){return this.configs.get(n)}listConfigs(){return Array.from(this.configs.values())}getJob(n){return this.jobs.get(n)}listJobs(n){let i=Array.from(this.jobs.values());if(n)i=i.filter((s)=>s.configId===n);return i}generateBatchProcessorCF(n){return{Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:`arn:aws:sqs:us-east-1:123456789012:${n.queueUrl.split("/").pop()}`,FunctionName:"batch-processor-function",BatchSize:n.batchSize,MaximumBatchingWindowInSeconds:n.maxWaitTime/1000,FunctionResponseTypes:["ReportBatchItemFailures"]}}}clear(){this.configs.clear(),this.jobs.clear(),this.metrics.clear(),this.configCounter=0,this.jobCounter=0,this.metricsCounter=0}}var ME=new km;class Bm{queues=new Map;retentionPolicies=new Map;delayQueues=new Map;purgeOperations=new Map;metrics=new Map;queueCounter=0;retentionCounter=0;delayCounter=0;purgeCounter=0;metricsCounter=0;createQueue(n){let i=`queue-${Date.now()}-${this.queueCounter++}`,s={id:i,purgeInProgress:!1,...n};return this.queues.set(i,s),s}createStandardQueue(n){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n.queueName}`,queueName:n.queueName,messageRetentionPeriod:(n.messageRetentionDays||4)*24*60*60,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:0})}createLongPollingQueue(n){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n.queueName}`,queueName:n.queueName,messageRetentionPeriod:345600,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:n.waitTimeSeconds||20})}createRetentionPolicy(n){let i=`retention-${Date.now()}-${this.retentionCounter++}`,s={id:i,...n};this.retentionPolicies.set(i,s);let o=this.queues.get(n.queueId);if(o)o.messageRetentionPeriod=n.retentionPeriod;return s}createShortRetentionPolicy(n){return this.createRetentionPolicy({queueId:n.queueId,retentionPeriod:n.retentionHours*60*60,autoCleanup:!0,archiveExpiredMessages:!1})}createArchivalRetentionPolicy(n){return this.createRetentionPolicy({queueId:n.queueId,retentionPeriod:n.retentionDays*24*60*60,autoCleanup:!0,cleanupSchedule:"cron(0 0 * * ? *)",archiveExpiredMessages:!0,archiveS3Bucket:n.s3Bucket})}createDelayQueue(n){let i=`delay-${Date.now()}-${this.delayCounter++}`,s={id:i,...n};this.delayQueues.set(i,s);let o=Array.from(this.queues.values()).find((c)=>c.queueUrl===n.queueUrl);if(o)o.delaySeconds=n.defaultDelay;return s}createScheduledDelayQueue(n){return this.createDelayQueue({queueUrl:n.queueUrl,defaultDelay:n.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(n){let i=this.queues.get(n);if(!i)throw Error(`Queue not found: ${n}`);if(i.purgeInProgress)throw Error("Purge already in progress for this queue");let s=`purge-${Date.now()}-${this.purgeCounter++}`,o={id:s,queueUrl:i.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(s,o),i.purgeInProgress=!0,setTimeout(()=>{o.status="completed",o.completedAt=new Date,o.messagesPurged=Math.floor(Math.random()*1000),i.purgeInProgress=!1},100),o}collectQueueMetrics(n){let i={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:n,timestamp:new Date,approximateNumberOfMessages:Math.floor(Math.random()*1000),approximateNumberOfMessagesNotVisible:Math.floor(Math.random()*100),approximateNumberOfMessagesDelayed:Math.floor(Math.random()*50),oldestMessageAge:Math.floor(Math.random()*86400)},s=this.metrics.get(n)||[];return s.push(i),this.metrics.set(n,s),i}getQueueHealth(n){let i=this.metrics.get(n)||[];if(i.length===0)return{status:"healthy",issues:[],recommendations:[]};let s=i[i.length-1],o=[],c=[],l="healthy";if(s.approximateNumberOfMessages>1e4)l="critical",o.push("Large message backlog detected"),c.push("Increase consumer capacity");else if(s.approximateNumberOfMessages>1000)l="warning",o.push("Growing message backlog"),c.push("Monitor consumer performance");if(s.oldestMessageAge&&s.oldestMessageAge>3600){if(l!=="critical")l="warning";o.push("Old messages in queue"),c.push("Review message processing")}if(s.approximateNumberOfMessagesDelayed>100){if(l!=="critical")l="warning";o.push("High number of delayed messages")}return{status:l,issues:o,recommendations:c}}getQueue(n){return this.queues.get(n)}listQueues(){return Array.from(this.queues.values())}getRetentionPolicy(n){return this.retentionPolicies.get(n)}listRetentionPolicies(){return Array.from(this.retentionPolicies.values())}getPurgeOperations(n){let i=Array.from(this.purgeOperations.values());if(n)i=i.filter((s)=>s.queueUrl===n);return i}generateQueueCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:n.queueName,MessageRetentionPeriod:n.messageRetentionPeriod,DelaySeconds:n.delaySeconds,MaximumMessageSize:n.maximumMessageSize,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime}}}generateCleanupRuleCF(n){return{Type:"AWS::Events::Rule",Properties:{Name:`${n.id}-cleanup`,Description:"Automated queue cleanup",ScheduleExpression:n.cleanupSchedule||"cron(0 0 * * ? *)",State:"ENABLED",Targets:[{Arn:"arn:aws:lambda:us-east-1:123456789012:function:queue-cleanup",Id:n.id,Input:JSON.stringify({queueId:n.queueId,archiveBucket:n.archiveS3Bucket})}]}}}clear(){this.queues.clear(),this.retentionPolicies.clear(),this.delayQueues.clear(),this.purgeOperations.clear(),this.metrics.clear(),this.queueCounter=0,this.retentionCounter=0,this.delayCounter=0,this.purgeCounter=0,this.metricsCounter=0}}var FE=new Bm,Qn=(()=>{let n=[];for(let i=0;i<256;i++){let s=i;for(let o=0;o<8;o++)s=s&1?3988292384^s>>>1:s>>>1;n[i]=s>>>0}return n})();function Jn(n){let i=4294967295;for(let s=0;s<n.length;s++)i=Qn[(i^n[s])&255]^i>>>8;return(i^4294967295)>>>0}function Yn(n){if(typeof n==="string")return Buffer.from(n,"utf-8");if(Buffer.isBuffer(n))return n;return Buffer.from(n)}function Zn(n){let i=Math.max(1980,n.getFullYear()),s=(n.getHours()<<11|n.getMinutes()<<5|n.getSeconds()>>1)&65535,o=(i-1980<<9|n.getMonth()+1<<5|n.getDate())&65535;return{time:s,date:o}}function Bi(n){let i=[],s=[],o=0;for(let u of n){let h=Yn(u.data),y=zn(h),f=Jn(h),b=Buffer.from(u.name.replace(/\\/g,"/"),"utf-8"),{time:C,date:T}=Zn(u.date??new Date(0)),w=u.mode??420,E=Buffer.alloc(30+b.length);E.writeUInt32LE(67324752,0),E.writeUInt16LE(20,4),E.writeUInt16LE(0,6),E.writeUInt16LE(8,8),E.writeUInt16LE(C,10),E.writeUInt16LE(T,12),E.writeUInt32LE(f,14),E.writeUInt32LE(y.length,18),E.writeUInt32LE(h.length,22),E.writeUInt16LE(b.length,26),E.writeUInt16LE(0,28),b.copy(E,30);let I=Buffer.alloc(46+b.length);I.writeUInt32LE(33639248,0),I.writeUInt16LE(798,4),I.writeUInt16LE(20,6),I.writeUInt16LE(0,8),I.writeUInt16LE(8,10),I.writeUInt16LE(C,12),I.writeUInt16LE(T,14),I.writeUInt32LE(f,16),I.writeUInt32LE(y.length,20),I.writeUInt32LE(h.length,24),I.writeUInt16LE(b.length,28),I.writeUInt16LE(0,30),I.writeUInt16LE(0,32),I.writeUInt16LE(0,34),I.writeUInt16LE(0,36),I.writeUInt32LE((w&65535)<<16,38),I.writeUInt32LE(o,42),b.copy(I,46),i.push(E,y),s.push(I),o+=E.length+y.length}let c=Buffer.concat(s),l=Buffer.alloc(22);return l.writeUInt32LE(101010256,0),l.writeUInt16LE(0,4),l.writeUInt16LE(0,6),l.writeUInt16LE(n.length,8),l.writeUInt16LE(n.length,10),l.writeUInt32LE(c.length,12),l.writeUInt32LE(o,16),l.writeUInt16LE(0,20),Buffer.concat([...i,c,l])}function KA(n){let i=n.adapterImport??"./adapter",s=n.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
7264
+ `;static createAbTestsTable(n){return{[`${n.slug}AbTestsTable`]:{Type:"AWS::DynamoDB::Table",Properties:{TableName:`${n.slug}-ab-tests`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"id",AttributeType:"S"}],KeySchema:[{AttributeName:"id",KeyType:"HASH"}]}}}}static createAbTestManagerLambda(n){return{[`${n.slug}AbTestManagerLambda`]:{Type:"AWS::Lambda::Function",Properties:{FunctionName:`${n.slug}-ab-test-manager`,Runtime:"nodejs20.x",Handler:"index.handler",Role:n.roleArn,Timeout:30,MemorySize:256,Code:{ZipFile:Te.AbTestManagerCode},Environment:{Variables:{AB_TESTS_TABLE:n.abTestsTable}}}}}}static selectVariant(n,i){let s=Te.hashString(i+n.id)%100,o=0;for(let c=0;c<n.variants.length;c++)if(o+=n.trafficSplit[c],s<o)return n.variants[c];return n.variants[n.variants.length-1]}static determineWinner(n){if(n.variants.length===0)return null;let i=n.winningCriteria,s=n.variants[0],o=Te.getMetricValue(s,i);for(let c of n.variants.slice(1)){let l=Te.getMetricValue(c,i);if(l>o)o=l,s=c}return s}static calculateSignificance(n,i,s){let o=n.stats.sent,c=i.stats.sent;if(o<30||c<30)return 0;let l=Te.getMetricValue(n,s)/100,u=Te.getMetricValue(i,s)/100,h=(l*o+u*c)/(o+c),y=Math.sqrt(h*(1-h)*(1/o+1/c));if(y===0)return 0;let f=Math.abs(l-u)/y;if(f>=2.576)return 99;if(f>=1.96)return 95;if(f>=1.645)return 90;if(f>=1.28)return 80;return Math.round(f*30)}static getMetricValue(n,i){switch(i){case"delivery_rate":return n.stats.deliveryRate;case"click_rate":return n.stats.clickRate;case"reply_rate":return n.stats.replyRate;case"conversion_rate":return n.stats.conversionRate;default:return n.stats.deliveryRate}}static hashString(n){let i=0;for(let s=0;s<n.length;s++){let o=n.charCodeAt(s);i=(i<<5)-i+o,i=i&i}return Math.abs(i)}}class Pm{queues=new Map;messageGroups=new Map;deduplicationConfigs=new Map;messages=new Map;queueCounter=0;groupCounter=0;deduplicationCounter=0;messageCounter=0;sequenceCounter=0;createFIFOQueue(n){let i=`fifo-queue-${Date.now()}-${this.queueCounter++}`,s=n.name.endsWith(".fifo")?n.name:`${n.name}.fifo`,{name:o,...c}=n,l={id:i,name:s,queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${s}`,...c};return this.queues.set(i,l),this.createDeduplicationConfig({queueId:i,contentBasedDeduplication:n.contentBasedDeduplication,deduplicationInterval:300}),l}createHighThroughputFIFO(n){return this.createFIFOQueue({name:n.name,contentBasedDeduplication:n.contentBasedDeduplication??!0,deduplicationScope:"messageGroup",fifoThroughputLimit:"perMessageGroupId",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createStandardFIFO(n){return this.createFIFOQueue({name:n.name,contentBasedDeduplication:n.contentBasedDeduplication??!1,deduplicationScope:"queue",fifoThroughputLimit:"perQueue",messageRetentionPeriod:345600,visibilityTimeout:30,receiveMessageWaitTime:0})}createDeduplicationConfig(n){let i={id:`dedup-${Date.now()}-${this.deduplicationCounter++}`,deduplicationHashes:new Map,...n};return this.deduplicationConfigs.set(n.queueId,i),i}sendMessage(n){let i=this.queues.get(n.queueId);if(!i)throw Error(`Queue not found: ${n.queueId}`);let s=this.deduplicationConfigs.get(n.queueId);if(s){let u=n.messageDeduplicationId||(i.contentBasedDeduplication?this.generateHash(n.messageBody):void 0);if(u&&this.isDuplicate(s,u))return null;if(u)s.deduplicationHashes.set(u,new Date)}let o=`msg-${Date.now()}-${this.messageCounter++}`,c=this.generateSequenceNumber(),l={id:o,messageId:o,messageGroupId:n.messageGroupId,messageDeduplicationId:n.messageDeduplicationId,body:n.messageBody,attributes:n.messageAttributes||{},sentTimestamp:new Date,sequenceNumber:c};return this.messages.set(o,l),this.updateMessageGroup(n.queueId,n.messageGroupId),l}isDuplicate(n,i){let s=n.deduplicationHashes.get(i);if(!s)return!1;if((Date.now()-s.getTime())/1000>n.deduplicationInterval)return n.deduplicationHashes.delete(i),!1;return!0}generateHash(n){let i=0;for(let s=0;s<n.length;s++){let o=n.charCodeAt(s);i=(i<<5)-i+o,i=i&i}return Math.abs(i).toString(36)}generateSequenceNumber(){return`${Date.now()}${this.sequenceCounter++}`.padStart(20,"0")}updateMessageGroup(n,i){let s=`${n}-${i}`,o=this.messageGroups.get(s);if(!o)o={id:`group-${Date.now()}-${this.groupCounter++}`,messageGroupId:i,queueId:n,messagesInFlight:0},this.messageGroups.set(s,o);o.messagesInFlight++,o.lastMessageTimestamp=new Date}getMessageGroups(n){return Array.from(this.messageGroups.values()).filter((i)=>i.queueId===n)}getQueue(n){return this.queues.get(n)}listQueues(){return Array.from(this.queues.values())}getMessages(n,i){let s=Array.from(this.messages.values());if(i)s=s.filter((o)=>o.messageGroupId===i);return s.sort((o,c)=>o.sequenceNumber.localeCompare(c.sequenceNumber))}generateFIFOQueueCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:n.name,FifoQueue:!0,ContentBasedDeduplication:n.contentBasedDeduplication,DeduplicationScope:n.deduplicationScope,FifoThroughputLimit:n.fifoThroughputLimit,MessageRetentionPeriod:n.messageRetentionPeriod,VisibilityTimeout:n.visibilityTimeout,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime,...n.deadLetterTargetArn&&{RedrivePolicy:{deadLetterTargetArn:n.deadLetterTargetArn,maxReceiveCount:n.maxReceiveCount||3}}}}}clear(){this.queues.clear(),this.messageGroups.clear(),this.deduplicationConfigs.clear(),this.messages.clear(),this.queueCounter=0,this.groupCounter=0,this.deduplicationCounter=0,this.messageCounter=0,this.sequenceCounter=0}}var LE=new Pm;class Nm{monitors=new Map;metrics=new Map;alerts=new Map;reprocessJobs=new Map;monitorCounter=0;metricsCounter=0;alertCounter=0;jobCounter=0;createDLQMonitor(n){let i=`dlq-monitor-${Date.now()}-${this.monitorCounter++}`,s={id:i,...n};return this.monitors.set(i,s),s}createAutomatedMonitor(n){return this.createDLQMonitor({name:n.name,queueUrl:n.queueUrl,sourceQueues:n.sourceQueues,maxReceiveCount:3,alarmThreshold:10,autoReprocess:!0,reprocessStrategy:"scheduled",notificationTopicArn:n.notificationTopicArn})}collectMetrics(n){let i={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:n,timestamp:new Date,approximateNumberOfMessages:Math.floor(Math.random()*100),approximateAgeOfOldestMessage:Math.floor(Math.random()*86400),messagesReceived:Math.floor(Math.random()*50),messagesDeleted:Math.floor(Math.random()*30),messagesReprocessed:Math.floor(Math.random()*20)},s=this.metrics.get(n)||[];return s.push(i),this.metrics.set(n,s),this.checkForAlerts(n,i),i}checkForAlerts(n,i){let s=Array.from(this.monitors.values()).find((c)=>c.queueUrl===n);if(!s)return;if(i.approximateNumberOfMessages>=s.alarmThreshold)this.createAlert({monitorId:s.id,alertType:"threshold_exceeded",severity:"high",message:`DLQ ${s.name} has ${i.approximateNumberOfMessages} messages (threshold: ${s.alarmThreshold})`});let o=3600;if(i.approximateAgeOfOldestMessage>o)this.createAlert({monitorId:s.id,alertType:"old_message",severity:"medium",message:`DLQ ${s.name} has messages older than ${o} seconds`})}createAlert(n){let i=`alert-${Date.now()}-${this.alertCounter++}`,s={id:i,timestamp:new Date,acknowledged:!1,...n};return this.alerts.set(i,s),s}acknowledgeAlert(n){let i=this.alerts.get(n);if(!i)throw Error(`Alert not found: ${n}`);return i.acknowledged=!0,i}createReprocessJob(n){let i=`reprocess-${Date.now()}-${this.jobCounter++}`,s={id:i,queueUrl:n.queueUrl,messageId:n.messageId,attempts:0,status:"pending"};return this.reprocessJobs.set(i,s),s}async executeReprocessJob(n){let i=this.reprocessJobs.get(n);if(!i)throw Error(`Reprocess job not found: ${n}`);i.status="processing",i.startedAt=new Date,i.attempts++,await new Promise((o)=>setTimeout(o,100));let s=Math.random()>0.3;if(i.status=s?"success":"failed",i.completedAt=new Date,!s)i.error="Reprocessing failed - original error still present";return i}async batchReprocess(n){let i=[];for(let s=0;s<n.maxMessages;s++){let o=this.createReprocessJob({queueUrl:n.queueUrl,messageId:`msg-${s}`});await this.executeReprocessJob(o.id),i.push(o)}return i}getDLQStatistics(n,i=24){let s=new Date(Date.now()-i*60*60*1000),o=(this.metrics.get(n)||[]).filter((S)=>S.timestamp>=s);if(o.length===0)return{totalMessages:0,avgAge:0,messagesReceived:0,messagesDeleted:0,messagesReprocessed:0,successRate:0};let c=o[o.length-1],l=o.reduce((S,b)=>S+b.messagesReceived,0),u=o.reduce((S,b)=>S+b.messagesDeleted,0),h=o.reduce((S,b)=>S+b.messagesReprocessed,0),y=o.reduce((S,b)=>S+b.approximateAgeOfOldestMessage,0)/o.length,f=h>0?u/h*100:0;return{totalMessages:c.approximateNumberOfMessages,avgAge:y,messagesReceived:l,messagesDeleted:u,messagesReprocessed:h,successRate:f}}getMonitor(n){return this.monitors.get(n)}listMonitors(){return Array.from(this.monitors.values())}getAlerts(n,i){let s=Array.from(this.alerts.values());if(n)s=s.filter((o)=>o.monitorId===n);if(i!==void 0)s=s.filter((o)=>o.acknowledged===i);return s.sort((o,c)=>c.timestamp.getTime()-o.timestamp.getTime())}getReprocessJobs(n){let i=Array.from(this.reprocessJobs.values());if(n)i=i.filter((s)=>s.queueUrl===n);return i}generateDLQAlarmCF(n){return{Type:"AWS::CloudWatch::Alarm",Properties:{AlarmName:`${n.name}-messages-alarm`,AlarmDescription:`Alert when DLQ ${n.name} exceeds threshold`,MetricName:"ApproximateNumberOfMessagesVisible",Namespace:"AWS/SQS",Statistic:"Average",Period:300,EvaluationPeriods:1,Threshold:n.alarmThreshold,ComparisonOperator:"GreaterThanThreshold",Dimensions:[{Name:"QueueName",Value:n.queueUrl.split("/").pop()}],...n.notificationTopicArn&&{AlarmActions:[n.notificationTopicArn]}}}}clear(){this.monitors.clear(),this.metrics.clear(),this.alerts.clear(),this.reprocessJobs.clear(),this.monitorCounter=0,this.metricsCounter=0,this.alertCounter=0,this.jobCounter=0}}var $E=new Nm;class km{configs=new Map;jobs=new Map;metrics=new Map;configCounter=0;jobCounter=0;metricsCounter=0;createBatchConfig(n){let i=`batch-config-${Date.now()}-${this.configCounter++}`,s={id:i,...n};return this.configs.set(i,s),s}createHighThroughputConfig(n){return this.createBatchConfig({queueUrl:n.queueUrl,batchSize:10,maxWaitTime:100,parallelProcessors:10,retryAttempts:3,visibilityTimeout:30})}createLowLatencyConfig(n){return this.createBatchConfig({queueUrl:n.queueUrl,batchSize:1,maxWaitTime:0,parallelProcessors:5,retryAttempts:2,visibilityTimeout:10})}createBatchJob(n){let i=`batch-job-${Date.now()}-${this.jobCounter++}`;if(!this.configs.get(n.configId))throw Error(`Batch config not found: ${n.configId}`);let s=[];for(let c=0;c<n.messageCount;c++)s.push({id:`msg-${i}-${c}`,messageId:`${i}-${c}`,body:`Message ${c}`,receiptHandle:`receipt-${i}-${c}`,attributes:{},status:"pending"});let o={id:i,configId:n.configId,messages:s,status:"pending",processedCount:0,failedCount:0};return this.jobs.set(i,o),o}async processBatchJob(n){let i=this.jobs.get(n);if(!i)throw Error(`Batch job not found: ${n}`);let s=this.configs.get(i.configId);if(!s)throw Error(`Batch config not found: ${i.configId}`);i.status="processing",i.startedAt=new Date;let o=this.chunkArray(i.messages,s.batchSize);for(let c of o)await this.processBatch(c,s);return i.processedCount=i.messages.filter((c)=>c.status==="success").length,i.failedCount=i.messages.filter((c)=>c.status==="failed").length,i.status=i.failedCount===0?"completed":"failed",i.completedAt=new Date,this.collectProcessorMetrics(s.id,i),i}async processBatch(n,i){let s=n.map((o)=>this.processMessage(o,i));await Promise.all(s)}async processMessage(n,i){n.status="processing";let s=Date.now();await new Promise((c)=>setTimeout(c,Math.random()*100));let o=Date.now()-s;if(n.processingTime=o,Math.random()>0.1)n.status="success";else n.status="failed",n.error="Processing error"}chunkArray(n,i){let s=[];for(let o=0;o<n.length;o+=i)s.push(n.slice(o,o+i));return s}collectProcessorMetrics(n,i){let s=`metrics-${Date.now()}-${this.metricsCounter++}`,o=i.messages.filter((S)=>S.status==="success").map((S)=>S.processingTime||0).filter((S)=>S>0),c=o.length>0?o.reduce((S,b)=>S+b,0)/o.length:0,l=i.completedAt&&i.startedAt?(i.completedAt.getTime()-i.startedAt.getTime())/1000:1,u=i.processedCount/l,h=i.messages.length>0?i.failedCount/i.messages.length*100:0,y={id:s,configId:n,timestamp:new Date,messagesProcessed:i.processedCount,averageProcessingTime:c,throughput:u,errorRate:h},f=this.metrics.get(n)||[];f.push(y),this.metrics.set(n,f)}getBatchStatistics(n){let i=this.metrics.get(n)||[];if(i.length===0)return{totalJobsProcessed:0,totalMessagesProcessed:0,averageThroughput:0,averageErrorRate:0,averageProcessingTime:0};let s=i.reduce((u,h)=>u+h.messagesProcessed,0),o=i.reduce((u,h)=>u+h.throughput,0)/i.length,c=i.reduce((u,h)=>u+h.errorRate,0)/i.length,l=i.reduce((u,h)=>u+h.averageProcessingTime,0)/i.length;return{totalJobsProcessed:i.length,totalMessagesProcessed:s,averageThroughput:o,averageErrorRate:c,averageProcessingTime:l}}optimizeBatchConfig(n){let i=this.configs.get(n);if(!i)throw Error(`Batch config not found: ${n}`);let s=this.getBatchStatistics(n);if(s.averageErrorRate<5&&i.batchSize<10)i.batchSize=Math.min(10,i.batchSize+1);if(s.averageErrorRate>20&&i.batchSize>1)i.batchSize=Math.max(1,i.batchSize-1);if(s.averageThroughput<5&&i.parallelProcessors<20)i.parallelProcessors++;return i}getConfig(n){return this.configs.get(n)}listConfigs(){return Array.from(this.configs.values())}getJob(n){return this.jobs.get(n)}listJobs(n){let i=Array.from(this.jobs.values());if(n)i=i.filter((s)=>s.configId===n);return i}generateBatchProcessorCF(n){return{Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:`arn:aws:sqs:us-east-1:123456789012:${n.queueUrl.split("/").pop()}`,FunctionName:"batch-processor-function",BatchSize:n.batchSize,MaximumBatchingWindowInSeconds:n.maxWaitTime/1000,FunctionResponseTypes:["ReportBatchItemFailures"]}}}clear(){this.configs.clear(),this.jobs.clear(),this.metrics.clear(),this.configCounter=0,this.jobCounter=0,this.metricsCounter=0}}var ME=new km;class Bm{queues=new Map;retentionPolicies=new Map;delayQueues=new Map;purgeOperations=new Map;metrics=new Map;queueCounter=0;retentionCounter=0;delayCounter=0;purgeCounter=0;metricsCounter=0;createQueue(n){let i=`queue-${Date.now()}-${this.queueCounter++}`,s={id:i,purgeInProgress:!1,...n};return this.queues.set(i,s),s}createStandardQueue(n){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n.queueName}`,queueName:n.queueName,messageRetentionPeriod:(n.messageRetentionDays||4)*24*60*60,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:0})}createLongPollingQueue(n){return this.createQueue({queueUrl:`https://sqs.us-east-1.amazonaws.com/123456789012/${n.queueName}`,queueName:n.queueName,messageRetentionPeriod:345600,delaySeconds:0,maximumMessageSize:262144,receiveMessageWaitTime:n.waitTimeSeconds||20})}createRetentionPolicy(n){let i=`retention-${Date.now()}-${this.retentionCounter++}`,s={id:i,...n};this.retentionPolicies.set(i,s);let o=this.queues.get(n.queueId);if(o)o.messageRetentionPeriod=n.retentionPeriod;return s}createShortRetentionPolicy(n){return this.createRetentionPolicy({queueId:n.queueId,retentionPeriod:n.retentionHours*60*60,autoCleanup:!0,archiveExpiredMessages:!1})}createArchivalRetentionPolicy(n){return this.createRetentionPolicy({queueId:n.queueId,retentionPeriod:n.retentionDays*24*60*60,autoCleanup:!0,cleanupSchedule:"cron(0 0 * * ? *)",archiveExpiredMessages:!0,archiveS3Bucket:n.s3Bucket})}createDelayQueue(n){let i=`delay-${Date.now()}-${this.delayCounter++}`,s={id:i,...n};this.delayQueues.set(i,s);let o=Array.from(this.queues.values()).find((c)=>c.queueUrl===n.queueUrl);if(o)o.delaySeconds=n.defaultDelay;return s}createScheduledDelayQueue(n){return this.createDelayQueue({queueUrl:n.queueUrl,defaultDelay:n.delayMinutes*60,perMessageDelay:!1,maxDelay:900})}async purgeQueue(n){let i=this.queues.get(n);if(!i)throw Error(`Queue not found: ${n}`);if(i.purgeInProgress)throw Error("Purge already in progress for this queue");let s=`purge-${Date.now()}-${this.purgeCounter++}`,o={id:s,queueUrl:i.queueUrl,status:"in_progress",startedAt:new Date};return this.purgeOperations.set(s,o),i.purgeInProgress=!0,setTimeout(()=>{o.status="completed",o.completedAt=new Date,o.messagesPurged=Math.floor(Math.random()*1000),i.purgeInProgress=!1},100),o}collectQueueMetrics(n){let i={id:`metrics-${Date.now()}-${this.metricsCounter++}`,queueUrl:n,timestamp:new Date,approximateNumberOfMessages:Math.floor(Math.random()*1000),approximateNumberOfMessagesNotVisible:Math.floor(Math.random()*100),approximateNumberOfMessagesDelayed:Math.floor(Math.random()*50),oldestMessageAge:Math.floor(Math.random()*86400)},s=this.metrics.get(n)||[];return s.push(i),this.metrics.set(n,s),i}getQueueHealth(n){let i=this.metrics.get(n)||[];if(i.length===0)return{status:"healthy",issues:[],recommendations:[]};let s=i[i.length-1],o=[],c=[],l="healthy";if(s.approximateNumberOfMessages>1e4)l="critical",o.push("Large message backlog detected"),c.push("Increase consumer capacity");else if(s.approximateNumberOfMessages>1000)l="warning",o.push("Growing message backlog"),c.push("Monitor consumer performance");if(s.oldestMessageAge&&s.oldestMessageAge>3600){if(l!=="critical")l="warning";o.push("Old messages in queue"),c.push("Review message processing")}if(s.approximateNumberOfMessagesDelayed>100){if(l!=="critical")l="warning";o.push("High number of delayed messages")}return{status:l,issues:o,recommendations:c}}getQueue(n){return this.queues.get(n)}listQueues(){return Array.from(this.queues.values())}getRetentionPolicy(n){return this.retentionPolicies.get(n)}listRetentionPolicies(){return Array.from(this.retentionPolicies.values())}getPurgeOperations(n){let i=Array.from(this.purgeOperations.values());if(n)i=i.filter((s)=>s.queueUrl===n);return i}generateQueueCF(n){return{Type:"AWS::SQS::Queue",Properties:{QueueName:n.queueName,MessageRetentionPeriod:n.messageRetentionPeriod,DelaySeconds:n.delaySeconds,MaximumMessageSize:n.maximumMessageSize,ReceiveMessageWaitTimeSeconds:n.receiveMessageWaitTime}}}generateCleanupRuleCF(n){return{Type:"AWS::Events::Rule",Properties:{Name:`${n.id}-cleanup`,Description:"Automated queue cleanup",ScheduleExpression:n.cleanupSchedule||"cron(0 0 * * ? *)",State:"ENABLED",Targets:[{Arn:"arn:aws:lambda:us-east-1:123456789012:function:queue-cleanup",Id:n.id,Input:JSON.stringify({queueId:n.queueId,archiveBucket:n.archiveS3Bucket})}]}}}clear(){this.queues.clear(),this.retentionPolicies.clear(),this.delayQueues.clear(),this.purgeOperations.clear(),this.metrics.clear(),this.queueCounter=0,this.retentionCounter=0,this.delayCounter=0,this.purgeCounter=0,this.metricsCounter=0}}var FE=new Bm,Qn=(()=>{let n=[];for(let i=0;i<256;i++){let s=i;for(let o=0;o<8;o++)s=s&1?3988292384^s>>>1:s>>>1;n[i]=s>>>0}return n})();function Jn(n){let i=4294967295;for(let s=0;s<n.length;s++)i=Qn[(i^n[s])&255]^i>>>8;return(i^4294967295)>>>0}function Yn(n){if(typeof n==="string")return Buffer.from(n,"utf-8");if(Buffer.isBuffer(n))return n;return Buffer.from(n)}function Zn(n){let i=Math.max(1980,n.getFullYear()),s=(n.getHours()<<11|n.getMinutes()<<5|n.getSeconds()>>1)&65535,o=(i-1980<<9|n.getMonth()+1<<5|n.getDate())&65535;return{time:s,date:o}}function Bi(n){let i=[],s=[],o=0;for(let u of n){let h=Yn(u.data),y=zn(h),f=Jn(h),S=Buffer.from(u.name.replace(/\\/g,"/"),"utf-8"),{time:b,date:v}=Zn(u.date??new Date(0)),w=u.mode??420,E=Buffer.alloc(30+S.length);E.writeUInt32LE(67324752,0),E.writeUInt16LE(20,4),E.writeUInt16LE(0,6),E.writeUInt16LE(8,8),E.writeUInt16LE(b,10),E.writeUInt16LE(v,12),E.writeUInt32LE(f,14),E.writeUInt32LE(y.length,18),E.writeUInt32LE(h.length,22),E.writeUInt16LE(S.length,26),E.writeUInt16LE(0,28),S.copy(E,30);let P=Buffer.alloc(46+S.length);P.writeUInt32LE(33639248,0),P.writeUInt16LE(798,4),P.writeUInt16LE(20,6),P.writeUInt16LE(0,8),P.writeUInt16LE(8,10),P.writeUInt16LE(b,12),P.writeUInt16LE(v,14),P.writeUInt32LE(f,16),P.writeUInt32LE(y.length,20),P.writeUInt32LE(h.length,24),P.writeUInt16LE(S.length,28),P.writeUInt16LE(0,30),P.writeUInt16LE(0,32),P.writeUInt16LE(0,34),P.writeUInt16LE(0,36),P.writeUInt32LE((w&65535)<<16,38),P.writeUInt32LE(o,42),S.copy(P,46),i.push(E,y),s.push(P),o+=E.length+y.length}let c=Buffer.concat(s),l=Buffer.alloc(22);return l.writeUInt32LE(101010256,0),l.writeUInt16LE(0,4),l.writeUInt16LE(0,6),l.writeUInt16LE(n.length,8),l.writeUInt16LE(n.length,10),l.writeUInt32LE(c.length,12),l.writeUInt32LE(o,16),l.writeUInt16LE(0,20),Buffer.concat([...i,c,l])}function KA(n){let i=n.adapterImport??"./adapter",s=n.entryImport.replace(/\\/g,"/");return`// Generated by ts-cloud — serverless app bootstrap. Do not edit.
7265
7265
  import * as __userModule from ${JSON.stringify(s)}
7266
7266
  import { resolveApp, createHandlers } from ${JSON.stringify(i)}
7267
7267
 
@@ -7271,9 +7271,9 @@ const __handlers = createHandlers(__app)
7271
7271
  export const http = __handlers.http
7272
7272
  export const queue = __handlers.queue
7273
7273
  export const cli = __handlers.cli
7274
- `}var ui=["adapter.ts","recursion.ts","auto-recursion.ts"];function di(){return Oe(si(li(import.meta.url)),"runtime")}function WA(n,i,s){for(let o of n??[])s?.(`build: ${o}`),Xn(o,{stdio:"inherit",cwd:i})}function Io(n){return ei("sha256").update(n).digest("hex")}function Ud(n,i,s){return`deployments/${n}/${i}/${s}.zip`}async function Kr(n){let i=ci(n.projectRoot??process.cwd()),{app:s}=n;if(!n.skipBuild)WA(s.build,i,n.onStep);let o=s.entry;if(!o)throw Error("serverless app: `entry` is required to package a Node/Bun application");let c=oi(o)?o:Oe(i,o),l=ai(Oe(ii(),"tscloud-pkg-"));try{for(let T of ui)ti(Oe(di(),T),Oe(l,T));let u=Oe(l,"bootstrap.ts");ni(u,KA({entryImport:c,adapterImport:"./adapter"})),n.onStep?.("bundling application");let h=await Bun.build({entrypoints:[u],target:s.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!h.success){let T=h.logs.map((w)=>String(w)).join(`
7274
+ `}var ui=["adapter.ts","recursion.ts","auto-recursion.ts"];function di(){return Oe(si(li(import.meta.url)),"runtime")}function WA(n,i,s){for(let o of n??[])s?.(`build: ${o}`),Xn(o,{stdio:"inherit",cwd:i})}function Io(n){return ei("sha256").update(n).digest("hex")}function Ud(n,i,s){return`deployments/${n}/${i}/${s}.zip`}async function Kr(n){let i=ci(n.projectRoot??process.cwd()),{app:s}=n;if(!n.skipBuild)WA(s.build,i,n.onStep);let o=s.entry;if(!o)throw Error("serverless app: `entry` is required to package a Node/Bun application");let c=oi(o)?o:Oe(i,o),l=ai(Oe(ii(),"tscloud-pkg-"));try{for(let v of ui)ti(Oe(di(),v),Oe(l,v));let u=Oe(l,"bootstrap.ts");ni(u,KA({entryImport:c,adapterImport:"./adapter"})),n.onStep?.("bundling application");let h=await Bun.build({entrypoints:[u],target:s.kind==="bun"?"bun":"node",format:"esm",minify:!1,sourcemap:"none"});if(!h.success){let v=h.logs.map((w)=>String(w)).join(`
7275
7275
  `);throw Error(`serverless app bundle failed:
7276
- ${T}`)}let y=h.outputs[0],f=Buffer.from(await y.arrayBuffer()),b="index",C=Bi([{name:`${b}.mjs`,data:f}]);return{zip:C,bundle:f,sha256:Io(C),handlerFile:b,handlers:{http:s.handlers?.http??`${b}.http`,queue:s.handlers?.queue??`${b}.queue`,cli:s.handlers?.cli??`${b}.cli`},bundleBytes:f.length}}finally{ri(l,{recursive:!0,force:!0})}}var JA=["18","20","22"];function mi(n){if(!n)return"22";let i=String(n).match(/(\d+)/);return i?i[1]:"22"}function So(n){let i=n.kind??"node";if(i==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:n.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(i==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:n.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let s=mi(n.runtimeVersion);if(n.runtime!=="provided.al2023"&&JA.includes(s))return{lambdaRuntime:n.runtime&&n.runtime.startsWith("nodejs")?n.runtime:`nodejs${s}.x`,kind:"node",version:s,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:s,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function Jt(n,i,s){if(n.queues===!1)return[];if(n.queues===void 0||n.queues===!0)return[{name:`${i}-${s}-default`}];return n.queues.map((o)=>{if(typeof o==="string")return{name:`${i}-${s}-${o}`};let[c,l]=Object.entries(o)[0];return{name:`${i}-${s}-${c}`,concurrency:l}})}function Qd(n,i,s){return Jt(n,i,s).map((o)=>o.name)}function Hd(n){let{app:i,environment:s,handlers:o}=n,c=n.config.project.slug,l=So(i).lambdaRuntime,u=i.architecture??"x86_64",h=n.config.project.region,y={http:`${c}-${s}-http`,queue:`${c}-${s}-queue`,cli:`${c}-${s}-cli`};if(i.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let f=Jt(i,c,s),b=f.map((z)=>z.name),C=b.length>0,T=i.logRetention??14,w=i.packaging==="image";if(w&&i.lambdaInsights)throw Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");let E=(i.scheduler??"on")!=="off",I=(i.cache?.driver??"dynamodb")==="dynamodb",N=Boolean(i.assets),D=uo(c,s),x=i.tmpStorage??512,R={},_={},B=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:e.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:e.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${c}-${s}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[e.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${c}/${s}/*`),e.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${c}/${s}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[e.sub(`arn:aws:s3:::${D}`),e.sub(`arn:aws:s3:::${D}/*`),...i.storage?.bucket?[e.sub(`arn:aws:s3:::${i.storage.bucket}`),e.sub(`arn:aws:s3:::${i.storage.bucket}/*`)]:[]]}]}}];if(C)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:e.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${c}-${s}-*`)});if(I)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:e.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${c}-${s}-cache*`)});let W=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(i.vpc?.subnets?.length)W.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(i.lambdaInsights)W.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");R.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${c}-${s}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:W,Policies:B}};let J=(z)=>({TSCLOUD_LAMBDA_MODE:z,TSCLOUD_ENV:s,...i.octane?{TSCLOUD_OCTANE:"1"}:{},...i.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...I?{TSCLOUD_CACHE_TABLE:`${c}-${s}-cache`}:{},...C?{TSCLOUD_QUEUE:b[0]}:{},...i.env??{}}),K=Boolean(i.efs),Y=typeof i.efs==="object"?i.efs:{},Z=Y.mountPath??"/mnt/local",ne=K&&!Y.accessPointArn,de=Y.accessPointArn??(ne?e.getAtt("EfsAccessPoint","Arn"):void 0),oe=i.vpc?.subnets??[],le=oe.length>0,ie=i.cache?.driver==="elasticache"||i.database?.connection==="aurora-serverless"||Boolean(i.rdsProxy)||K;if(ie&&!le)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Ee=le?{VpcConfig:{SubnetIds:oe,SecurityGroupIds:[...i.vpc?.securityGroups??[],...ie?[e.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Fe=ne?oe.map((z,ae)=>`EfsMountTarget${ae}`):[],Et=K?{FileSystemConfigs:[{Arn:de,LocalMountPath:Z}]}:{};if(K)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function pe(z,ae,X,se,fe,nt,Ce,it=x){R[`${z}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${ae}`,RetentionInDays:T}};let Pt=[...n.runtimeLayers??[],...i.lambdaInsights?[i.lambdaInsights.layerArn]:[]],It=w?{PackageType:"Image",Code:{ImageUri:e.ref("ImageUri")},...i.kind==="php"?{}:{ImageConfig:{Command:[X]}}}:{Runtime:l,Handler:X,Code:{S3Bucket:e.ref("ArtifactBucket"),S3Key:e.ref("ArtifactKey")},...Pt.length?{Layers:[...new Set(Pt)]}:{}};R[z]={Type:"AWS::Lambda::Function",DependsOn:[`${z}LogGroup`,...Fe],Properties:{FunctionName:ae,Architectures:[u],MemorySize:fe,Timeout:nt,Role:e.getAtt("AppRole","Arn"),Environment:{Variables:J(se)},EphemeralStorage:{Size:it},...It,...Ce!==void 0?{ReservedConcurrentExecutions:Ce}:{},...Ee,...Et}}}if(pe("HttpFunction",y.http,o.http,"http",i.memory??1024,i.timeout??28,i.concurrency,x),pe("CliFunction",y.cli,o.cli,"cli",i.cliMemory??1024,i.cliTimeout??900,void 0,i.cliTmpStorage??x),C)pe("QueueFunction",y.queue,o.queue,"queue",i.queueMemory??1024,i.queueTimeout??120,void 0,i.queueTmpStorage??x);let ue=(i.provisionedConcurrency??0)>0?i.provisionedConcurrency:0,he=["HttpFunction","CliFunction",...C?["QueueFunction"]:[]];if(ue)for(let z of he)R[`${z}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:e.ref(z)}},R[`${z}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.ref(z),Name:"live",FunctionVersion:e.getAtt(`${z}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ue}}};let Ie=(z)=>ue?e.ref(`${z}Alias`):e.getAtt(z,"Arn"),ye=(z)=>ue?e.ref(`${z}Alias`):e.ref(z);R.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${c}-${s}`,ProtocolType:"HTTP"}},R.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:e.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:Ie("HttpFunction"),PayloadFormatVersion:"2.0"}},R.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:e.ref("HttpApi"),RouteKey:"$default",Target:e.join("/",["integrations",e.ref("HttpIntegration")])}},R.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:e.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},R.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ye("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:e.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},_.HttpApiEndpoint={Description:"HTTP API endpoint",Value:e.getAtt("HttpApi","ApiEndpoint")},_.HttpApiId={Description:"HTTP API id",Value:e.ref("HttpApi")};let Ae=(Array.isArray(i.domain)?i.domain:i.domain?[i.domain]:[]).filter(Boolean);if(Ae.length){if(!i.certificateArn&&!i.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let z=i.certificateArn;if(!z)R.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:Ae[0],...Ae.length>1?{SubjectAlternativeNames:Ae.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:Ae.map((ae)=>({DomainName:ae,HostedZoneId:i.hostedZoneId}))}},z=e.ref("HttpCertificate");Ae.forEach((ae,X)=>{let se=`HttpDomain${X}`;if(R[se]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:ae,DomainNameConfigurations:[{CertificateArn:z,EndpointType:"REGIONAL"}]}},R[`HttpApiMapping${X}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:e.ref("HttpApi"),DomainName:e.ref(se),Stage:"$default"}},i.hostedZoneId)R[`HttpDomainRecord${X}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i.hostedZoneId,Name:ae,Type:"A",AliasTarget:{DNSName:e.getAtt(se,"RegionalDomainName"),HostedZoneId:e.getAtt(se,"RegionalHostedZoneId")}}};_[`CustomDomain${X}`]={Description:`Custom domain ${ae}`,Value:ae},_[`CustomDomainTarget${X}`]={Description:`Point ${ae} (CNAME/alias) at this APIGW regional domain`,Value:e.getAtt(se,"RegionalDomainName")}})}if(C)R.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${c}-${s}-dlq`,MessageRetentionPeriod:1209600}},f.forEach((z,ae)=>{let X=`AppQueue${ae}`,se=i.queueTimeout??120;R[X]={Type:"AWS::SQS::Queue",Properties:{QueueName:z.name,VisibilityTimeout:Math.min(43200,se*6),RedrivePolicy:{deadLetterTargetArn:e.getAtt("AppQueueDlq","Arn"),maxReceiveCount:i.queueTries??3}}};let fe=z.concurrency??i.queueConcurrency;R[`${X}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:e.getAtt(X,"Arn"),FunctionName:ye("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...fe?{ScalingConfig:{MaximumConcurrency:Math.max(2,fe)}}:{}}},_[`QueueUrl${ae}`]={Description:`Queue URL: ${z.name}`,Value:e.ref(X)}});if(E)R.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${c}-${s}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:Ie("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},R.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ye("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.getAtt("SchedulerRule","Arn")}};if(i.warm&&i.warm>0){let z={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},ae=(i.warmFunctions??["http"]).filter((X)=>X!=="queue"||C);for(let X of ae){let se=X.charAt(0).toUpperCase()+X.slice(1),fe=Math.ceil(i.warm/5),nt=0;for(let Ce=0;Ce<fe;Ce++){let it=Math.min(5,i.warm-nt);R[`Warmer${se}Rule${Ce}`]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-${s}-warmer-${X}-${Ce}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:it},(Pt,It)=>({Id:`warm-${X}-${Ce}-${It}`,Arn:e.getAtt(z[X],"Arn"),Input:JSON.stringify({warmer:!0})}))}},nt+=it}R[`Warmer${se}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:e.ref(z[X]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${c}-${s}-warmer-${X}-*`)}}}}if(I)R.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-${s}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},_.CacheTableName={Description:"DynamoDB cache table",Value:e.ref("CacheTable")};if(N){if(R.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:D,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},R.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${c}-${s}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},R.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:e.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:e.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...i.assetDomain?{Aliases:[i.assetDomain],ViewerCertificate:{AcmCertificateArn:i.assetCertificateArn??e.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},i.assetDomain){if(!i.assetCertificateArn){if(!i.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(h!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${h}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);R.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:i.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:i.assetDomain,HostedZoneId:i.hostedZoneId}]}}}if(i.hostedZoneId)R.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i.hostedZoneId,Name:i.assetDomain,Type:"A",AliasTarget:{DNSName:e.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};_.AssetDomain={Description:"Custom asset CDN host",Value:i.assetDomain}}R.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:e.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:e.sub(`arn:aws:s3:::${D}/*`),Condition:{StringEquals:{"AWS:SourceArn":e.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},_.AssetsBucketName={Description:"Assets bucket",Value:e.ref("AssetsBucket")},_.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:e.getAtt("AssetsDistribution","DomainName")}}if(i.firewall?.enabled){let z=[],ae=0;if(i.firewall.rateLimit)z.push({Name:"rate-limit",Priority:ae++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:i.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-rate`}});let X={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let se of i.firewall.rules??[]){let fe=X[se];if(!fe)continue;z.push({Name:`managed-${se}`,Priority:ae++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:fe}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-${se}`}})}R.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${c}-${s}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:z,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-waf`}}},_.WafAclArn={Description:"WAF web ACL ARN. Attach to a CloudFront distribution fronting the API to enforce (HTTP API v2 stages do not support direct WAF association).",Value:e.getAtt("WebAcl","Arn")}}if(le&&ie){if(!i.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");R.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:i.vpc.id,GroupDescription:`${c}-${s} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(ne)R.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${c}-${s}-efs`}]}},oe.forEach((z,ae)=>{R[`EfsMountTarget${ae}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:e.ref("EfsFileSystem"),SubnetId:z,SecurityGroups:[e.getAtt("DataSecurityGroup","GroupId")]}}}),R.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:e.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},_.EfsFileSystemId={Description:"EFS file system id",Value:e.ref("EfsFileSystem")};if(i.cache?.driver==="elasticache")R.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${c}-${s} cache subnets`,SubnetIds:oe}},R.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${c}-${s}-cache`,ReplicationGroupDescription:`${c}-${s} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:e.ref("CacheSubnetGroup"),SecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},_.CacheEndpoint={Description:"Redis primary endpoint",Value:e.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(i.database?.connection==="aurora-serverless")R.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${c}-${s} db subnets`,SubnetIds:oe}},R.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${c}/${s}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},R.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${c}-${s}-db`,DatabaseName:"app",MasterUsername:e.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:e.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:i.database?.minCapacity??0.5,MaxCapacity:i.database?.maxCapacity??4},DBSubnetGroupName:e.ref("DbSubnetGroup"),VpcSecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")]}},R.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:e.ref("DbCluster")}},_.DbEndpoint={Description:"Aurora cluster endpoint",Value:e.getAtt("DbCluster","Endpoint.Address")};if(i.rdsProxy&&i.database?.connection==="aurora-serverless")R.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:e.ref("DbSecret")}]}}]}},R.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof i.rdsProxy==="object"&&i.rdsProxy.name?i.rdsProxy.name:`${c}-${s}-proxy`,EngineFamily:"MYSQL",RoleArn:e.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:e.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:oe,VpcSecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},R.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:e.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[e.ref("DbCluster")]}},_.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:e.getAtt("DbProxy","Endpoint")};if(_.HttpFunctionName={Description:"HTTP function name",Value:e.ref("HttpFunction")},_.CliFunctionName={Description:"CLI function name",Value:e.ref("CliFunction")},C)_.QueueFunctionName={Description:"Queue function name",Value:e.ref("QueueFunction")};let Me={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${n.config.project.name} (${c}-${s})`,Parameters:w?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:R,Outputs:_},Ue={};for(let z of Object.values(R))Ue[z.Type]=(Ue[z.Type]??0)+1;return{template:Me,functionNames:y,queueNames:b,resourceSummary:Ue}}var XA=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function YA(n){let i=`php${n.replace(".","")}`;return XA.map((s)=>`${i}-php-${s}`)}function _m(n,i){let s=`php${n.replace(".","")}`,o=YA(n).join(" \\\n "),c=`/opt/remi/${s}/root`,l=`/etc/opt/remi/${s}`;return`${i?`FROM almalinux:9 AS ${i}`:"FROM almalinux:9"}
7276
+ ${v}`)}let y=h.outputs[0],f=Buffer.from(await y.arrayBuffer()),S="index",b=Bi([{name:`${S}.mjs`,data:f}]);return{zip:b,bundle:f,sha256:Io(b),handlerFile:S,handlers:{http:s.handlers?.http??`${S}.http`,queue:s.handlers?.queue??`${S}.queue`,cli:s.handlers?.cli??`${S}.cli`},bundleBytes:f.length}}finally{ri(l,{recursive:!0,force:!0})}}var JA=["18","20","22"];function mi(n){if(!n)return"22";let i=String(n).match(/(\d+)/);return i?i[1]:"22"}function So(n){let i=n.kind??"node";if(i==="php")return{lambdaRuntime:"provided.al2023",kind:"php",version:n.phpVersion??"8.3",usesLayer:!0,layerKind:"php",layerEnvVar:"TSCLOUD_PHP_LAYER_ARN"};if(i==="bun")return{lambdaRuntime:"provided.al2023",kind:"bun",version:n.runtimeVersion??"latest",usesLayer:!0,layerKind:"bun",layerEnvVar:"TSCLOUD_BUN_LAYER_ARN"};let s=mi(n.runtimeVersion);if(n.runtime!=="provided.al2023"&&JA.includes(s))return{lambdaRuntime:n.runtime&&n.runtime.startsWith("nodejs")?n.runtime:`nodejs${s}.x`,kind:"node",version:s,usesLayer:!1};return{lambdaRuntime:"provided.al2023",kind:"node",version:s,usesLayer:!0,layerKind:"node",layerEnvVar:"TSCLOUD_NODE_LAYER_ARN"}}function Jt(n,i,s){if(n.queues===!1)return[];if(n.queues===void 0||n.queues===!0)return[{name:`${i}-${s}-default`}];return n.queues.map((o)=>{if(typeof o==="string")return{name:`${i}-${s}-${o}`};let[c,l]=Object.entries(o)[0];return{name:`${i}-${s}-${c}`,concurrency:l}})}function Qd(n,i,s){return Jt(n,i,s).map((o)=>o.name)}function Hd(n){let{app:i,environment:s,handlers:o}=n,c=n.config.project.slug,l=So(i).lambdaRuntime,u=i.architecture??"x86_64",h=n.config.project.region,y={http:`${c}-${s}-http`,queue:`${c}-${s}-queue`,cli:`${c}-${s}-cli`};if(i.gatewayVersion===1)throw Error("serverless app: `gatewayVersion: 1` (REST API) is not supported — ts-cloud uses API Gateway HTTP API (v2). Remove `gatewayVersion` or set it to 2.");let f=Jt(i,c,s),S=f.map((z)=>z.name),b=S.length>0,v=i.logRetention??14,w=i.packaging==="image";if(w&&i.lambdaInsights)throw Error("serverless app: `lambdaInsights` layer attachment is only supported for zip packaging. Container images must install the Lambda Insights extension in the image.");let E=(i.scheduler??"on")!=="off",P=(i.cache?.driver??"dynamodb")==="dynamodb",R=Boolean(i.assets),D=uo(c,s),x=i.tmpStorage??512,I={},_={},B=[{PolicyName:"tscloud-serverless-app",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],Resource:e.sub("arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*")},{Effect:"Allow",Action:["lambda:InvokeFunction"],Resource:e.sub(`arn:aws:lambda:\${AWS::Region}:\${AWS::AccountId}:function:${c}-${s}-*`)},{Effect:"Allow",Action:["secretsmanager:GetSecretValue","ssm:GetParameter","ssm:GetParameters","ssm:GetParametersByPath"],Resource:[e.sub(`arn:aws:secretsmanager:\${AWS::Region}:\${AWS::AccountId}:secret:${c}/${s}/*`),e.sub(`arn:aws:ssm:\${AWS::Region}:\${AWS::AccountId}:parameter/${c}/${s}/*`)]},{Effect:"Allow",Action:["s3:GetObject","s3:PutObject","s3:DeleteObject","s3:ListBucket"],Resource:[e.sub(`arn:aws:s3:::${D}`),e.sub(`arn:aws:s3:::${D}/*`),...i.storage?.bucket?[e.sub(`arn:aws:s3:::${i.storage.bucket}`),e.sub(`arn:aws:s3:::${i.storage.bucket}/*`)]:[]]}]}}];if(b)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["sqs:SendMessage","sqs:ReceiveMessage","sqs:DeleteMessage","sqs:GetQueueAttributes","sqs:GetQueueUrl"],Resource:e.sub(`arn:aws:sqs:\${AWS::Region}:\${AWS::AccountId}:${c}-${s}-*`)});if(P)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["dynamodb:GetItem","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem","dynamodb:Query","dynamodb:Scan","dynamodb:BatchGetItem","dynamodb:BatchWriteItem"],Resource:e.sub(`arn:aws:dynamodb:\${AWS::Region}:\${AWS::AccountId}:table/${c}-${s}-cache*`)});let W=["arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"];if(i.vpc?.subnets?.length)W.push("arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole");if(i.lambdaInsights)W.push("arn:aws:iam::aws:policy/CloudWatchLambdaInsightsExecutionRolePolicy");I.AppRole={Type:"AWS::IAM::Role",Properties:{RoleName:`${c}-${s}-app-role`,AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"lambda.amazonaws.com"},Action:"sts:AssumeRole"}]},ManagedPolicyArns:W,Policies:B}};let J=(z)=>({TSCLOUD_LAMBDA_MODE:z,TSCLOUD_ENV:s,...i.octane?{TSCLOUD_OCTANE:"1"}:{},...i.scheduler==="sub-minute"?{TSCLOUD_SCHEDULER:"sub-minute"}:{},...P?{TSCLOUD_CACHE_TABLE:`${c}-${s}-cache`}:{},...b?{TSCLOUD_QUEUE:S[0]}:{},...i.env??{}}),K=Boolean(i.efs),Y=typeof i.efs==="object"?i.efs:{},Z=Y.mountPath??"/mnt/local",ne=K&&!Y.accessPointArn,de=Y.accessPointArn??(ne?e.getAtt("EfsAccessPoint","Arn"):void 0),oe=i.vpc?.subnets??[],le=oe.length>0,ie=i.cache?.driver==="elasticache"||i.database?.connection==="aurora-serverless"||Boolean(i.rdsProxy)||K;if(ie&&!le)throw Error("serverless app: elasticache / aurora-serverless / rdsProxy / efs require app.vpc.subnets (private subnets) to be set.");let Ee=le?{VpcConfig:{SubnetIds:oe,SecurityGroupIds:[...i.vpc?.securityGroups??[],...ie?[e.getAtt("DataSecurityGroup","GroupId")]:[]]}}:{},Fe=ne?oe.map((z,ae)=>`EfsMountTarget${ae}`):[],Et=K?{FileSystemConfigs:[{Arn:de,LocalMountPath:Z}]}:{};if(K)B[0].PolicyDocument.Statement.push({Effect:"Allow",Action:["elasticfilesystem:ClientMount","elasticfilesystem:ClientWrite","elasticfilesystem:ClientRootAccess","elasticfilesystem:DescribeMountTargets"],Resource:"*"});function pe(z,ae,X,se,fe,nt,Ce,it=x){I[`${z}LogGroup`]={Type:"AWS::Logs::LogGroup",Properties:{LogGroupName:`/aws/lambda/${ae}`,RetentionInDays:v}};let Pt=[...n.runtimeLayers??[],...i.lambdaInsights?[i.lambdaInsights.layerArn]:[]],It=w?{PackageType:"Image",Code:{ImageUri:e.ref("ImageUri")},...i.kind==="php"?{}:{ImageConfig:{Command:[X]}}}:{Runtime:l,Handler:X,Code:{S3Bucket:e.ref("ArtifactBucket"),S3Key:e.ref("ArtifactKey")},...Pt.length?{Layers:[...new Set(Pt)]}:{}};I[z]={Type:"AWS::Lambda::Function",DependsOn:[`${z}LogGroup`,...Fe],Properties:{FunctionName:ae,Architectures:[u],MemorySize:fe,Timeout:nt,Role:e.getAtt("AppRole","Arn"),Environment:{Variables:J(se)},EphemeralStorage:{Size:it},...It,...Ce!==void 0?{ReservedConcurrentExecutions:Ce}:{},...Ee,...Et}}}if(pe("HttpFunction",y.http,o.http,"http",i.memory??1024,i.timeout??28,i.concurrency,x),pe("CliFunction",y.cli,o.cli,"cli",i.cliMemory??1024,i.cliTimeout??900,void 0,i.cliTmpStorage??x),b)pe("QueueFunction",y.queue,o.queue,"queue",i.queueMemory??1024,i.queueTimeout??120,void 0,i.queueTmpStorage??x);let ue=(i.provisionedConcurrency??0)>0?i.provisionedConcurrency:0,he=["HttpFunction","CliFunction",...b?["QueueFunction"]:[]];if(ue)for(let z of he)I[`${z}Version`]={Type:"AWS::Lambda::Version",DeletionPolicy:"Retain",Properties:{FunctionName:e.ref(z)}},I[`${z}Alias`]={Type:"AWS::Lambda::Alias",Properties:{FunctionName:e.ref(z),Name:"live",FunctionVersion:e.getAtt(`${z}Version`,"Version"),ProvisionedConcurrencyConfig:{ProvisionedConcurrentExecutions:ue}}};let Ie=(z)=>ue?e.ref(`${z}Alias`):e.getAtt(z,"Arn"),ye=(z)=>ue?e.ref(`${z}Alias`):e.ref(z);I.HttpApi={Type:"AWS::ApiGatewayV2::Api",Properties:{Name:`${c}-${s}`,ProtocolType:"HTTP"}},I.HttpIntegration={Type:"AWS::ApiGatewayV2::Integration",Properties:{ApiId:e.ref("HttpApi"),IntegrationType:"AWS_PROXY",IntegrationUri:Ie("HttpFunction"),PayloadFormatVersion:"2.0"}},I.HttpRoute={Type:"AWS::ApiGatewayV2::Route",Properties:{ApiId:e.ref("HttpApi"),RouteKey:"$default",Target:e.join("/",["integrations",e.ref("HttpIntegration")])}},I.HttpStage={Type:"AWS::ApiGatewayV2::Stage",Properties:{ApiId:e.ref("HttpApi"),StageName:"$default",AutoDeploy:!0}},I.HttpPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ye("HttpFunction"),Action:"lambda:InvokeFunction",Principal:"apigateway.amazonaws.com",SourceArn:e.sub("arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${HttpApi}/*/*")}},_.HttpApiEndpoint={Description:"HTTP API endpoint",Value:e.getAtt("HttpApi","ApiEndpoint")},_.HttpApiId={Description:"HTTP API id",Value:e.ref("HttpApi")};let Ae=(Array.isArray(i.domain)?i.domain:i.domain?[i.domain]:[]).filter(Boolean);if(Ae.length){if(!i.certificateArn&&!i.hostedZoneId)throw Error("serverless app: a custom `domain` needs either `certificateArn` (pre-issued, regional) or `hostedZoneId` (to auto-issue + validate an ACM cert).");let z=i.certificateArn;if(!z)I.HttpCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:Ae[0],...Ae.length>1?{SubjectAlternativeNames:Ae.slice(1)}:{},ValidationMethod:"DNS",DomainValidationOptions:Ae.map((ae)=>({DomainName:ae,HostedZoneId:i.hostedZoneId}))}},z=e.ref("HttpCertificate");Ae.forEach((ae,X)=>{let se=`HttpDomain${X}`;if(I[se]={Type:"AWS::ApiGatewayV2::DomainName",Properties:{DomainName:ae,DomainNameConfigurations:[{CertificateArn:z,EndpointType:"REGIONAL"}]}},I[`HttpApiMapping${X}`]={Type:"AWS::ApiGatewayV2::ApiMapping",DependsOn:["HttpStage"],Properties:{ApiId:e.ref("HttpApi"),DomainName:e.ref(se),Stage:"$default"}},i.hostedZoneId)I[`HttpDomainRecord${X}`]={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i.hostedZoneId,Name:ae,Type:"A",AliasTarget:{DNSName:e.getAtt(se,"RegionalDomainName"),HostedZoneId:e.getAtt(se,"RegionalHostedZoneId")}}};_[`CustomDomain${X}`]={Description:`Custom domain ${ae}`,Value:ae},_[`CustomDomainTarget${X}`]={Description:`Point ${ae} (CNAME/alias) at this APIGW regional domain`,Value:e.getAtt(se,"RegionalDomainName")}})}if(b)I.AppQueueDlq={Type:"AWS::SQS::Queue",Properties:{QueueName:`${c}-${s}-dlq`,MessageRetentionPeriod:1209600}},f.forEach((z,ae)=>{let X=`AppQueue${ae}`,se=i.queueTimeout??120;I[X]={Type:"AWS::SQS::Queue",Properties:{QueueName:z.name,VisibilityTimeout:Math.min(43200,se*6),RedrivePolicy:{deadLetterTargetArn:e.getAtt("AppQueueDlq","Arn"),maxReceiveCount:i.queueTries??3}}};let fe=z.concurrency??i.queueConcurrency;I[`${X}Mapping`]={Type:"AWS::Lambda::EventSourceMapping",Properties:{EventSourceArn:e.getAtt(X,"Arn"),FunctionName:ye("QueueFunction"),BatchSize:1,FunctionResponseTypes:["ReportBatchItemFailures"],...fe?{ScalingConfig:{MaximumConcurrency:Math.max(2,fe)}}:{}}},_[`QueueUrl${ae}`]={Description:`Queue URL: ${z.name}`,Value:e.ref(X)}});if(E)I.SchedulerRule={Type:"AWS::Events::Rule",Properties:{Name:`${c}-${s}-scheduler`,ScheduleExpression:"rate(1 minute)",State:"ENABLED",Targets:[{Id:"cli",Arn:Ie("CliFunction"),Input:JSON.stringify({command:"schedule:run"})}]}},I.SchedulerPermission={Type:"AWS::Lambda::Permission",Properties:{FunctionName:ye("CliFunction"),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.getAtt("SchedulerRule","Arn")}};if(i.warm&&i.warm>0){let z={http:"HttpFunction",queue:"QueueFunction",cli:"CliFunction"},ae=(i.warmFunctions??["http"]).filter((X)=>X!=="queue"||b);for(let X of ae){let se=X.charAt(0).toUpperCase()+X.slice(1),fe=Math.ceil(i.warm/5),nt=0;for(let Ce=0;Ce<fe;Ce++){let it=Math.min(5,i.warm-nt);I[`Warmer${se}Rule${Ce}`]={Type:"AWS::Events::Rule",Properties:{Name:`${c}-${s}-warmer-${X}-${Ce}`,ScheduleExpression:"rate(5 minutes)",State:"ENABLED",Targets:Array.from({length:it},(Pt,It)=>({Id:`warm-${X}-${Ce}-${It}`,Arn:e.getAtt(z[X],"Arn"),Input:JSON.stringify({warmer:!0})}))}},nt+=it}I[`Warmer${se}Permission`]={Type:"AWS::Lambda::Permission",Properties:{FunctionName:e.ref(z[X]),Action:"lambda:InvokeFunction",Principal:"events.amazonaws.com",SourceArn:e.sub(`arn:aws:events:\${AWS::Region}:\${AWS::AccountId}:rule/${c}-${s}-warmer-${X}-*`)}}}}if(P)I.CacheTable={Type:"AWS::DynamoDB::Table",Properties:{TableName:`${c}-${s}-cache`,BillingMode:"PAY_PER_REQUEST",AttributeDefinitions:[{AttributeName:"key",AttributeType:"S"}],KeySchema:[{AttributeName:"key",KeyType:"HASH"}],TimeToLiveSpecification:{AttributeName:"expires_at",Enabled:!0}}},_.CacheTableName={Description:"DynamoDB cache table",Value:e.ref("CacheTable")};if(R){if(I.AssetsBucket={Type:"AWS::S3::Bucket",Properties:{BucketName:D,PublicAccessBlockConfiguration:{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}}},I.AssetsOAC={Type:"AWS::CloudFront::OriginAccessControl",Properties:{OriginAccessControlConfig:{Name:`${c}-${s}-assets-oac`,OriginAccessControlOriginType:"s3",SigningBehavior:"always",SigningProtocol:"sigv4"}}},I.AssetsDistribution={Type:"AWS::CloudFront::Distribution",Properties:{DistributionConfig:{Enabled:!0,DefaultCacheBehavior:{TargetOriginId:"assets",ViewerProtocolPolicy:"redirect-to-https",Compress:!0,CachePolicyId:"658327ea-f89d-4fab-a63d-7e88639e58f6"},Origins:[{Id:"assets",DomainName:e.getAtt("AssetsBucket","RegionalDomainName"),OriginAccessControlId:e.ref("AssetsOAC"),S3OriginConfig:{OriginAccessIdentity:""}}],...i.assetDomain?{Aliases:[i.assetDomain],ViewerCertificate:{AcmCertificateArn:i.assetCertificateArn??e.ref("AssetsCertificate"),SslSupportMethod:"sni-only",MinimumProtocolVersion:"TLSv1.2_2021"}}:{}}}},i.assetDomain){if(!i.assetCertificateArn){if(!i.hostedZoneId)throw Error("serverless app: `assetDomain` requires either `assetCertificateArn` (a us-east-1 ACM cert) or `hostedZoneId` (to auto-issue + validate one). CloudFront only accepts certs from us-east-1.");if(h!=="us-east-1")throw Error(`serverless app: auto-issuing an asset-domain cert needs a us-east-1 app (CloudFront certs must be us-east-1); this app is in ${h}. Supply a pre-issued us-east-1 \`assetCertificateArn\` instead.`);I.AssetsCertificate={Type:"AWS::CertificateManager::Certificate",Properties:{DomainName:i.assetDomain,ValidationMethod:"DNS",DomainValidationOptions:[{DomainName:i.assetDomain,HostedZoneId:i.hostedZoneId}]}}}if(i.hostedZoneId)I.AssetsDomainRecord={Type:"AWS::Route53::RecordSet",Properties:{HostedZoneId:i.hostedZoneId,Name:i.assetDomain,Type:"A",AliasTarget:{DNSName:e.getAtt("AssetsDistribution","DomainName"),HostedZoneId:"Z2FDTNDATAQYW2"}}};_.AssetDomain={Description:"Custom asset CDN host",Value:i.assetDomain}}I.AssetsBucketPolicy={Type:"AWS::S3::BucketPolicy",Properties:{Bucket:e.ref("AssetsBucket"),PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"cloudfront.amazonaws.com"},Action:"s3:GetObject",Resource:e.sub(`arn:aws:s3:::${D}/*`),Condition:{StringEquals:{"AWS:SourceArn":e.sub("arn:aws:cloudfront::${AWS::AccountId}:distribution/${AssetsDistribution}")}}}]}}},_.AssetsBucketName={Description:"Assets bucket",Value:e.ref("AssetsBucket")},_.AssetsCdnDomain={Description:"Assets CloudFront domain",Value:e.getAtt("AssetsDistribution","DomainName")}}if(i.firewall?.enabled){let z=[],ae=0;if(i.firewall.rateLimit)z.push({Name:"rate-limit",Priority:ae++,Action:{Block:{}},Statement:{RateBasedStatement:{Limit:i.firewall.rateLimit,AggregateKeyType:"IP"}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-rate`}});let X={sqlInjection:"AWSManagedRulesSQLiRuleSet",xss:"AWSManagedRulesCommonRuleSet",common:"AWSManagedRulesCommonRuleSet",botControl:"AWSManagedRulesBotControlRuleSet",ipReputation:"AWSManagedRulesAmazonIpReputationList"};for(let se of i.firewall.rules??[]){let fe=X[se];if(!fe)continue;z.push({Name:`managed-${se}`,Priority:ae++,OverrideAction:{None:{}},Statement:{ManagedRuleGroupStatement:{VendorName:"AWS",Name:fe}},VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-${se}`}})}I.WebAcl={Type:"AWS::WAFv2::WebACL",Properties:{Name:`${c}-${s}-waf`,Scope:"REGIONAL",DefaultAction:{Allow:{}},Rules:z,VisibilityConfig:{SampledRequestsEnabled:!0,CloudWatchMetricsEnabled:!0,MetricName:`${c}-${s}-waf`}}},_.WafAclArn={Description:"WAF web ACL ARN. Attach to a CloudFront distribution fronting the API to enforce (HTTP API v2 stages do not support direct WAF association).",Value:e.getAtt("WebAcl","Arn")}}if(le&&ie){if(!i.vpc?.id)throw Error("serverless app: data services (elasticache / aurora-serverless / rdsProxy / efs) need app.vpc.id (the VPC id) so the managed security group is created in the right VPC.");I.DataSecurityGroup={Type:"AWS::EC2::SecurityGroup",Properties:{VpcId:i.vpc.id,GroupDescription:`${c}-${s} serverless data access`,SecurityGroupIngress:[{IpProtocol:"-1",CidrIp:"10.0.0.0/8"}]}}}if(ne)I.EfsFileSystem={Type:"AWS::EFS::FileSystem",Properties:{Encrypted:!0,FileSystemTags:[{Key:"Name",Value:`${c}-${s}-efs`}]}},oe.forEach((z,ae)=>{I[`EfsMountTarget${ae}`]={Type:"AWS::EFS::MountTarget",Properties:{FileSystemId:e.ref("EfsFileSystem"),SubnetId:z,SecurityGroups:[e.getAtt("DataSecurityGroup","GroupId")]}}}),I.EfsAccessPoint={Type:"AWS::EFS::AccessPoint",Properties:{FileSystemId:e.ref("EfsFileSystem"),PosixUser:{Uid:1001,Gid:1001},RootDirectory:{Path:"/lambda",CreationInfo:{OwnerUid:1001,OwnerGid:1001,Permissions:"0755"}}}},_.EfsFileSystemId={Description:"EFS file system id",Value:e.ref("EfsFileSystem")};if(i.cache?.driver==="elasticache")I.CacheSubnetGroup={Type:"AWS::ElastiCache::SubnetGroup",Properties:{Description:`${c}-${s} cache subnets`,SubnetIds:oe}},I.CacheCluster={Type:"AWS::ElastiCache::ReplicationGroup",Properties:{ReplicationGroupId:`${c}-${s}-cache`,ReplicationGroupDescription:`${c}-${s} redis`,Engine:"redis",CacheNodeType:"cache.t4g.micro",NumCacheClusters:1,AutomaticFailoverEnabled:!1,CacheSubnetGroupName:e.ref("CacheSubnetGroup"),SecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")],TransitEncryptionEnabled:!1}},_.CacheEndpoint={Description:"Redis primary endpoint",Value:e.getAtt("CacheCluster","PrimaryEndPoint.Address")};if(i.database?.connection==="aurora-serverless")I.DbSubnetGroup={Type:"AWS::RDS::DBSubnetGroup",Properties:{DBSubnetGroupDescription:`${c}-${s} db subnets`,SubnetIds:oe}},I.DbSecret={Type:"AWS::SecretsManager::Secret",Properties:{Name:`${c}/${s}/db`,GenerateSecretString:{SecretStringTemplate:JSON.stringify({username:"app"}),GenerateStringKey:"password",PasswordLength:32,ExcludePunctuation:!0}}},I.DbCluster={Type:"AWS::RDS::DBCluster",Properties:{Engine:"aurora-mysql",EngineMode:"provisioned",DBClusterIdentifier:`${c}-${s}-db`,DatabaseName:"app",MasterUsername:e.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:username}}"),MasterUserPassword:e.sub("{{resolve:secretsmanager:${DbSecret}:SecretString:password}}"),ServerlessV2ScalingConfiguration:{MinCapacity:i.database?.minCapacity??0.5,MaxCapacity:i.database?.maxCapacity??4},DBSubnetGroupName:e.ref("DbSubnetGroup"),VpcSecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")]}},I.DbInstance={Type:"AWS::RDS::DBInstance",Properties:{Engine:"aurora-mysql",DBInstanceClass:"db.serverless",DBClusterIdentifier:e.ref("DbCluster")}},_.DbEndpoint={Description:"Aurora cluster endpoint",Value:e.getAtt("DbCluster","Endpoint.Address")};if(i.rdsProxy&&i.database?.connection==="aurora-serverless")I.DbProxyRole={Type:"AWS::IAM::Role",Properties:{AssumeRolePolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Principal:{Service:"rds.amazonaws.com"},Action:"sts:AssumeRole"}]},Policies:[{PolicyName:"read-db-secret",PolicyDocument:{Version:"2012-10-17",Statement:[{Effect:"Allow",Action:["secretsmanager:GetSecretValue"],Resource:e.ref("DbSecret")}]}}]}},I.DbProxy={Type:"AWS::RDS::DBProxy",Properties:{DBProxyName:typeof i.rdsProxy==="object"&&i.rdsProxy.name?i.rdsProxy.name:`${c}-${s}-proxy`,EngineFamily:"MYSQL",RoleArn:e.getAtt("DbProxyRole","Arn"),Auth:[{AuthScheme:"SECRETS",SecretArn:e.ref("DbSecret"),IAMAuth:"DISABLED"}],VpcSubnetIds:oe,VpcSecurityGroupIds:[e.getAtt("DataSecurityGroup","GroupId")],RequireTLS:!1}},I.DbProxyTargetGroup={Type:"AWS::RDS::DBProxyTargetGroup",DependsOn:["DbInstance"],Properties:{DBProxyName:e.ref("DbProxy"),TargetGroupName:"default",DBClusterIdentifiers:[e.ref("DbCluster")]}},_.DbProxyEndpoint={Description:"RDS Proxy endpoint",Value:e.getAtt("DbProxy","Endpoint")};if(_.HttpFunctionName={Description:"HTTP function name",Value:e.ref("HttpFunction")},_.CliFunctionName={Description:"CLI function name",Value:e.ref("CliFunction")},b)_.QueueFunctionName={Description:"Queue function name",Value:e.ref("QueueFunction")};let Me={AWSTemplateFormatVersion:"2010-09-09",Description:`Serverless application for ${n.config.project.name} (${c}-${s})`,Parameters:w?{ImageUri:{Type:"String",Description:"ECR image URI of the deployment artifact"}}:{ArtifactBucket:{Type:"String",Description:"S3 bucket holding the deployment artifact"},ArtifactKey:{Type:"String",Description:"S3 key of the deployment artifact (zip)"}},Resources:I,Outputs:_},Ue={};for(let z of Object.values(I))Ue[z.Type]=(Ue[z.Type]??0)+1;return{template:Me,functionNames:y,queueNames:S,resourceSummary:Ue}}var XA=["cli","fpm","curl","mbstring","xml","pdo","mysqlnd","gd","bcmath","intl","opcache","sodium","process","pecl-redis6","pecl-apcu","pgsql"];function YA(n){let i=`php${n.replace(".","")}`;return XA.map((s)=>`${i}-php-${s}`)}function _m(n,i){let s=`php${n.replace(".","")}`,o=YA(n).join(" \\\n "),c=`/opt/remi/${s}/root`,l=`/etc/opt/remi/${s}`;return`${i?`FROM almalinux:9 AS ${i}`:"FROM almalinux:9"}
7277
7277
 
7278
7278
  # Build PHP on AlmaLinux 9 (where Remi's version-isolated SCL packages install
7279
7279
  # cleanly — Remi's release RPM rejects Amazon Linux 2023). AlmaLinux 9 shares
@@ -7334,7 +7334,7 @@ COPY app/ \${LAMBDA_TASK_ROOT}/
7334
7334
 
7335
7335
  # Per-function CMD (e.g. index.http) is supplied via ImageConfig.Command.
7336
7336
  CMD [ "index.http" ]
7337
- `}function ja(){return pi(gi(import.meta.url))}function xm(){return wt(we(ja(),"runtime.mjs"),"utf-8")}function Ka(n){return wt(we(ja(),`${n}-bootstrap`),"utf-8")}function UE(n){let i=n.architecture??"x86_64",s=i==="arm64"?"arm64":"x64",o=n.version.replace(/^v/,""),c=n.onStep??(()=>{}),l=Fa(we(Va(),"tscloud-node-layer-"));try{let u=o.includes(".")?o:hi(o),h=`node-v${u}-linux-${s}`,y=`https://nodejs.org/dist/v${u}/${h}.tar.xz`;c(`downloading Node ${u} (${i})`);let f=we(l,"node.tar.xz");qa(y,f),c("extracting node binary"),Tt("tar",["-xf",f,"-C",l,`${h}/bin/node`],{stdio:"inherit"});let b=wt(we(l,h,"bin","node"));c("packaging layer");let C=[{name:"bootstrap",data:Ka("node"),mode:493},{name:"runtime.mjs",data:xm(),mode:420},{name:"bin/node",data:b,mode:493}];return{zip:Bi(C),architecture:i,version:u,fileCount:C.length}}finally{Ua(l,{recursive:!0,force:!0})}}function QE(n){let i=n.architecture??"x86_64",s=i==="arm64"?"bun-linux-aarch64":"bun-linux-x64",o=n.version==="latest"?"":n.version.replace(/^v/,""),c=n.onStep??(()=>{}),l=Fa(we(Va(),"tscloud-bun-layer-"));try{let u=o?`https://github.com/oven-sh/bun/releases/download/bun-v${o}/${s}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${s}.zip`;c(`downloading Bun ${o||"latest"} (${i})`);let h=we(l,"bun.zip");qa(u,h),c("extracting bun binary"),Tt("unzip",["-o","-q",h,"-d",l],{stdio:"inherit"});let y=wt(we(l,s,"bun"));c("packaging layer");let f=[{name:"bootstrap",data:Ka("bun"),mode:493},{name:"runtime.mjs",data:xm(),mode:420},{name:"bin/bun",data:y,mode:493}];return{zip:Bi(f),architecture:i,version:o||"latest",fileCount:f.length}}finally{Ua(l,{recursive:!0,force:!0})}}function qa(n,i){Tt("curl",["-fsSL","-o",i,n],{stdio:["ignore","ignore","inherit"]})}function hi(n){let i=Tt("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),s=JSON.parse(i).find((o)=>o.version.startsWith(`v${n}.`));if(!s)throw Error(`No Node release found for major version ${n}`);return s.version.replace(/^v/,"")}var Co="x-ts-cloud-invoke-depth",Eo="x-ts-cloud-invoke-chain",bo="x-ts-cloud-trace-id";function qd(n){return fi("sha256").update(n).digest("hex").slice(0,8)}var _i={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function Mt(n,i){if(typeof n.get==="function")return n.get(i)??void 0;let s=n;return s[i]??s[i.toLowerCase()]??s[i.toUpperCase()]}function Vd(n,i=64){if(!n)return[];return n.split(".").map((s)=>s.trim()).filter((s)=>/^[0-9a-f]{8}$/.test(s)).slice(-i)}function jd(n,i=_i){let s=qd(n.functionId),o=Vd(Mt(n.headers,Eo)),c=n.traceId??Mt(n.headers,bo)??crypto.randomUUID(),l=[...o,s],u=o.filter((C)=>C===s).length,h=o[o.length-1]===s,y=Number.parseInt(Mt(n.headers,Co)??"",10),f=Math.max(l.length,Number.isFinite(y)?y+1:0),b="ok";if(f>i.maxDepth)b="depth_exceeded";else if(u>=i.maxRepeats)b="cycle_detected";else if(h&&i.maxRepeats<=1)b="self_invocation";return{reason:b,depth:f,chain:l,traceId:c,selfInvocation:h,repeats:u,propagate:{[Co]:String(f),[Eo]:l.join("."),[bo]:c}}}var Ha={ok:"",depth_exceeded:"Invocation chain is deeper than the configured limit; the call was refused to stop a runaway loop.",cycle_detected:"This function already appears in the invocation chain; the call was refused as a recursion loop.",self_invocation:"This function invoked itself directly; the call was refused.",trace_budget_exceeded:"This request has already made more invocations than its budget allows.",breaker_open:"Recursion protection is open for this function after repeated loop detections."};class vo{limits;clock;traces=new Map;breakers=new Map;constructor(n=_i,i=()=>Date.now()){this.limits=n,this.clock=i}check(n){let i=this.clock();this.expireTraces(i);let s=jd(n,this.limits),o=this.breakers.get(n.functionId);if(o?.openUntil!=null&&o.openUntil>i)return this.deny(n.functionId,s,"breaker_open",i,!1);if(s.reason!=="ok")return this.deny(n.functionId,s,s.reason,i,!0);let c=this.traces.get(s.traceId)??{count:0,firstAt:i};if(c.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(s.traceId,c),this.deny(n.functionId,s,"trace_budget_exceeded",i,!0);if(this.traces.set(s.traceId,{count:c.count+1,firstAt:c.firstAt}),o)this.breakers.set(n.functionId,{consecutiveBlocks:0});return{...s,allowed:!0,reason:"ok",propagate:s.propagate}}deny(n,i,s,o,c){if(c){let l=this.breakers.get(n)??{consecutiveBlocks:0},u=l.consecutiveBlocks+1;this.breakers.set(n,{consecutiveBlocks:u,openUntil:u>=this.limits.breakerThreshold?o+this.limits.breakerCooldownMs:l.openUntil})}return{...i,allowed:!1,reason:s,message:Ha[s]}}breakerOpen(n){let i=this.breakers.get(n);return i?.openUntil!=null&&i.openUntil>this.clock()}reset(n){if(n){this.breakers.delete(n);return}this.breakers.clear(),this.traces.clear()}expireTraces(n){if(this.traces.size===0)return;for(let[i,s]of this.traces)if(n-s.firstAt>this.limits.traceWindowMs)this.traces.delete(i)}get trackedTraces(){return this.traces.size}}function zd(n){return{...n.propagate}}function Kd(n){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":n.reason},body:{error:"recursion_blocked",reason:n.reason,message:n.message??Ha[n.reason],depth:n.depth,traceId:n.traceId}}}var Om=new yi;function ba(n){let i=globalThis.process?.env?.[n];if(i==null||i==="")return;return i!=="0"&&i.toLowerCase()!=="false"}function Si(){let n=globalThis.process?.env??{};return n.TS_CLOUD_FUNCTION_ID||n.AWS_LAMBDA_FUNCTION_NAME||n.FUNCTION_NAME||"function"}function ey(n){let i=n===!1?{enabled:!1}:n??{},s=ba("TS_CLOUD_RECURSION_PROTECTION"),o=ba("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:s??i.enabled??!0,detectionOnly:o??i.detectionOnly??!1,limits:{..._i,...i.limits},functionId:i.functionId??Si()}}var $e,be;function ty(){let n=globalThis.fetch;if(!n||$e===n)return()=>{};be=n;let i=async(s,o)=>{let c=Om.getStore();if(!c)return be(s,o);let l=new Headers(o?.headers??(s instanceof Request?s.headers:void 0));for(let[u,h]of Object.entries(zd(c)))l.set(u,h);if(s instanceof Request)return be(new Request(s,{headers:l}),o);return be(s,{...o,headers:l})};return Object.assign(i,n),globalThis.fetch=i,$e=i,()=>{if(globalThis.fetch===$e&&be)globalThis.fetch=be;$e=void 0}}var dt,_t;function ry(n){if(!dt||JSON.stringify(_t)!==JSON.stringify(n))dt=new vo(n),_t=n;return dt}function HE(){if(dt=void 0,_t=void 0,$e&&be&&globalThis.fetch===$e)globalThis.fetch=be;$e=void 0,be=void 0}function ny(n,i){let s=ey(i);if(!s.enabled)return;let o=ry(s.limits),c={functionId:s.functionId,headers:n},l=o.check(c);return{verdict:l,blocked:!l.allowed&&!s.detectionOnly,observed:!l.allowed&&s.detectionOnly}}function iy(n,i){return ty(),Om.run(n,i)}function GE(n){let i=n,s=i?.default??i;if(typeof s==="function")return{fetch:s};return{fetch:s?.fetch??i?.fetch,queue:s?.queue??i?.queue,cli:s?.cli??i?.cli}}var bi=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Ai(n){if(!n)return!0;return bi.test(n)}function Ci(n){if(n?.maintenance)return n.maintenance;let i=globalThis.process?.env??{};return{enabled:i.MAINTENANCE_MODE==="1"||i.MAINTENANCE_MODE==="true",bypassSecret:i.MAINTENANCE_BYPASS_SECRET}}function sy(n){let i=n.requestContext?.domainName??"localhost",s=n.rawQueryString?`?${n.rawQueryString}`:"",o=`https://${i}${n.rawPath||"/"}${s}`,c=new Headers;for(let[h,y]of Object.entries(n.headers??{}))if(y!==void 0)c.set(h,y);if(n.cookies?.length)c.set("cookie",n.cookies.join("; "));let l=n.requestContext.http.method,u;if(n.body!==void 0&&l!=="GET"&&l!=="HEAD")u=n.isBase64Encoded?new Uint8Array(Buffer.from(n.body,"base64")):new TextEncoder().encode(n.body);return new Request(o,{method:l,headers:c,body:u})}async function Lm(n){let i={},s=[],o=typeof n.headers.getSetCookie==="function"?n.headers.getSetCookie():[];for(let u of o)s.push(u);n.headers.forEach((u,h)=>{if(h.toLowerCase()==="set-cookie")return;i[h]=u});let c=Buffer.from(await n.arrayBuffer()),l=Ai(n.headers.get("content-type"));return{statusCode:n.status,headers:i,...s.length?{cookies:s}:{},body:l?c.toString("utf-8"):c.toString("base64"),isBase64Encoded:!l}}function oy(n,i){return async(s)=>{if(s.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!n)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let o=Ci(i);if(o.enabled){let u=s.headers?.["x-maintenance-bypass"]??s.cookies?.find((h)=>h.startsWith("tscloud_bypass="))?.split("=")[1];if(!o.bypassSecret||u!==o.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let c=ny(s.headers??{},i?.recursionProtection);if(c?.blocked){let u=Kd(c.verdict);return{statusCode:u.status,headers:{...u.headers,"retry-after":"60"},body:JSON.stringify(u.body),isBase64Encoded:!1}}let l=sy(s);if(!c){let u=await n(l);return Lm(u)}if(c.observed)console.warn(`[ts-cloud] recursion detected (${c.verdict.reason}) at depth ${c.verdict.depth}; detection-only mode let it run`);return iy(c.verdict,async()=>Lm(await n(l)))}}function vi(n){try{return JSON.parse(n)}catch{return n}}function ay(n){return async(i)=>{let s=[];if(i.warmer)return{batchItemFailures:s};if(!n)return{batchItemFailures:s};for(let o of i.Records??[])try{await n(vi(o.body),o)}catch{s.push({itemIdentifier:o.messageId})}return{batchItemFailures:s}}}function cy(n){return async(i)=>{if(i.warmer)return{statusCode:0,output:"warm"};if(!n)return{statusCode:501,output:"No CLI handler configured"};return n(i)}}function qE(n,i){return{http:oy(n.fetch,i),queue:ay(n.queue),cli:cy(n.cli)}}function dy(n={}){let i=n.socketPath??"/tmp/.tscloud-fpm.sock",s=n.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
7337
+ `}function ja(){return pi(gi(import.meta.url))}function xm(){return wt(we(ja(),"runtime.mjs"),"utf-8")}function Ka(n){return wt(we(ja(),`${n}-bootstrap`),"utf-8")}function UE(n){let i=n.architecture??"x86_64",s=i==="arm64"?"arm64":"x64",o=n.version.replace(/^v/,""),c=n.onStep??(()=>{}),l=Fa(we(Va(),"tscloud-node-layer-"));try{let u=o.includes(".")?o:hi(o),h=`node-v${u}-linux-${s}`,y=`https://nodejs.org/dist/v${u}/${h}.tar.xz`;c(`downloading Node ${u} (${i})`);let f=we(l,"node.tar.xz");qa(y,f),c("extracting node binary"),Tt("tar",["-xf",f,"-C",l,`${h}/bin/node`],{stdio:"inherit"});let S=wt(we(l,h,"bin","node"));c("packaging layer");let b=[{name:"bootstrap",data:Ka("node"),mode:493},{name:"runtime.mjs",data:xm(),mode:420},{name:"bin/node",data:S,mode:493}];return{zip:Bi(b),architecture:i,version:u,fileCount:b.length}}finally{Ua(l,{recursive:!0,force:!0})}}function QE(n){let i=n.architecture??"x86_64",s=i==="arm64"?"bun-linux-aarch64":"bun-linux-x64",o=n.version==="latest"?"":n.version.replace(/^v/,""),c=n.onStep??(()=>{}),l=Fa(we(Va(),"tscloud-bun-layer-"));try{let u=o?`https://github.com/oven-sh/bun/releases/download/bun-v${o}/${s}.zip`:`https://github.com/oven-sh/bun/releases/latest/download/${s}.zip`;c(`downloading Bun ${o||"latest"} (${i})`);let h=we(l,"bun.zip");qa(u,h),c("extracting bun binary"),Tt("unzip",["-o","-q",h,"-d",l],{stdio:"inherit"});let y=wt(we(l,s,"bun"));c("packaging layer");let f=[{name:"bootstrap",data:Ka("bun"),mode:493},{name:"runtime.mjs",data:xm(),mode:420},{name:"bin/bun",data:y,mode:493}];return{zip:Bi(f),architecture:i,version:o||"latest",fileCount:f.length}}finally{Ua(l,{recursive:!0,force:!0})}}function qa(n,i){Tt("curl",["-fsSL","-o",i,n],{stdio:["ignore","ignore","inherit"]})}function hi(n){let i=Tt("curl",["-fsSL","https://nodejs.org/dist/index.json"],{encoding:"utf-8"}),s=JSON.parse(i).find((o)=>o.version.startsWith(`v${n}.`));if(!s)throw Error(`No Node release found for major version ${n}`);return s.version.replace(/^v/,"")}var Co="x-ts-cloud-invoke-depth",Eo="x-ts-cloud-invoke-chain",bo="x-ts-cloud-trace-id";function qd(n){return fi("sha256").update(n).digest("hex").slice(0,8)}var _i={maxDepth:10,maxRepeats:3,maxInvocationsPerTrace:100,traceWindowMs:60000,breakerThreshold:5,breakerCooldownMs:60000};function Mt(n,i){if(typeof n.get==="function")return n.get(i)??void 0;let s=n;return s[i]??s[i.toLowerCase()]??s[i.toUpperCase()]}function Vd(n,i=64){if(!n)return[];return n.split(".").map((s)=>s.trim()).filter((s)=>/^[0-9a-f]{8}$/.test(s)).slice(-i)}function jd(n,i=_i){let s=qd(n.functionId),o=Vd(Mt(n.headers,Eo)),c=n.traceId??Mt(n.headers,bo)??crypto.randomUUID(),l=[...o,s],u=o.filter((b)=>b===s).length,h=o[o.length-1]===s,y=Number.parseInt(Mt(n.headers,Co)??"",10),f=Math.max(l.length,Number.isFinite(y)?y+1:0),S="ok";if(f>i.maxDepth)S="depth_exceeded";else if(u>=i.maxRepeats)S="cycle_detected";else if(h&&i.maxRepeats<=1)S="self_invocation";return{reason:S,depth:f,chain:l,traceId:c,selfInvocation:h,repeats:u,propagate:{[Co]:String(f),[Eo]:l.join("."),[bo]:c}}}var Ha={ok:"",depth_exceeded:"Invocation chain is deeper than the configured limit; the call was refused to stop a runaway loop.",cycle_detected:"This function already appears in the invocation chain; the call was refused as a recursion loop.",self_invocation:"This function invoked itself directly; the call was refused.",trace_budget_exceeded:"This request has already made more invocations than its budget allows.",breaker_open:"Recursion protection is open for this function after repeated loop detections."};class vo{limits;clock;traces=new Map;breakers=new Map;constructor(n=_i,i=()=>Date.now()){this.limits=n,this.clock=i}check(n){let i=this.clock();this.expireTraces(i);let s=jd(n,this.limits),o=this.breakers.get(n.functionId);if(o?.openUntil!=null&&o.openUntil>i)return this.deny(n.functionId,s,"breaker_open",i,!1);if(s.reason!=="ok")return this.deny(n.functionId,s,s.reason,i,!0);let c=this.traces.get(s.traceId)??{count:0,firstAt:i};if(c.count>=this.limits.maxInvocationsPerTrace)return this.traces.set(s.traceId,c),this.deny(n.functionId,s,"trace_budget_exceeded",i,!0);if(this.traces.set(s.traceId,{count:c.count+1,firstAt:c.firstAt}),o)this.breakers.set(n.functionId,{consecutiveBlocks:0});return{...s,allowed:!0,reason:"ok",propagate:s.propagate}}deny(n,i,s,o,c){if(c){let l=this.breakers.get(n)??{consecutiveBlocks:0},u=l.consecutiveBlocks+1;this.breakers.set(n,{consecutiveBlocks:u,openUntil:u>=this.limits.breakerThreshold?o+this.limits.breakerCooldownMs:l.openUntil})}return{...i,allowed:!1,reason:s,message:Ha[s]}}breakerOpen(n){let i=this.breakers.get(n);return i?.openUntil!=null&&i.openUntil>this.clock()}reset(n){if(n){this.breakers.delete(n);return}this.breakers.clear(),this.traces.clear()}expireTraces(n){if(this.traces.size===0)return;for(let[i,s]of this.traces)if(n-s.firstAt>this.limits.traceWindowMs)this.traces.delete(i)}get trackedTraces(){return this.traces.size}}function zd(n){return{...n.propagate}}function Kd(n){return{status:508,headers:{"content-type":"application/json","x-ts-cloud-recursion-blocked":n.reason},body:{error:"recursion_blocked",reason:n.reason,message:n.message??Ha[n.reason],depth:n.depth,traceId:n.traceId}}}var Om=new yi;function ba(n){let i=globalThis.process?.env?.[n];if(i==null||i==="")return;return i!=="0"&&i.toLowerCase()!=="false"}function Si(){let n=globalThis.process?.env??{};return n.TS_CLOUD_FUNCTION_ID||n.AWS_LAMBDA_FUNCTION_NAME||n.FUNCTION_NAME||"function"}function ey(n){let i=n===!1?{enabled:!1}:n??{},s=ba("TS_CLOUD_RECURSION_PROTECTION"),o=ba("TS_CLOUD_RECURSION_DETECTION_ONLY");return{enabled:s??i.enabled??!0,detectionOnly:o??i.detectionOnly??!1,limits:{..._i,...i.limits},functionId:i.functionId??Si()}}var $e,be;function ty(){let n=globalThis.fetch;if(!n||$e===n)return()=>{};be=n;let i=async(s,o)=>{let c=Om.getStore();if(!c)return be(s,o);let l=new Headers(o?.headers??(s instanceof Request?s.headers:void 0));for(let[u,h]of Object.entries(zd(c)))l.set(u,h);if(s instanceof Request)return be(new Request(s,{headers:l}),o);return be(s,{...o,headers:l})};return Object.assign(i,n),globalThis.fetch=i,$e=i,()=>{if(globalThis.fetch===$e&&be)globalThis.fetch=be;$e=void 0}}var dt,_t;function ry(n){if(!dt||JSON.stringify(_t)!==JSON.stringify(n))dt=new vo(n),_t=n;return dt}function HE(){if(dt=void 0,_t=void 0,$e&&be&&globalThis.fetch===$e)globalThis.fetch=be;$e=void 0,be=void 0}function ny(n,i){let s=ey(i);if(!s.enabled)return;let o=ry(s.limits),c={functionId:s.functionId,headers:n},l=o.check(c);return{verdict:l,blocked:!l.allowed&&!s.detectionOnly,observed:!l.allowed&&s.detectionOnly}}function iy(n,i){return ty(),Om.run(n,i)}function GE(n){let i=n,s=i?.default??i;if(typeof s==="function")return{fetch:s};return{fetch:s?.fetch??i?.fetch,queue:s?.queue??i?.queue,cli:s?.cli??i?.cli}}var bi=/^(?:text\/|application\/(?:json|xml|javascript|graphql|x-www-form-urlencoded|.*\+json|.*\+xml)|image\/svg)/i;function Ai(n){if(!n)return!0;return bi.test(n)}function Ci(n){if(n?.maintenance)return n.maintenance;let i=globalThis.process?.env??{};return{enabled:i.MAINTENANCE_MODE==="1"||i.MAINTENANCE_MODE==="true",bypassSecret:i.MAINTENANCE_BYPASS_SECRET}}function sy(n){let i=n.requestContext?.domainName??"localhost",s=n.rawQueryString?`?${n.rawQueryString}`:"",o=`https://${i}${n.rawPath||"/"}${s}`,c=new Headers;for(let[h,y]of Object.entries(n.headers??{}))if(y!==void 0)c.set(h,y);if(n.cookies?.length)c.set("cookie",n.cookies.join("; "));let l=n.requestContext.http.method,u;if(n.body!==void 0&&l!=="GET"&&l!=="HEAD")u=n.isBase64Encoded?new Uint8Array(Buffer.from(n.body,"base64")):new TextEncoder().encode(n.body);return new Request(o,{method:l,headers:c,body:u})}async function Lm(n){let i={},s=[],o=typeof n.headers.getSetCookie==="function"?n.headers.getSetCookie():[];for(let u of o)s.push(u);n.headers.forEach((u,h)=>{if(h.toLowerCase()==="set-cookie")return;i[h]=u});let c=Buffer.from(await n.arrayBuffer()),l=Ai(n.headers.get("content-type"));return{statusCode:n.status,headers:i,...s.length?{cookies:s}:{},body:l?c.toString("utf-8"):c.toString("base64"),isBase64Encoded:!l}}function oy(n,i){return async(s)=>{if(s.warmer)return{statusCode:200,headers:{"content-type":"text/plain"},body:"warm",isBase64Encoded:!1};if(!n)return{statusCode:501,headers:{"content-type":"text/plain"},body:"No HTTP handler configured",isBase64Encoded:!1};let o=Ci(i);if(o.enabled){let u=s.headers?.["x-maintenance-bypass"]??s.cookies?.find((h)=>h.startsWith("tscloud_bypass="))?.split("=")[1];if(!o.bypassSecret||u!==o.bypassSecret)return{statusCode:503,headers:{"content-type":"text/plain","retry-after":"120"},body:"Service temporarily unavailable (maintenance mode)",isBase64Encoded:!1}}let c=ny(s.headers??{},i?.recursionProtection);if(c?.blocked){let u=Kd(c.verdict);return{statusCode:u.status,headers:{...u.headers,"retry-after":"60"},body:JSON.stringify(u.body),isBase64Encoded:!1}}let l=sy(s);if(!c){let u=await n(l);return Lm(u)}if(c.observed)console.warn(`[ts-cloud] recursion detected (${c.verdict.reason}) at depth ${c.verdict.depth}; detection-only mode let it run`);return iy(c.verdict,async()=>Lm(await n(l)))}}function vi(n){try{return JSON.parse(n)}catch{return n}}function ay(n){return async(i)=>{let s=[];if(i.warmer)return{batchItemFailures:s};if(!n)return{batchItemFailures:s};for(let o of i.Records??[])try{await n(vi(o.body),o)}catch{s.push({itemIdentifier:o.messageId})}return{batchItemFailures:s}}}function cy(n){return async(i)=>{if(i.warmer)return{statusCode:0,output:"warm"};if(!n)return{statusCode:501,output:"No CLI handler configured"};return n(i)}}function qE(n,i){return{http:oy(n.fetch,i),queue:ay(n.queue),cli:cy(n.cli)}}function dy(n={}){let i=n.socketPath??"/tmp/.tscloud-fpm.sock",s=n.maxChildren??1;return`; ts-cloud php-fpm configuration (generated) — AWS Lambda custom runtime.
7338
7338
  [global]
7339
7339
  daemonize = no
7340
7340
  error_log = ${n.errorLog??"/tmp/storage/logs/php-fpm.log"}
@@ -7351,5 +7351,5 @@ decorate_workers_output = no
7351
7351
  php_admin_value[error_log] = /dev/stderr
7352
7352
  php_admin_flag[log_errors] = on
7353
7353
  clear_env = no
7354
- `}function Ii(){return za(wi(Ei(import.meta.url)),"runtime-assets")}function xi(){let n=Ii(),i=(s)=>Ti(za(n,s),"utf-8");return[{path:"bootstrap",contents:i("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:i("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:i("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:i("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:i("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:dy(),mode:420}]}function Wd(n={}){let i=n.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:i,CACHE_DRIVER:i,SESSION_DRIVER:i,QUEUE_CONNECTION:"sqs",FILESYSTEM_DISK:"s3",VIEW_COMPILED_PATH:"/tmp/storage/framework/views",APP_SERVICES_CACHE:"/tmp/bootstrap/cache/services.php",APP_PACKAGES_CACHE:"/tmp/bootstrap/cache/packages.php",APP_CONFIG_CACHE:"/tmp/bootstrap/cache/config.php",APP_ROUTES_CACHE:"/tmp/bootstrap/cache/routes.php",APP_EVENTS_CACHE:"/tmp/bootstrap/cache/events.php"}}var ly=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];function*Ja(n){for(let i of Mi(n)){let s=xe(n,i);if(Qa(s).isDirectory())yield*Ja(s);else yield s}}function VE(n={}){let i=n.architecture??"x86_64",s=n.platform??(i==="arm64"?"linux/arm64":"linux/amd64"),o=n.onStep??(()=>{}),c=Li(xe(Fi(),"tscloud-php-layer-")),l="tscloud-php-layer:build";try{Gi(xe(c,"Dockerfile"),ZA(n)),o("Building PHP runtime image (docker)"),ut("docker",["build","--platform",s,"-t","tscloud-php-layer:build",c],{stdio:"inherit"}),o("Extracting /opt/php from image");let u=ut("docker",["create","--platform",s,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),h=xe(c,"opt");$i(h,{recursive:!0});try{ut("docker",["cp",`${u}:/opt/php`,xe(h,"php")],{stdio:"inherit"})}finally{ut("docker",["rm",u],{stdio:"ignore"})}if(!Ri(xe(h,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let y=[];for(let C of Ja(h)){let T=Ui(h,C).replace(/\\/g,"/"),w=Qa(C).mode&73?493:420;y.push({name:T,data:Oi(C),mode:w})}o("Injecting runtime assets");let f=new Set(xi().map((C)=>C.path)),b=y.filter((C)=>!f.has(C.name));for(let C of xi())b.push({name:C.path,data:C.contents,mode:C.mode});return o("Packaging layer ZIP"),{zip:Bi(b),architecture:i,fileCount:b.length}}finally{Wi(c,{recursive:!0,force:!0})}}var uy=[".git",".github","node_modules","tests","storage/logs","storage/framework/cache","storage/framework/sessions","storage/framework/views",".env",".env.local",".vapor",".ts-cloud","dist-lambda"];function zi(n,i){return i.some((s)=>n===s||n.startsWith(`${s}/`))}function*Xa(n,i,s){for(let o of Ki(n)){let c=Hi(n,o),l=Za(i,c).replace(/\\/g,"/");if(zi(l,s))continue;if(Ya(c).isDirectory())yield*Xa(c,i,s);else yield c}}function To(n){if(n.skipBuild)return;let i=ua(n.projectRoot??process.cwd()),s=n.app.build??ly;for(let o of s)n.onStep?.(`build: ${o}`),Vi(o,{stdio:"inherit",cwd:i})}function wo(n,i=[]){let s=ua(n),o=[...uy,lo(),...i],c=[];for(let l of Xa(s,s,o)){let u=Za(s,l).replace(/\\/g,"/"),h=(Ya(l).mode&73)!==0;c.push({name:u,data:qi(l),mode:h?493:420})}return c}function Jd(n){let i=ua(n.projectRoot??process.cwd());To(n),n.onStep?.("packaging application tree");let s=wo(i,n.exclude);if(!s.length)throw Error(`No files to package under ${i}`);let o=Bi(s),c=n.app.handlers?.http??"public/index.php";return{zip:o,sha256:ji("sha256").update(o).digest("hex"),handlers:{http:c,queue:n.app.handlers?.queue??c,cli:n.app.handlers?.cli??c},fileCount:s.length}}class $m{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(n){let i=`asset-opt-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.optimizations.set(i,s),s}createImageOptimization(n){let i=`image-opt-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.imageConfigs.set(i,s),s}createSSGConfig(n){let i=`ssg-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.ssgConfigs.set(i,s),s}createPrerenderConfig(n){let i=`prerender-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.prerenderConfigs.set(i,s),s}listOptimizations(){return Array.from(this.optimizations.values())}listImageConfigs(){return Array.from(this.imageConfigs.values())}clear(){this.optimizations.clear(),this.imageConfigs.clear(),this.ssgConfigs.clear(),this.prerenderConfigs.clear()}}var jE=new $m;class Mm{policies=new Map;versioningConfigs=new Map;replicationRules=new Map;tieringConfigs=new Map;objectLocks=new Map;transferAcceleration=new Map;accessPoints=new Map;glacierConfigs=new Map;inventories=new Map;batchOps=new Map;eventNotifications=new Map;counter=0;createLifecyclePolicy(n,i){let s=`lifecycle-${Date.now()}-${this.counter++}`,o={id:s,transitions:n,expiration:i};return this.policies.set(s,o),o}enableVersioning(n=!1){let i=`versioning-${Date.now()}-${this.counter++}`,s={id:i,enabled:!0,mfaDelete:n};return this.versioningConfigs.set(i,s),s}createReplicationRule(n,i,s){let o=`replication-${Date.now()}-${this.counter++}`,c={id:o,sourceRegion:n,destRegion:i,destBucket:s};return this.replicationRules.set(o,c),c}createIntelligentTiering(n,i){let s=`tiering-${Date.now()}-${this.counter++}`,o={id:s,archiveDays:n,deepArchiveDays:i};return this.tieringConfigs.set(s,o),o}enableObjectLock(n){let i=`object-lock-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,mode:n.mode||"COMPLIANCE",retentionDays:n.retentionDays,retentionYears:n.retentionYears,legalHoldEnabled:n.legalHoldEnabled||!1};return this.objectLocks.set(i,s),s}enableTransferAcceleration(n){let i=`transfer-accel-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n,enabled:!0,endpoint:`${n}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(i,s),s}createAccessPoint(n){let i=`access-point-${Date.now()}-${this.counter++}`,s={id:i,name:n.name,bucketName:n.bucketName,vpcId:n.vpcId,publicAccessBlock:n.publicAccessBlock!==!1,policy:n.policy};return this.accessPoints.set(i,s),s}createGlacierArchive(n){let i=`glacier-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,archiveType:n.archiveType,transitionDays:n.transitionDays,restoreConfig:n.restoreTier?{tier:n.restoreTier,days:n.restoreDays||7}:void 0};return this.glacierConfigs.set(i,s),s}createInventory(n){let i=`inventory-${Date.now()}-${this.counter++}`,s={id:i,sourceBucket:n.sourceBucket,destinationBucket:n.destinationBucket,schedule:n.schedule||"Daily",format:n.format||"CSV",includedFields:n.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:n.prefix};return this.inventories.set(i,s),s}createBatchOperation(n){let i=`batch-op-${Date.now()}-${this.counter++}`,s={id:i,operation:n.operation,manifestBucket:n.manifestBucket,manifestKey:n.manifestKey,priority:n.priority||10,status:"pending"};return this.batchOps.set(i,s),s}executeBatchOperation(n){let i=this.batchOps.get(n);if(!i)throw Error(`Batch operation not found: ${n}`);return i.status="in_progress",i.totalObjects=1000,i.processedObjects=0,i}getBatchOperationStatus(n){return this.batchOps.get(n)}createLambdaNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"Lambda",arn:n.lambdaArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}createSQSNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"SQS",arn:n.queueArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}createSNSNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"SNS",arn:n.topicArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}generateObjectLockCF(n){let i={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:n.mode}}}};if(n.retentionDays)i.ObjectLockConfiguration.Rule.DefaultRetention.Days=n.retentionDays;if(n.retentionYears)i.ObjectLockConfiguration.Rule.DefaultRetention.Years=n.retentionYears;return i}generateTransferAccelerationCF(n){return{AccelerateConfiguration:{AccelerationStatus:n.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(n){return{Type:"AWS::S3::AccessPoint",Properties:{Name:n.name,Bucket:n.bucketName,...n.vpcId&&{VpcConfiguration:{VpcId:n.vpcId}},PublicAccessBlockConfiguration:n.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...n.policy&&{Policy:n.policy}}}}generateInventoryCF(n){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:n.id,Destination:{BucketArn:`arn:aws:s3:::${n.destinationBucket}`,Format:n.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:n.includedFields,ScheduleFrequency:n.schedule,...n.prefix&&{Prefix:n.prefix}}]}}}generateEventNotificationCF(n){let i=n.destination.type==="Lambda"?"LambdaConfigurations":n.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",s=n.destination.type==="Lambda"?"Function":n.destination.type==="SQS"?"Queue":"Topic",o={Event:n.events[0],[s]:n.destination.arn};if(n.filter)o.Filter={S3Key:{Rules:[...n.filter.prefix?[{Name:"prefix",Value:n.filter.prefix}]:[],...n.filter.suffix?[{Name:"suffix",Value:n.filter.suffix}]:[]]}};return{NotificationConfiguration:{[i]:[o]}}}clear(){this.policies.clear(),this.versioningConfigs.clear(),this.replicationRules.clear(),this.tieringConfigs.clear(),this.objectLocks.clear(),this.transferAcceleration.clear(),this.accessPoints.clear(),this.glacierConfigs.clear(),this.inventories.clear(),this.batchOps.clear(),this.eventNotifications.clear()}}var zE=new Mm;class Fm{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(n,i=30,s=10){let o=`health-${Date.now()}-${this.counter++}`,c={id:o,url:n,interval:i,timeout:s,status:"healthy"};return this.checks.set(o,c),c}createSyntheticMonitor(n,i,s,o){let c=`synthetic-${Date.now()}-${this.counter++}`,l={id:c,name:n,script:i,frequency:s,locations:o};return this.synthetics.set(c,l),l}trackUptime(n,i,s){let o=`uptime-${Date.now()}-${this.counter++}`,c=i/(i+s)*100,l={id:o,resource:n,uptime:i,downtime:s,availability:c};return this.uptimeTrackers.set(o,l),l}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var KE=new Fm;class Um{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(n,i,s,o){let c=`waf-${Date.now()}-${this.counter++}`,l={id:c,name:n,priority:i,action:s,conditions:o};return this.wafRules.set(c,l),l}enableShield(n,i="standard"){let s=`shield-${Date.now()}-${this.counter++}`,o={id:s,resourceArn:n,protectionType:i};return this.shieldProtections.set(s,o),o}createSecurityGroup(n,i,s){let o=`sg-${Date.now()}-${this.counter++}`,c={id:o,name:n,vpcId:i,rules:s};return this.securityGroups.set(o,c),c}createNACL(n,i){let s=`nacl-${Date.now()}-${this.counter++}`,o={id:s,vpcId:n,rules:i};return this.nacls.set(s,o),o}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var WE=new Um;class Qm{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(n,i){let s=`tagging-${Date.now()}-${this.counter++}`,o={id:s,tags:n,resources:i};return this.strategies.set(s,o),o}createCostAllocation(n,i){let s=`cost-${Date.now()}-${this.counter++}`,o={id:s,tagKey:n,allocations:i};return this.allocations.set(s,o),o}createResourceGroup(n,i,s){let o=`group-${Date.now()}-${this.counter++}`,c={id:o,name:n,query:{resourceTypeFilters:i,tagFilters:s}};return this.groups.set(o,c),c}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var JE=new Qm;
7355
- export{cg,O,dg,nA,pI,iA,gI,mI,hI,fI,yI,II,SI,CI,EI,bI,lg,ug,Cd,Ed,lo,L,d,bd,pg,M,vd,p,sA,Di,Td,wd,ge,Rd,vI,r,t,TI,wI,g,RI,DI,PI,NI,kI,Gt,Dd,uo,oA,BI,_I,Re,je,Pd,gg,mg,xI,hg,fg,Ag,Nd,yg,De,Gr,qt,kd,Vt,me,aA,Bd,po,Ig,Sg,Cg,Eg,_d,OI,F,S,a,A,ze,m,cA,Ke,U,ft,LI,dA,Q,xd,Pe,jt,go,ee,Od,te,lA,mo,H,G,P,Pi,v,zt,At,q,e,ho,$I,bg,Ld,MI,FI,UI,QI,$d,HI,GI,qI,VI,jI,zI,KI,WI,JI,XI,YI,ZI,uA,pA,gA,mA,hA,fA,AA,Kt,vg,Tg,qr,Ni,eS,wg,tS,rS,Vr,nS,iS,sS,oS,aS,cS,yA,IA,SA,CA,EA,fo,dS,bA,vA,TA,V,lS,We,Ao,Wt,wA,Rg,RA,DA,PA,Dg,re,uS,pS,gS,mS,NA,hS,j,fS,AS,yS,Pg,Ng,IS,kg,Bg,SS,CS,ES,bS,vS,kA,Md,TS,wS,RS,DS,PS,BA,_A,NS,kS,BS,_S,xS,OS,LS,$S,MS,_g,Fd,FS,US,QS,HS,xg,Og,Lg,GS,$g,qS,VS,jS,zS,Mg,KS,WS,JS,XS,YS,ZS,eC,tC,xA,OA,LA,$A,Fg,rC,nC,iC,sC,oC,aC,cC,dC,lC,MA,FA,UA,QA,uC,pC,Ug,gC,Qg,Hg,Gg,qg,mC,hC,fC,AC,Ne,ki,yC,IC,SC,CC,EC,bC,vC,TC,HA,wC,RC,Vg,jg,DC,PC,GA,NC,kC,BC,_C,xC,OC,LC,$C,MC,FC,UC,QC,HC,GC,qC,VC,jC,zC,KC,WC,JC,zg,XC,Kg,YC,Wg,ZC,Jg,eE,Xg,tE,jr,rE,Yg,nE,yo,iE,Zg,sE,em,oE,tm,aE,rm,cE,nm,dE,zr,lE,im,uE,sm,pE,om,gE,am,mE,cm,hE,dm,fE,lm,AE,um,yE,pm,IE,gm,SE,mm,CE,hm,EE,fm,bE,Am,vE,ym,TE,Im,wE,Sm,RE,Cm,DE,Em,PE,bm,NE,vm,kE,Tm,BE,wm,_E,Rm,xE,Dm,OE,qA,VA,jA,zA,Pm,LE,Nm,$E,km,ME,Bm,FE,Bi,KA,WA,Io,Ud,Kr,JA,So,Jt,Qd,Hd,XA,YA,_m,ZA,Gd,xm,UE,QE,Co,Eo,bo,qd,_i,Vd,jd,vo,zd,Kd,Om,ey,ty,ry,HE,ny,iy,GE,sy,Lm,oy,ay,cy,qE,dy,xi,Wd,ly,VE,uy,To,wo,Jd,$m,jE,Mm,zE,Fm,KE,Um,WE,Qm,JE};
7354
+ `}function Ii(){return za(wi(Ei(import.meta.url)),"runtime-assets")}function xi(){let n=Ii(),i=(s)=>Ti(za(n,s),"utf-8");return[{path:"bootstrap",contents:i("bootstrap"),mode:493},{path:"tscloud/runtime.php",contents:i("runtime.php"),mode:420},{path:"tscloud/octane-runtime.php",contents:i("octane-runtime.php"),mode:420},{path:"tscloud/cli-runtime.php",contents:i("cli-runtime.php"),mode:420},{path:"tscloud/fastcgi-client.php",contents:i("fastcgi-client.php"),mode:420},{path:"tscloud/php-fpm.conf",contents:dy(),mode:420}]}function Wd(n={}){let i=n.cacheDriver??"dynamodb";return{APP_ENV:"production",LOG_CHANNEL:"stderr",CACHE_STORE:i,CACHE_DRIVER:i,SESSION_DRIVER:i,QUEUE_CONNECTION:"sqs",FILESYSTEM_DISK:"s3",VIEW_COMPILED_PATH:"/tmp/storage/framework/views",APP_SERVICES_CACHE:"/tmp/bootstrap/cache/services.php",APP_PACKAGES_CACHE:"/tmp/bootstrap/cache/packages.php",APP_CONFIG_CACHE:"/tmp/bootstrap/cache/config.php",APP_ROUTES_CACHE:"/tmp/bootstrap/cache/routes.php",APP_EVENTS_CACHE:"/tmp/bootstrap/cache/events.php"}}var ly=["composer install --no-dev --optimize-autoloader --no-interaction","php artisan config:cache","php artisan route:cache","php artisan event:cache","php artisan view:cache"];function*Ja(n){for(let i of Mi(n)){let s=xe(n,i);if(Qa(s).isDirectory())yield*Ja(s);else yield s}}function VE(n={}){let i=n.architecture??"x86_64",s=n.platform??(i==="arm64"?"linux/arm64":"linux/amd64"),o=n.onStep??(()=>{}),c=Li(xe(Fi(),"tscloud-php-layer-")),l="tscloud-php-layer:build";try{Gi(xe(c,"Dockerfile"),ZA(n)),o("Building PHP runtime image (docker)"),ut("docker",["build","--platform",s,"-t","tscloud-php-layer:build",c],{stdio:"inherit"}),o("Extracting /opt/php from image");let u=ut("docker",["create","--platform",s,"tscloud-php-layer:build"],{encoding:"utf-8"}).trim(),h=xe(c,"opt");$i(h,{recursive:!0});try{ut("docker",["cp",`${u}:/opt/php`,xe(h,"php")],{stdio:"inherit"})}finally{ut("docker",["rm",u],{stdio:"ignore"})}if(!Ri(xe(h,"php","bin","php")))throw Error("layer build produced no /opt/php/bin/php");let y=[];for(let b of Ja(h)){let v=Ui(h,b).replace(/\\/g,"/"),w=Qa(b).mode&73?493:420;y.push({name:v,data:Oi(b),mode:w})}o("Injecting runtime assets");let f=new Set(xi().map((b)=>b.path)),S=y.filter((b)=>!f.has(b.name));for(let b of xi())S.push({name:b.path,data:b.contents,mode:b.mode});return o("Packaging layer ZIP"),{zip:Bi(S),architecture:i,fileCount:S.length}}finally{Wi(c,{recursive:!0,force:!0})}}var uy=[".git",".github","node_modules","tests","storage/logs","storage/framework/cache","storage/framework/sessions","storage/framework/views",".env",".env.local",".vapor",".ts-cloud","dist-lambda"];function zi(n,i){return i.some((s)=>n===s||n.startsWith(`${s}/`))}function*Xa(n,i,s){for(let o of Ki(n)){let c=Hi(n,o),l=Za(i,c).replace(/\\/g,"/");if(zi(l,s))continue;if(Ya(c).isDirectory())yield*Xa(c,i,s);else yield c}}function To(n){if(n.skipBuild)return;let i=ua(n.projectRoot??process.cwd()),s=n.app.build??ly;for(let o of s)n.onStep?.(`build: ${o}`),Vi(o,{stdio:"inherit",cwd:i})}function wo(n,i=[]){let s=ua(n),o=[...uy,lo(),...i],c=[];for(let l of Xa(s,s,o)){let u=Za(s,l).replace(/\\/g,"/"),h=(Ya(l).mode&73)!==0;c.push({name:u,data:qi(l),mode:h?493:420})}return c}function Jd(n){let i=ua(n.projectRoot??process.cwd());To(n),n.onStep?.("packaging application tree");let s=wo(i,n.exclude);if(!s.length)throw Error(`No files to package under ${i}`);let o=Bi(s),c=n.app.handlers?.http??"public/index.php";return{zip:o,sha256:ji("sha256").update(o).digest("hex"),handlers:{http:c,queue:n.app.handlers?.queue??c,cli:n.app.handlers?.cli??c},fileCount:s.length}}class $m{optimizations=new Map;imageConfigs=new Map;ssgConfigs=new Map;prerenderConfigs=new Map;counter=0;createAssetOptimization(n){let i=`asset-opt-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.optimizations.set(i,s),s}createImageOptimization(n){let i=`image-opt-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.imageConfigs.set(i,s),s}createSSGConfig(n){let i=`ssg-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.ssgConfigs.set(i,s),s}createPrerenderConfig(n){let i=`prerender-${Date.now()}-${this.counter++}`,s={id:i,...n};return this.prerenderConfigs.set(i,s),s}listOptimizations(){return Array.from(this.optimizations.values())}listImageConfigs(){return Array.from(this.imageConfigs.values())}clear(){this.optimizations.clear(),this.imageConfigs.clear(),this.ssgConfigs.clear(),this.prerenderConfigs.clear()}}var jE=new $m;class Mm{policies=new Map;versioningConfigs=new Map;replicationRules=new Map;tieringConfigs=new Map;objectLocks=new Map;transferAcceleration=new Map;accessPoints=new Map;glacierConfigs=new Map;inventories=new Map;batchOps=new Map;eventNotifications=new Map;counter=0;createLifecyclePolicy(n,i){let s=`lifecycle-${Date.now()}-${this.counter++}`,o={id:s,transitions:n,expiration:i};return this.policies.set(s,o),o}enableVersioning(n=!1){let i=`versioning-${Date.now()}-${this.counter++}`,s={id:i,enabled:!0,mfaDelete:n};return this.versioningConfigs.set(i,s),s}createReplicationRule(n,i,s){let o=`replication-${Date.now()}-${this.counter++}`,c={id:o,sourceRegion:n,destRegion:i,destBucket:s};return this.replicationRules.set(o,c),c}createIntelligentTiering(n,i){let s=`tiering-${Date.now()}-${this.counter++}`,o={id:s,archiveDays:n,deepArchiveDays:i};return this.tieringConfigs.set(s,o),o}enableObjectLock(n){let i=`object-lock-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,mode:n.mode||"COMPLIANCE",retentionDays:n.retentionDays,retentionYears:n.retentionYears,legalHoldEnabled:n.legalHoldEnabled||!1};return this.objectLocks.set(i,s),s}enableTransferAcceleration(n){let i=`transfer-accel-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n,enabled:!0,endpoint:`${n}.s3-accelerate.amazonaws.com`};return this.transferAcceleration.set(i,s),s}createAccessPoint(n){let i=`access-point-${Date.now()}-${this.counter++}`,s={id:i,name:n.name,bucketName:n.bucketName,vpcId:n.vpcId,publicAccessBlock:n.publicAccessBlock!==!1,policy:n.policy};return this.accessPoints.set(i,s),s}createGlacierArchive(n){let i=`glacier-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,archiveType:n.archiveType,transitionDays:n.transitionDays,restoreConfig:n.restoreTier?{tier:n.restoreTier,days:n.restoreDays||7}:void 0};return this.glacierConfigs.set(i,s),s}createInventory(n){let i=`inventory-${Date.now()}-${this.counter++}`,s={id:i,sourceBucket:n.sourceBucket,destinationBucket:n.destinationBucket,schedule:n.schedule||"Daily",format:n.format||"CSV",includedFields:n.includedFields||["Size","LastModifiedDate","StorageClass","ETag"],prefix:n.prefix};return this.inventories.set(i,s),s}createBatchOperation(n){let i=`batch-op-${Date.now()}-${this.counter++}`,s={id:i,operation:n.operation,manifestBucket:n.manifestBucket,manifestKey:n.manifestKey,priority:n.priority||10,status:"pending"};return this.batchOps.set(i,s),s}executeBatchOperation(n){let i=this.batchOps.get(n);if(!i)throw Error(`Batch operation not found: ${n}`);return i.status="in_progress",i.totalObjects=1000,i.processedObjects=0,i}getBatchOperationStatus(n){return this.batchOps.get(n)}createLambdaNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"Lambda",arn:n.lambdaArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}createSQSNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"SQS",arn:n.queueArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}createSNSNotification(n){let i=`event-${Date.now()}-${this.counter++}`,s={id:i,bucketName:n.bucketName,events:n.events,destination:{type:"SNS",arn:n.topicArn},filter:n.prefix||n.suffix?{prefix:n.prefix,suffix:n.suffix}:void 0};return this.eventNotifications.set(i,s),s}generateObjectLockCF(n){let i={ObjectLockEnabled:"Enabled",ObjectLockConfiguration:{ObjectLockEnabled:"Enabled",Rule:{DefaultRetention:{Mode:n.mode}}}};if(n.retentionDays)i.ObjectLockConfiguration.Rule.DefaultRetention.Days=n.retentionDays;if(n.retentionYears)i.ObjectLockConfiguration.Rule.DefaultRetention.Years=n.retentionYears;return i}generateTransferAccelerationCF(n){return{AccelerateConfiguration:{AccelerationStatus:n.enabled?"Enabled":"Suspended"}}}generateAccessPointCF(n){return{Type:"AWS::S3::AccessPoint",Properties:{Name:n.name,Bucket:n.bucketName,...n.vpcId&&{VpcConfiguration:{VpcId:n.vpcId}},PublicAccessBlockConfiguration:n.publicAccessBlock?{BlockPublicAcls:!0,BlockPublicPolicy:!0,IgnorePublicAcls:!0,RestrictPublicBuckets:!0}:void 0,...n.policy&&{Policy:n.policy}}}}generateInventoryCF(n){return{Type:"AWS::S3::Bucket",Properties:{InventoryConfigurations:[{Id:n.id,Destination:{BucketArn:`arn:aws:s3:::${n.destinationBucket}`,Format:n.format},Enabled:!0,IncludedObjectVersions:"Current",OptionalFields:n.includedFields,ScheduleFrequency:n.schedule,...n.prefix&&{Prefix:n.prefix}}]}}}generateEventNotificationCF(n){let i=n.destination.type==="Lambda"?"LambdaConfigurations":n.destination.type==="SQS"?"QueueConfigurations":"TopicConfigurations",s=n.destination.type==="Lambda"?"Function":n.destination.type==="SQS"?"Queue":"Topic",o={Event:n.events[0],[s]:n.destination.arn};if(n.filter)o.Filter={S3Key:{Rules:[...n.filter.prefix?[{Name:"prefix",Value:n.filter.prefix}]:[],...n.filter.suffix?[{Name:"suffix",Value:n.filter.suffix}]:[]]}};return{NotificationConfiguration:{[i]:[o]}}}clear(){this.policies.clear(),this.versioningConfigs.clear(),this.replicationRules.clear(),this.tieringConfigs.clear(),this.objectLocks.clear(),this.transferAcceleration.clear(),this.accessPoints.clear(),this.glacierConfigs.clear(),this.inventories.clear(),this.batchOps.clear(),this.eventNotifications.clear()}}var zE=new Mm;class Fm{checks=new Map;synthetics=new Map;uptimeTrackers=new Map;counter=0;createHealthCheck(n,i=30,s=10){let o=`health-${Date.now()}-${this.counter++}`,c={id:o,url:n,interval:i,timeout:s,status:"healthy"};return this.checks.set(o,c),c}createSyntheticMonitor(n,i,s,o){let c=`synthetic-${Date.now()}-${this.counter++}`,l={id:c,name:n,script:i,frequency:s,locations:o};return this.synthetics.set(c,l),l}trackUptime(n,i,s){let o=`uptime-${Date.now()}-${this.counter++}`,c=i/(i+s)*100,l={id:o,resource:n,uptime:i,downtime:s,availability:c};return this.uptimeTrackers.set(o,l),l}clear(){this.checks.clear(),this.synthetics.clear(),this.uptimeTrackers.clear()}}var KE=new Fm;class Um{wafRules=new Map;shieldProtections=new Map;securityGroups=new Map;nacls=new Map;counter=0;createWAFRule(n,i,s,o){let c=`waf-${Date.now()}-${this.counter++}`,l={id:c,name:n,priority:i,action:s,conditions:o};return this.wafRules.set(c,l),l}enableShield(n,i="standard"){let s=`shield-${Date.now()}-${this.counter++}`,o={id:s,resourceArn:n,protectionType:i};return this.shieldProtections.set(s,o),o}createSecurityGroup(n,i,s){let o=`sg-${Date.now()}-${this.counter++}`,c={id:o,name:n,vpcId:i,rules:s};return this.securityGroups.set(o,c),c}createNACL(n,i){let s=`nacl-${Date.now()}-${this.counter++}`,o={id:s,vpcId:n,rules:i};return this.nacls.set(s,o),o}clear(){this.wafRules.clear(),this.shieldProtections.clear(),this.securityGroups.clear(),this.nacls.clear()}}var WE=new Um;class Qm{strategies=new Map;allocations=new Map;groups=new Map;counter=0;createTaggingStrategy(n,i){let s=`tagging-${Date.now()}-${this.counter++}`,o={id:s,tags:n,resources:i};return this.strategies.set(s,o),o}createCostAllocation(n,i){let s=`cost-${Date.now()}-${this.counter++}`,o={id:s,tagKey:n,allocations:i};return this.allocations.set(s,o),o}createResourceGroup(n,i,s){let o=`group-${Date.now()}-${this.counter++}`,c={id:o,name:n,query:{resourceTypeFilters:i,tagFilters:s}};return this.groups.set(o,c),c}clear(){this.strategies.clear(),this.allocations.clear(),this.groups.clear()}}var JE=new Qm;
7355
+ export{cg,O,dg,nA,pI,iA,gI,mI,hI,fI,yI,II,SI,CI,EI,bI,lg,ug,Cd,Ed,lo,L,d,bd,pg,M,vd,p,sA,Di,Td,wd,ge,Rd,vI,r,t,TI,wI,g,RI,DI,PI,NI,kI,Gt,Dd,uo,oA,BI,_I,Re,je,Pd,gg,mg,xI,hg,fg,Ag,Nd,yg,De,Gr,qt,kd,Vt,me,aA,Bd,po,Ig,Sg,Cg,Eg,_d,OI,F,C,a,A,ze,m,cA,Ke,U,ft,LI,dA,Q,xd,Pe,jt,go,ee,Od,te,lA,mo,H,G,N,Pi,T,zt,At,q,e,ho,$I,bg,Ld,MI,FI,UI,QI,$d,HI,GI,qI,VI,jI,zI,KI,WI,JI,XI,YI,ZI,uA,pA,gA,mA,hA,fA,AA,Kt,vg,Tg,qr,Ni,eS,wg,tS,rS,Vr,nS,iS,sS,oS,aS,cS,yA,IA,SA,CA,EA,fo,dS,bA,vA,TA,V,lS,We,Ao,Wt,wA,Rg,RA,DA,PA,Dg,re,uS,pS,gS,mS,NA,hS,j,fS,AS,yS,Pg,Ng,IS,kg,Bg,SS,CS,ES,bS,vS,kA,Md,TS,wS,RS,DS,PS,BA,_A,NS,kS,BS,_S,xS,OS,LS,$S,MS,_g,Fd,FS,US,QS,HS,xg,Og,Lg,GS,$g,qS,VS,jS,zS,Mg,KS,WS,JS,XS,YS,ZS,eC,tC,xA,OA,LA,$A,Fg,rC,nC,iC,sC,oC,aC,cC,dC,lC,MA,FA,UA,QA,uC,pC,Ug,gC,Qg,Hg,Gg,qg,mC,hC,fC,AC,Ne,ki,yC,IC,SC,CC,EC,bC,vC,TC,HA,wC,RC,Vg,jg,DC,PC,GA,NC,kC,BC,_C,xC,OC,LC,$C,MC,FC,UC,QC,HC,GC,qC,VC,jC,zC,KC,WC,JC,zg,XC,Kg,YC,Wg,ZC,Jg,eE,Xg,tE,jr,rE,Yg,nE,yo,iE,Zg,sE,em,oE,tm,aE,rm,cE,nm,dE,zr,lE,im,uE,sm,pE,om,gE,am,mE,cm,hE,dm,fE,lm,AE,um,yE,pm,IE,gm,SE,mm,CE,hm,EE,fm,bE,Am,vE,ym,TE,Im,wE,Sm,RE,Cm,DE,Em,PE,bm,NE,vm,kE,Tm,BE,wm,_E,Rm,xE,Dm,OE,qA,VA,jA,zA,Pm,LE,Nm,$E,km,ME,Bm,FE,Bi,KA,WA,Io,Ud,Kr,JA,So,Jt,Qd,Hd,XA,YA,_m,ZA,Gd,xm,UE,QE,Co,Eo,bo,qd,_i,Vd,jd,vo,zd,Kd,Om,ey,ty,ry,HE,ny,iy,GE,sy,Lm,oy,ay,cy,qE,dy,xi,Wd,ly,VE,uy,To,wo,Jd,$m,jE,Mm,zE,Fm,KE,Um,WE,Qm,JE};